From ed34cb8e1a6a49bee7bf57631ef4fc1fc2184bea Mon Sep 17 00:00:00 2001 From: Dreamwxz <82244600+Dreamwxz@users.noreply.github.com> Date: Tue, 5 May 2026 16:26:47 +0800 Subject: [PATCH] =?UTF-8?q?mcp=E6=96=B0=E5=A2=9Esse=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mcp_module/config.py | 6 ++++-- src/mcp_module/connection.py | 33 +++++++++++++++++++++++++++++++++ src/mcp_module/manager.py | 2 +- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/mcp_module/config.py b/src/mcp_module/config.py index 4d4d73af..2bc2621c 100644 --- a/src/mcp_module/config.py +++ b/src/mcp_module/config.py @@ -50,7 +50,7 @@ class MCPServerRuntimeConfig: """单个 MCP 服务器的运行时配置。""" name: str - transport: Literal["stdio", "streamable_http"] = "stdio" + transport: Literal["stdio", "streamable_http", "sse"] = "stdio" command: str = "" args: list[str] = field(default_factory=list) env: dict[str, str] = field(default_factory=dict) @@ -65,13 +65,15 @@ class MCPServerRuntimeConfig: """返回当前服务器的传输类型。 Returns: - str: ``stdio``、``streamable_http`` 或 ``unknown``。 + str: ``stdio``、``streamable_http``、``sse`` 或 ``unknown``。 """ if self.transport == "stdio" and self.command: return "stdio" if self.transport == "streamable_http" and self.url: return "streamable_http" + if self.transport == "sse" and self.url: + return "sse" return "unknown" def build_http_headers(self) -> dict[str, str]: diff --git a/src/mcp_module/connection.py b/src/mcp_module/connection.py index 10a1ea5e..631eef5e 100644 --- a/src/mcp_module/connection.py +++ b/src/mcp_module/connection.py @@ -43,16 +43,26 @@ try: from mcp.client.stdio import stdio_client from mcp.client.streamable_http import streamable_http_client + try: + from mcp.client.sse import sse_client + + SSE_AVAILABLE = True + except ImportError: + SSE_AVAILABLE = False + sse_client = None # type: ignore[assignment] + MCP_AVAILABLE = True STREAMABLE_HTTP_AVAILABLE = True except ImportError: MCP_AVAILABLE = False STREAMABLE_HTTP_AVAILABLE = False + SSE_AVAILABLE = False ClientSession = None # type: ignore[assignment,misc] StdioServerParameters = None # type: ignore[assignment,misc] mcp_types = None # type: ignore[assignment] stdio_client = None # type: ignore[assignment] streamable_http_client = None # type: ignore[assignment] + sse_client = None # type: ignore[assignment] class MCPConnection: @@ -139,6 +149,8 @@ class MCPConnection: return await self._connect_stdio() if self.config.transport_type == "streamable_http": return await self._connect_streamable_http() + if self.config.transport_type == "sse": + return await self._connect_sse() raise ValueError(f"MCP 服务器 '{self.config.name}' 使用了未知传输类型: {self.config.transport}") @@ -184,6 +196,27 @@ class MCPConnection: self._session_id_getter = session_id_getter return read_stream, write_stream + async def _connect_sse(self) -> tuple[Any, Any]: + """建立 SSE 传输连接。 + + Returns: + tuple[Any, Any]: 读写流对象。 + """ + + if not SSE_AVAILABLE or sse_client is None: + raise ImportError("当前环境未安装可用的 MCP SSE 客户端") + if not self.config.url: + raise ValueError(f"MCP 服务器 '{self.config.name}' 缺少 SSE url 配置") + + self._http_client = await self._exit_stack.enter_async_context(self._build_http_client()) + read_stream, write_stream = await self._exit_stack.enter_async_context( + sse_client( + url=self.config.url, + http_client=self._http_client, + ) + ) + return read_stream, write_stream + def _build_http_client(self) -> httpx.AsyncClient: """构建 Streamable HTTP 使用的 `httpx` 客户端。 diff --git a/src/mcp_module/manager.py b/src/mcp_module/manager.py index 53c4dbc4..f0d054e7 100644 --- a/src/mcp_module/manager.py +++ b/src/mcp_module/manager.py @@ -309,7 +309,7 @@ class MCPManager: provider_type="mcp", icons=[build_tool_icon(item) for item in getattr(tool, "icons", []) or []], annotation=build_tool_annotation(getattr(tool, "annotations", None)), - metadata={"server_name": server_name} | getattr(tool, "meta", {}), + metadata={"server_name": server_name} | (getattr(tool, "meta", {}) or {}), ) ) return tool_specs