""" MCP Server 基类 提供通用的 MCP 服务器基础设施 设计说明: - McpServer: 通用 MCP 服务器基类 - 子类在 __init__ 中通过 self.tools = [...] 赋值工具实例 - 提供工具列表展示、调用处理、服务器启动等通用逻辑 使用示例: class MyServer(McpServer): def __init__(self): super().__init__("my-mcp", "1.0.0") # 直接赋值工具实例列表 self.tools = [MyTool1(), MyTool2()] # 启动服务器 server = MyServer() await server.run_stdio() """ import asyncio from typing import Any, Dict, List, Optional from mcp.server import Server from mcp.server.models import InitializationOptions from mcp.types import ( Tool, TextContent, ImageContent, EmbeddedResource, ServerCapabilities, ) class BaseMcpServer: """ 通用 MCP 服务器基类 子类在 __init__ 中通过 self.tools 属性赋值工具实例列表。 封装了工具列表展示、调用处理、结果格式化、服务器启动等通用逻辑。 """ def __init__(self, server_name: str, version: str = "1.0.0"): """ 初始化 MCP 服务器 Args: server_name: 服务器名称 version: 服务器版本 """ self.server_name = server_name self.version = version self.server = Server(server_name) # 工具列表(子类在 __init__ 中赋值) self.tools: List[Any] = [] # 注册处理器 self.server.list_tools()(self._handle_list_tools) self.server.call_tool()(self._handle_call_tool) async def _handle_list_tools(self) -> list[Tool]: """列出所有可用的工具""" return [ Tool( name=tool.name, description=tool.description, inputSchema=tool.parameters_schema, ) for tool in self.tools ] async def _handle_call_tool( self, name: str, arguments: Optional[dict[str, Any]] = None ) -> list[TextContent | ImageContent | EmbeddedResource]: """处理工具调用""" if not arguments: arguments = {} # 查找工具 tool = next((t for t in self.tools if t.name == name), None) if not tool: return [TextContent(type="text", text=f"未知工具:{name}")] try: result = tool.execute(**arguments) response_text = self._format_tool_result(result) return [TextContent(type="text", text=response_text)] except ValueError as e: return [TextContent(type="text", text=f"❌ 参数错误:{str(e)}")] except RuntimeError as e: return [TextContent(type="text", text=f"❌ 执行失败:{str(e)}")] except Exception as e: return [TextContent(type="text", text=f"❌ 未知错误:{str(e)}")] @staticmethod def _format_tool_result(result: Any) -> str: """ 格式化工具执行结果 支持多种返回格式: - 包含 message/data 属性的对象 - 字典(包含 message/data 键) - 其他类型(直接转为字符串) """ response_text = "" # 提取消息 message = getattr(result, 'message', None) if message: response_text += f"✅ {message}\n\n" elif isinstance(result, dict) and 'message' in result: response_text += f"✅ {result['message']}\n\n" # 提取数据 data = getattr(result, 'data', None) if data is None and isinstance(result, dict): data = result.get('data') if data: response_text += "详情:\n" if isinstance(data, dict): for key, value in data.items(): response_text += f" - {key}: {value}\n" else: response_text += f" {data}\n" # 如果没有消息也没有数据,直接返回结果的字符串形式 if not response_text: response_text = str(result) return response_text async def run_stdio(self): """ 启动服务器,使用标准输入输出通信 """ from mcp.server.stdio import stdio_server async with stdio_server() as (read_stream, write_stream): await self.server.run( read_stream, write_stream, InitializationOptions( server_name=self.server_name, server_version=self.version, capabilities=ServerCapabilities( tools={} # 启用工具能力 ), ), )