base_agent/mcp/mcp_server.py

129 lines
5.1 KiB
Python
Raw Normal View History

2026-02-28 08:21:35 +00:00
"""
mcp/mcp_server.py
2026-03-09 05:37:29 +00:00
MCP Server从配置读取 server_nametransportenabled_tools
支持按配置动态过滤注册工具
2026-02-28 08:21:35 +00:00
"""
from typing import Type
2026-03-09 05:37:29 +00:00
from config.settings import MCPConfig, settings
2026-02-28 08:21:35 +00:00
from mcp.mcp_protocol import MCPMethod, MCPRequest, MCPResponse, ToolSchema
from tools.base_tool import BaseTool, ToolResult
from utils.logger import get_logger
class MCPServer:
"""
2026-03-09 05:37:29 +00:00
MCP 服务器核心类配置驱动
2026-02-28 08:21:35 +00:00
2026-03-09 05:37:29 +00:00
配置项:
- server_name: 服务器名称
- transport: 通信方式 (stdio / http / websocket)
- enabled_tools: 白名单仅注册列表中的工具
2026-02-28 08:21:35 +00:00
使用示例:
2026-03-09 05:37:29 +00:00
server = MCPServer() # 从 settings 读取配置
server = MCPServer(cfg=custom_cfg) # 使用自定义配置
2026-02-28 08:21:35 +00:00
server.register_tool(CalculatorTool)
response = server.handle_request(request)
"""
2026-03-09 05:37:29 +00:00
def __init__(self, cfg: MCPConfig | None = None):
"""
Args:
cfg: MCPConfig 实例None 时从全局 settings 读取
"""
self.cfg = cfg or settings.mcp
2026-02-28 08:21:35 +00:00
self.logger = get_logger("MCP")
2026-03-09 05:37:29 +00:00
self._registry: dict[str, BaseTool] = {}
2026-02-28 08:21:35 +00:00
2026-03-09 05:37:29 +00:00
self.logger.info(f"🚀 MCP Server [{self.cfg.server_name}] 启动")
self.logger.info(f" transport = {self.cfg.transport}")
self.logger.info(f" enabled_tools = {self.cfg.enabled_tools}")
2026-02-28 08:21:35 +00:00
# ── 工具注册 ────────────────────────────────────────────────
def register_tool(self, tool_class: Type[BaseTool]) -> None:
"""
2026-03-09 05:37:29 +00:00
注册工具 enabled_tools 白名单过滤
2026-02-28 08:21:35 +00:00
Args:
2026-03-09 05:37:29 +00:00
tool_class: 继承自 BaseTool 的工具类
2026-02-28 08:21:35 +00:00
"""
instance = tool_class()
if not instance.name:
raise ValueError(f"工具类 {tool_class.__name__} 未设置 name 属性")
2026-03-09 05:37:29 +00:00
# 白名单过滤
if instance.name not in self.cfg.enabled_tools:
self.logger.warning(
f"⏭ 工具 [{instance.name}] 不在 enabled_tools 白名单中,跳过注册"
)
return
2026-02-28 08:21:35 +00:00
self._registry[instance.name] = instance
self.logger.info(f"📌 注册工具: [{instance.name}] — {instance.description}")
def register_tools(self, *tool_classes: Type[BaseTool]) -> None:
"""批量注册多个工具类"""
for cls in tool_classes:
self.register_tool(cls)
2026-03-09 05:37:29 +00:00
# ── 请求处理 ────────────────────────────────────────────────
2026-02-28 08:21:35 +00:00
def handle_request(self, request: MCPRequest) -> MCPResponse:
2026-03-09 05:37:29 +00:00
"""处理 MCP 请求的统一入口"""
self.logger.info(
f"📨 收到请求 id={request.id} method={request.method} "
f"transport={self.cfg.transport}"
)
2026-02-28 08:21:35 +00:00
handlers = {
MCPMethod.TOOLS_LIST: self._handle_tools_list,
MCPMethod.TOOLS_CALL: self._handle_tools_call,
}
handler = handlers.get(request.method)
if handler is None:
return self._error_response(request.id, -32601, f"未知方法: {request.method}")
return handler(request)
def _handle_tools_list(self, request: MCPRequest) -> MCPResponse:
schemas = [tool.get_schema().to_dict() for tool in self._registry.values()]
2026-03-09 05:37:29 +00:00
self.logger.info(f"📋 返回工具列表,共 {len(schemas)}")
return MCPResponse(id=request.id, result={"tools": schemas})
2026-02-28 08:21:35 +00:00
def _handle_tools_call(self, request: MCPRequest) -> MCPResponse:
tool_name = request.params.get("name")
arguments = request.params.get("arguments", {})
2026-03-09 05:37:29 +00:00
tool = self._registry.get(tool_name)
2026-02-28 08:21:35 +00:00
if tool is None:
return self._error_response(
request.id, -32602,
2026-03-09 05:37:29 +00:00
f"工具 [{tool_name}] 不存在,可用: {list(self._registry.keys())}"
2026-02-28 08:21:35 +00:00
)
result: ToolResult = tool.safe_execute(**arguments)
if result.success:
return MCPResponse(
id=request.id,
2026-03-09 05:37:29 +00:00
result={"content": [{"type": "text", "text": result.output}],
"metadata": result.metadata},
2026-02-28 08:21:35 +00:00
)
2026-03-09 05:37:29 +00:00
return self._error_response(request.id, -32000, result.output)
2026-02-28 08:21:35 +00:00
# ── 工具方法 ────────────────────────────────────────────────
def get_tool_schemas(self) -> list[ToolSchema]:
return [tool.get_schema() for tool in self._registry.values()]
def list_tools(self) -> list[str]:
return list(self._registry.keys())
@staticmethod
def _error_response(req_id: str, code: int, message: str) -> MCPResponse:
2026-03-09 05:37:29 +00:00
return MCPResponse(id=req_id, error={"code": code, "message": message})
2026-02-28 08:21:35 +00:00
def __repr__(self) -> str:
2026-03-09 05:37:29 +00:00
return (
f"MCPServer(name={self.cfg.server_name!r}, "
f"transport={self.cfg.transport!r}, "
f"tools={self.list_tools()})"
)