fix: store original MCP tool name, make close_mcp public

This commit is contained in:
Re-bin 2026-02-15 07:00:27 +00:00
parent 54d5f637e7
commit 52cf1da30a
4 changed files with 41 additions and 9 deletions

View File

@ -16,7 +16,7 @@
⚡️ Delivers core agent functionality in just **~4,000** lines of code — **99% smaller** than Clawdbot's 430k+ lines. ⚡️ Delivers core agent functionality in just **~4,000** lines of code — **99% smaller** than Clawdbot's 430k+ lines.
📏 Real-time line count: **3,536 lines** (run `bash core_agent_lines.sh` to verify anytime) 📏 Real-time line count: **3,656 lines** (run `bash core_agent_lines.sh` to verify anytime)
## 📢 News ## 📢 News
@ -683,6 +683,40 @@ That's it! Environment variables, model prefixing, config matching, and `nanobot
</details> </details>
### MCP (Model Context Protocol)
> [!TIP]
> The config format is compatible with Claude Desktop / Cursor. You can copy MCP server configs directly from any MCP server's README.
nanobot supports [MCP](https://modelcontextprotocol.io/) — connect external tool servers and use them as native agent tools.
Add MCP servers to your `config.json`:
```json
{
"tools": {
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"]
}
}
}
}
```
Two transport modes are supported:
| Mode | Config | Example |
|------|--------|---------|
| **Stdio** | `command` + `args` | Local process via `npx` / `uvx` |
| **HTTP** | `url` | Remote endpoint (`https://mcp.example.com/sse`) |
MCP tools are automatically discovered and registered on startup. The LLM can use them alongside built-in tools — no extra configuration needed.
### Security ### Security
> For production deployments, set `"restrictToWorkspace": true` in your config to sandbox the agent. > For production deployments, set `"restrictToWorkspace": true` in your config to sandbox the agent.

View File

@ -229,7 +229,7 @@ class AgentLoop:
except asyncio.TimeoutError: except asyncio.TimeoutError:
continue continue
async def _close_mcp(self) -> None: async def close_mcp(self) -> None:
"""Close MCP connections.""" """Close MCP connections."""
if self._mcp_stack: if self._mcp_stack:
try: try:

View File

@ -14,7 +14,7 @@ class MCPToolWrapper(Tool):
def __init__(self, session, server_name: str, tool_def): def __init__(self, session, server_name: str, tool_def):
self._session = session self._session = session
self._server = server_name self._original_name = tool_def.name
self._name = f"mcp_{server_name}_{tool_def.name}" self._name = f"mcp_{server_name}_{tool_def.name}"
self._description = tool_def.description or tool_def.name self._description = tool_def.description or tool_def.name
self._parameters = tool_def.inputSchema or {"type": "object", "properties": {}} self._parameters = tool_def.inputSchema or {"type": "object", "properties": {}}
@ -33,9 +33,7 @@ class MCPToolWrapper(Tool):
async def execute(self, **kwargs: Any) -> str: async def execute(self, **kwargs: Any) -> str:
from mcp import types from mcp import types
result = await self._session.call_tool( result = await self._session.call_tool(self._original_name, arguments=kwargs)
self._name.removeprefix(f"mcp_{self._server}_"), arguments=kwargs
)
parts = [] parts = []
for block in result.content: for block in result.content:
if isinstance(block, types.TextContent): if isinstance(block, types.TextContent):

View File

@ -405,7 +405,7 @@ def gateway(
except KeyboardInterrupt: except KeyboardInterrupt:
console.print("\nShutting down...") console.print("\nShutting down...")
finally: finally:
await agent._close_mcp() await agent.close_mcp()
heartbeat.stop() heartbeat.stop()
cron.stop() cron.stop()
agent.stop() agent.stop()
@ -473,7 +473,7 @@ def agent(
with _thinking_ctx(): with _thinking_ctx():
response = await agent_loop.process_direct(message, session_id) response = await agent_loop.process_direct(message, session_id)
_print_agent_response(response, render_markdown=markdown) _print_agent_response(response, render_markdown=markdown)
await agent_loop._close_mcp() await agent_loop.close_mcp()
asyncio.run(run_once()) asyncio.run(run_once())
else: else:
@ -515,7 +515,7 @@ def agent(
console.print("\nGoodbye!") console.print("\nGoodbye!")
break break
finally: finally:
await agent_loop._close_mcp() await agent_loop.close_mcp()
asyncio.run(run_interactive()) asyncio.run(run_interactive())