refactor(module11): restructure MCP client implementation and migrate to chapter 11

This commit is contained in:
Annyfee
2025-12-10 15:38:56 +08:00
parent fd3774d849
commit bca3f7486f
13 changed files with 671 additions and 81 deletions
+92
View File
@@ -0,0 +1,92 @@
import uuid
from contextlib import AsyncExitStack
from typing import Optional,Literal
from .transports.base import MCPTransport
from .transports.http import HttpMCPTransport
from .transports.stdio import StdioMCPTransport
class MCPClient:
# 编辑器 _impl 必须满足MCPTransport协议
_impl:MCPTransport
def __init__(
self,
transport:Literal["stdio","http"]="stdio",
command:str=None,
args:list[str]=None,
env:dict=None,
url:str=None
):
"""
MCP 客户端 - 支持 stdio 与 HTTP 两种传输方式
:param transport: 传输模式 "stdio" / "http"
:param command: stdio 模式的命令 (如npx
:param args: stdio 模式的参数
:param env: stdio 模式的环境变量
:param url: http模式的端点 URL
"""
if transport=="stdio":
if command is None:
raise ValueError("stdio 传输模式需要参数 'command'")
self._impl = StdioMCPTransport(command=command,args=args or [],env=env)
elif transport=="http":
if url is None:
raise ValueError("http 传输模式需要参数 'command'")
self._impl = HttpMCPTransport(url=url)
else:
raise ValueError(f"不支持的传输模式: {transport}")
async def connect(self):
""" 建立MCP连接(stdio或HTTP) """
await self._impl.connect()
async def list_tools(self):
"""查询工具列表,为LLM建立上下文用"""
return await self._impl.list_tools()
async def call_tool(self,name:str,args:dict):
"""调用工具(工程化:加上防御性处理)"""
return await self._impl.call_tool(name,args)
async def cleanup(self):
"""关闭MCP服务、会话和transport"""
return await self._impl.cleanup()
async def _http_request(self,method:str,params:dict=None):
""" 发送 HTTP JSON-RPC 请求 """
payload = {
"jsonrpc":"2.0",
"id":str(uuid.uuid4()),
"method":method,
}
if params:
payload["params"] = params
headers = {
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream"
}
if self.session_id:
headers["Mcp-Session-Id"] = self.session_id
response = await self.http_client.post(
self.url,
json=payload,
headers=headers
)
if "Mcp-Session-Id" in response.headers:
self.session_id = response.headers["Mcp-Session-Id"]
response.raise_for_status()
return response.json()