fix: env parameters exception when configuring SSE or HTTP MCP server (#513)

* fix: _create_streamable_http_session() got an unexpected keyword argument 'env'

fix unit error

* update md

---------

Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
This commit is contained in:
Anoyer-lzh
2025-08-20 17:23:57 +08:00
committed by GitHub
parent b08e9ad3ac
commit 270d8c3712
8 changed files with 54 additions and 16 deletions

View File

@@ -46,7 +46,18 @@ For `sse` type:
{ {
"transport": "sse", "transport": "sse",
"url": "http://localhost:3000/sse", "url": "http://localhost:3000/sse",
"env": { "headers": {
"API_KEY": "value"
}
}
```
For `streamable_http` type:
```json
{
"transport": "streamable_http",
"url": "http://localhost:3000/mcp",
"headers": {
"API_KEY": "value" "API_KEY": "value"
} }
} }

View File

@@ -450,7 +450,7 @@ async def _setup_and_execute_agent_step(
mcp_servers[server_name] = { mcp_servers[server_name] = {
k: v k: v
for k, v in server_config.items() for k, v in server_config.items()
if k in ("transport", "command", "args", "url", "env") if k in ("transport", "command", "args", "url", "env", "headers")
} }
for tool_name in server_config["enabled_tools"]: for tool_name in server_config["enabled_tools"]:
enabled_tools[tool_name] = server_name enabled_tools[tool_name] = server_name

View File

@@ -552,6 +552,7 @@ async def mcp_server_metadata(request: MCPServerMetadataRequest):
args=request.args, args=request.args,
url=request.url, url=request.url,
env=request.env, env=request.env,
headers=request.headers,
timeout_seconds=timeout, timeout_seconds=timeout,
) )
@@ -562,6 +563,7 @@ async def mcp_server_metadata(request: MCPServerMetadataRequest):
args=request.args, args=request.args,
url=request.url, url=request.url,
env=request.env, env=request.env,
headers=request.headers,
tools=tools, tools=tools,
) )

View File

@@ -10,7 +10,10 @@ class MCPServerMetadataRequest(BaseModel):
"""Request model for MCP server metadata.""" """Request model for MCP server metadata."""
transport: str = Field( transport: str = Field(
..., description="The type of MCP server connection (stdio or sse)" ...,
description=(
"The type of MCP server connection (stdio or sse or streamable_http)"
),
) )
command: Optional[str] = Field( command: Optional[str] = Field(
None, description="The command to execute (for stdio type)" None, description="The command to execute (for stdio type)"
@@ -21,7 +24,12 @@ class MCPServerMetadataRequest(BaseModel):
url: Optional[str] = Field( url: Optional[str] = Field(
None, description="The URL of the SSE server (for sse type)" None, description="The URL of the SSE server (for sse type)"
) )
env: Optional[Dict[str, str]] = Field(None, description="Environment variables") env: Optional[Dict[str, str]] = Field(
None, description="Environment variables (for stdio type)"
)
headers: Optional[Dict[str, str]] = Field(
None, description="HTTP headers (for sse/streamable_http type)"
)
timeout_seconds: Optional[int] = Field( timeout_seconds: Optional[int] = Field(
None, description="Optional custom timeout in seconds for the operation" None, description="Optional custom timeout in seconds for the operation"
) )
@@ -31,7 +39,10 @@ class MCPServerMetadataResponse(BaseModel):
"""Response model for MCP server metadata.""" """Response model for MCP server metadata."""
transport: str = Field( transport: str = Field(
..., description="The type of MCP server connection (stdio or sse)" ...,
description=(
"The type of MCP server connection (stdio or sse or streamable_http)"
),
) )
command: Optional[str] = Field( command: Optional[str] = Field(
None, description="The command to execute (for stdio type)" None, description="The command to execute (for stdio type)"
@@ -42,7 +53,12 @@ class MCPServerMetadataResponse(BaseModel):
url: Optional[str] = Field( url: Optional[str] = Field(
None, description="The URL of the SSE server (for sse type)" None, description="The URL of the SSE server (for sse type)"
) )
env: Optional[Dict[str, str]] = Field(None, description="Environment variables") env: Optional[Dict[str, str]] = Field(
None, description="Environment variables (for stdio type)"
)
headers: Optional[Dict[str, str]] = Field(
None, description="HTTP headers (for sse/streamable_http type)"
)
tools: List = Field( tools: List = Field(
default_factory=list, description="Available tools from the MCP server" default_factory=list, description="Available tools from the MCP server"
) )

View File

@@ -47,17 +47,19 @@ async def load_mcp_tools(
args: Optional[List[str]] = None, args: Optional[List[str]] = None,
url: Optional[str] = None, url: Optional[str] = None,
env: Optional[Dict[str, str]] = None, env: Optional[Dict[str, str]] = None,
headers: Optional[Dict[str, str]] = None,
timeout_seconds: int = 60, # Longer default timeout for first-time executions timeout_seconds: int = 60, # Longer default timeout for first-time executions
) -> List: ) -> List:
""" """
Load tools from an MCP server. Load tools from an MCP server.
Args: Args:
server_type: The type of MCP server connection (stdio or sse) server_type: The type of MCP server connection (stdio, sse, or streamable_http)
command: The command to execute (for stdio type) command: The command to execute (for stdio type)
args: Command arguments (for stdio type) args: Command arguments (for stdio type)
url: The URL of the SSE server (for sse type) url: The URL of the SSE/HTTP server (for sse/streamable_http type)
env: Environment variables env: Environment variables (for stdio type)
headers: HTTP headers (for sse/streamable_http type)
timeout_seconds: Timeout in seconds (default: 60 for first-time executions) timeout_seconds: Timeout in seconds (default: 60 for first-time executions)
Returns: Returns:
@@ -90,7 +92,7 @@ async def load_mcp_tools(
) )
return await _get_tools_from_client_session( return await _get_tools_from_client_session(
sse_client(url=url), timeout_seconds sse_client(url=url, headers=headers, timeout=timeout_seconds), timeout_seconds
) )
elif server_type == "streamable_http": elif server_type == "streamable_http":
@@ -100,7 +102,7 @@ async def load_mcp_tools(
) )
return await _get_tools_from_client_session( return await _get_tools_from_client_session(
streamablehttp_client(url=url), timeout_seconds streamablehttp_client(url=url, headers=headers, timeout=timeout_seconds), timeout_seconds,
) )
else: else:

View File

@@ -87,10 +87,15 @@ async def test_load_mcp_tools_sse_success(mock_sse_client, mock_get_tools):
result = await mcp_utils.load_mcp_tools( result = await mcp_utils.load_mcp_tools(
server_type="sse", server_type="sse",
url="http://localhost:1234", url="http://localhost:1234",
headers={"Authorization": "Bearer 1234567890"},
timeout_seconds=7, timeout_seconds=7,
) )
assert result == ["toolB"] assert result == ["toolB"]
mock_sse_client.assert_called_once_with(url="http://localhost:1234") mock_sse_client.assert_called_once_with(
url="http://localhost:1234",
headers={"Authorization": "Bearer 1234567890"},
timeout=7,
)
mock_get_tools.assert_awaited_once_with(mock_client, 7) mock_get_tools.assert_awaited_once_with(mock_client, 7)

View File

@@ -12,6 +12,7 @@ export interface GenericMCPServerMetadata<T extends string> {
transport: T; transport: T;
enabled: boolean; enabled: boolean;
env?: Record<string, string>; env?: Record<string, string>;
headers?: Record<string, string>;
tools: MCPToolMetadata[]; tools: MCPToolMetadata[];
createdAt: number; createdAt: number;
updatedAt: number; updatedAt: number;
@@ -28,8 +29,9 @@ export type SimpleStdioMCPServerMetadata = Omit<
"enabled" | "tools" | "createdAt" | "updatedAt" "enabled" | "tools" | "createdAt" | "updatedAt"
>; >;
export interface SSEMCPServerMetadata extends GenericMCPServerMetadata<"sse"|"streamable_http"> { export interface SSEMCPServerMetadata
transport: "sse"|"streamable_http" extends GenericMCPServerMetadata<"sse" | "streamable_http"> {
transport: "sse" | "streamable_http";
url: string; url: string;
} }

View File

@@ -94,7 +94,7 @@ export const getChatStreamSettings = () => {
if (mcpServers.length > 0) { if (mcpServers.length > 0) {
mcpSettings = { mcpSettings = {
servers: mcpServers.reduce((acc, cur) => { servers: mcpServers.reduce((acc, cur) => {
const { transport, env } = cur; const { transport, env, headers } = cur;
let server: SimpleMCPServerMetadata; let server: SimpleMCPServerMetadata;
if (transport === "stdio") { if (transport === "stdio") {
server = { server = {
@@ -108,7 +108,7 @@ export const getChatStreamSettings = () => {
server = { server = {
name: cur.name, name: cur.name,
transport, transport,
env, headers,
url: cur.url, url: cur.url,
}; };
} }