Coverage for merco/mcp/tool.py: 100%
26 statements
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-07 14:04 +0800
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-07 14:04 +0800
1"""MCP tool → BaseTool adapter for ToolRegistry."""
2from merco.tools.base import BaseTool
5class MCPServerTool(BaseTool):
6 """Adapt an MCP tool spec to a merco ToolRegistry-compatible tool."""
8 def __init__(self, mcp_spec: dict, server_name: str, handler, guard=None):
9 self.name = mcp_spec.get("name", "unknown")
10 self.description = mcp_spec.get("description", f"MCP tool from {server_name}")
11 self.toolset = f"mcp:{server_name}"
12 self.server = server_name
13 self._input_schema = mcp_spec.get("inputSchema", {})
14 self._handler = handler # async (tool_name, arguments) -> dict
15 self._guard = guard
17 @property
18 def parameters(self) -> dict:
19 return self._input_schema
21 async def execute(self, **kwargs) -> dict:
22 # ToolGuard check — sandbox integration
23 if self._guard:
24 approved = await self._guard.check(
25 self.name, kwargs, source=f"mcp:{self.server}"
26 )
27 if not approved:
28 return {"error": "操作已被拦截或取消"}
29 try:
30 return await self._handler(self.name, kwargs)
31 except Exception as e:
32 return {"error": f"{self.name}: {e}", "isError": True}
34 def check(self) -> bool:
35 return self._handler is not None
37 def get_definition(self, context=None) -> dict:
38 return {
39 "type": "function",
40 "function": {
41 "name": self.name,
42 "description": self.description,
43 "parameters": self._input_schema,
44 },
45 }