From 359cc693e07e4945820bf2930125d39301f2057e Mon Sep 17 00:00:00 2001 From: Cooper Miller Date: Sat, 4 Oct 2025 12:59:30 -0700 Subject: [PATCH] feat: http transport + browserbase mcp example --- environments/mcp_env/mcp_env.py | 11 ++++ .../mcp_env/src/mcp_server_connection.py | 59 ++++++++++++++----- environments/mcp_env/src/models.py | 13 ++-- 3 files changed, 64 insertions(+), 19 deletions(-) diff --git a/environments/mcp_env/mcp_env.py b/environments/mcp_env/mcp_env.py index a7d3f624..2ba20203 100644 --- a/environments/mcp_env/mcp_env.py +++ b/environments/mcp_env/mcp_env.py @@ -19,6 +19,7 @@ EXA_FETCH_TOOLS = [ { "name": "exa", + "transport": "stdio", "command": "npx", "args": [ "-y", @@ -31,12 +32,22 @@ }, { "name": "fetch", + "transport": "stdio", "command": "uvx", "args": ["mcp-server-fetch"], "description": "Fetch MCP server", }, ] +BROWSERBASE_TOOLS = [ + { + "name": "browserbase", + "transport": "http", + "url": os.getenv("BROWSERBASE_URL"), + "description": "Browserbase MCP", + }, +] + class MCPEnv(ToolEnv): """Environment for MCP-based tools using the official MCP SDK.""" diff --git a/environments/mcp_env/src/mcp_server_connection.py b/environments/mcp_env/src/mcp_server_connection.py index 67594765..899ce938 100644 --- a/environments/mcp_env/src/mcp_server_connection.py +++ b/environments/mcp_env/src/mcp_server_connection.py @@ -4,6 +4,7 @@ from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client +from mcp.client.streamable_http import streamablehttp_client from mcp.types import TextContent, Tool from .models import MCPServerConfig @@ -35,27 +36,55 @@ async def connect(self): async def _get_connection(self): try: - server_params = StdioServerParameters( - command=self.config.command, - args=self.config.args or [], - env=self.config.env, - ) + if self.config.transport == "stdio": + if not self.config.command: + raise ValueError("stdio transport requires 'command'") + server_params = StdioServerParameters( + command=self.config.command, + args=self.config.args or [], + env=self.config.env, + ) - async with stdio_client(server_params) as (read, write): - async with ClientSession(read, write) as session: - self.session = session + async with stdio_client(server_params) as (read, write): + async with ClientSession(read, write) as session: + self.session = session - await session.initialize() + await session.initialize() - tools_response = await session.list_tools() + tools_response = await session.list_tools() - for tool in tools_response.tools: - self.tools[tool.name] = tool + for tool in tools_response.tools: + self.tools[tool.name] = tool - self._ready.set() + self._ready.set() - while True: - await asyncio.sleep(1) + while True: + await asyncio.sleep(1) + + elif self.config.transport == "http": + if not self.config.url: + raise ValueError("http transport requires 'url'") + + async with streamablehttp_client( + self.config.url, + headers=self.config.headers or {}, + ) as (read, write, _get_session_id): + async with ClientSession(read, write) as session: + self.session = session + + await session.initialize() + + tools_response = await session.list_tools() + + for tool in tools_response.tools: + self.tools[tool.name] = tool + + self._ready.set() + + while True: + await asyncio.sleep(1) + else: + raise ValueError(f"Unknown transport: {self.config.transport}") except asyncio.CancelledError: raise diff --git a/environments/mcp_env/src/models.py b/environments/mcp_env/src/models.py index 7a20dd38..1b5ffc7c 100644 --- a/environments/mcp_env/src/models.py +++ b/environments/mcp_env/src/models.py @@ -1,11 +1,16 @@ from dataclasses import dataclass -from typing import Dict, List +from typing import Dict, List, Literal, Optional @dataclass class MCPServerConfig: name: str - command: str - args: List[str] | None = None - env: Dict[str, str] | None = None + transport: Literal["stdio", "http"] = "stdio" description: str = "" + # stdio params + command: Optional[str] = None + args: Optional[List[str]] = None + env: Optional[Dict[str, str]] = None + # http params + url: Optional[str] = None + headers: Optional[Dict[str, str]] = None