From 52cf1da30a408ac4ec91fac5e9249a72f01ee1d2 Mon Sep 17 00:00:00 2001 From: Re-bin Date: Sun, 15 Feb 2026 07:00:27 +0000 Subject: [PATCH] fix: store original MCP tool name, make close_mcp public --- README.md | 36 +++++++++++++++++++++++++++++++++++- nanobot/agent/loop.py | 2 +- nanobot/agent/tools/mcp.py | 6 ++---- nanobot/cli/commands.py | 6 +++--- 4 files changed, 41 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 47702c1..c08d3af 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ ⚡️ 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 @@ -683,6 +683,40 @@ That's it! Environment variables, model prefixing, config matching, and `nanobot +### 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 > For production deployments, set `"restrictToWorkspace": true` in your config to sandbox the agent. diff --git a/nanobot/agent/loop.py b/nanobot/agent/loop.py index cc7a0d0..7deef59 100644 --- a/nanobot/agent/loop.py +++ b/nanobot/agent/loop.py @@ -229,7 +229,7 @@ class AgentLoop: except asyncio.TimeoutError: continue - async def _close_mcp(self) -> None: + async def close_mcp(self) -> None: """Close MCP connections.""" if self._mcp_stack: try: diff --git a/nanobot/agent/tools/mcp.py b/nanobot/agent/tools/mcp.py index bcef4aa..1c8eac4 100644 --- a/nanobot/agent/tools/mcp.py +++ b/nanobot/agent/tools/mcp.py @@ -14,7 +14,7 @@ class MCPToolWrapper(Tool): def __init__(self, session, server_name: str, tool_def): self._session = session - self._server = server_name + self._original_name = tool_def.name self._name = f"mcp_{server_name}_{tool_def.name}" self._description = tool_def.description or tool_def.name self._parameters = tool_def.inputSchema or {"type": "object", "properties": {}} @@ -33,9 +33,7 @@ class MCPToolWrapper(Tool): async def execute(self, **kwargs: Any) -> str: from mcp import types - result = await self._session.call_tool( - self._name.removeprefix(f"mcp_{self._server}_"), arguments=kwargs - ) + result = await self._session.call_tool(self._original_name, arguments=kwargs) parts = [] for block in result.content: if isinstance(block, types.TextContent): diff --git a/nanobot/cli/commands.py b/nanobot/cli/commands.py index 34bfde8..6a9c92f 100644 --- a/nanobot/cli/commands.py +++ b/nanobot/cli/commands.py @@ -405,7 +405,7 @@ def gateway( except KeyboardInterrupt: console.print("\nShutting down...") finally: - await agent._close_mcp() + await agent.close_mcp() heartbeat.stop() cron.stop() agent.stop() @@ -473,7 +473,7 @@ def agent( with _thinking_ctx(): response = await agent_loop.process_direct(message, session_id) _print_agent_response(response, render_markdown=markdown) - await agent_loop._close_mcp() + await agent_loop.close_mcp() asyncio.run(run_once()) else: @@ -515,7 +515,7 @@ def agent( console.print("\nGoodbye!") break finally: - await agent_loop._close_mcp() + await agent_loop.close_mcp() asyncio.run(run_interactive())