Understanding external MCP server routing in projects03
MCP (Model Context Protocol) is a standard for AI tools to communicate with external services. An MCP server exposes tools that can be discovered and invoked by AI assistants.
The Meta-Router connects to multiple MCP servers and provides a unified interface to all their tools.
Connects to servers via stdio transport and handles JSON-RPC messages.
Finds available servers and tools, infers capabilities automatically.
Stores normalized tools in a searchable index with capability tags.
Selects the best tool and executes it on the appropriate server.
The Discovery module scans configured servers and retrieves their available tools.
Servers are defined in .mcp.json:
{
"mcpServers": {
"browser-mcp": {
"command": "node",
"args": ["browser-mcp/index.js"]
},
"paaf": {
"command": "python",
"args": ["-m", "paaf"]
}
}
}
Each server is spawned as a subprocess, and the client connects via stdin/stdout.
Once connected, the client sends a tools/list request to get available tools.
The Discovery module then infers capabilities from tool names and descriptions:
# Tool: browser_navigate # Description: "Navigate to a URL in the browser" # Inferred capabilities: ["browser", "navigation", "web"] CAPABILITY_KEYWORDS = { "browser": ["browser", "web", "navigate"], "file": ["file", "read", "write"], "research": ["research", "search", "analyze"], }
Tools from different servers may have different schemas. The Registry normalizes them:
class NormalizedTool: tool_id: str # "browser-mcp:browser_navigate" name: str # "browser_navigate" server: str # "browser-mcp" capabilities: list # ["browser", "navigation"] input_schema: dict # JSON Schema for inputs
The full tool ID includes the server name to avoid collisions between servers that might have tools with the same name.
When a task arrives, the Router searches the Registry for matching tools:
# Find tools for "browser" capability tools = registry.find_by_capability("browser") # Returns: [browser_navigate, browser_screenshot, browser_click, ...] # Select best tool for task tool = selector.select( task="Take a screenshot", capabilities=["browser", "screenshot"] ) # Returns: browser_screenshot
The MCP Client communicates with servers using JSON-RPC over stdio:
# Request (to server stdin) {"jsonrpc": "2.0", "method": "tools/call", "params": {...}, "id": 1} # Response (from server stdout) {"jsonrpc": "2.0", "result": {...}, "id": 1}
The MCP Meta-Router implements the ProviderAdapter protocol,
making it a first-class citizen in the orchestrator:
The orchestrator can select MCP tools alongside internal tools and AI provider tools, all through the same capability-based routing system.