fix: store original MCP tool name, make close_mcp public
This commit is contained in:
parent
54d5f637e7
commit
52cf1da30a
36
README.md
36
README.md
@ -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.
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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):
|
||||||
|
|||||||
@ -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())
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user