# MCP Tool Adapter This document covers the MCP (Model Context Protocol) adapter introduced in **M2.3.mcp-runtime**: connecting to external MCP servers, discovering tools, invoking them with schema validation, and registering them in the ToolRegistry. ## Overview The `MCPToolAdapter` bridges any MCP-compatible tool server into the CleverAgents runtime. It manages the full lifecycle: | Operation | Method | Description | |-----------|--------|-------------| | Connect | `connect(timeout?)` | Start the server process or HTTP session, perform handshake | | Disconnect | `disconnect()` | Clean shutdown of the server connection | | Reconnect | `reconnect(timeout?)` | Disconnect and re-connect; clears cached tool list | | Discover | `discover_tools(filter?)` | Enumerate available tools from the server | | Invoke | `invoke(name, args)` | Call a tool with automatic input validation | | Register | `register_tools(registry, namespace)` | Bulk-register into a ToolRegistry | ## Server Configuration ### `MCPServerConfig` Fields | Field | Type | Required | Description | |-------|------|----------|-------------| | `name` | `string` | Yes | Server identifier | | `transport` | `string` | Yes | `stdio`, `sse`, or `streamable-http` | | `command` | `string` | stdio only | Command to spawn the server process | | `args` | `list[string]` | No | Command-line arguments | | `env` | `dict` | No | Environment variables for the server process | | `url` | `string` | sse/http only | Server URL for remote connections | | `headers` | `dict` | No | HTTP headers for remote connections | ### Validation Rules - `stdio` transport **requires** `command` - `sse` / `streamable-http` transport **requires** `url` ## Tool Discovery After connecting, call `discover_tools()` to enumerate all tools exposed by the MCP server. Each returned `MCPToolDescriptor` includes the tool name, description, and JSON Schema for inputs. ### Filtering Use `MCPToolFilter` with `include` or `exclude` lists to control which tools are exposed. ### `MCPToolDescriptor` Fields | Field | Type | Description | |-------|------|-------------| | `name` | `string` | Tool name as exposed by the server | | `description` | `string` | Human-readable description | | `input_schema` | `dict` | JSON Schema for tool inputs | ## Tool Invocation Call `invoke(name, arguments)` to execute a discovered tool. Input arguments are validated against the tool's JSON Schema before the call is made. If validation fails, the result is returned immediately with `success=False`. ### `MCPToolResult` Fields | Field | Type | Description | |-------|------|-------------| | `success` | `bool` | Whether the invocation succeeded | | `data` | `dict` | Result payload from the server | | `error` | `string` or `null` | Error message on failure | | `duration_ms` | `float` | Wall-clock execution time in milliseconds | ## Reconnect Use `reconnect(timeout?)` to recover from a dropped connection or after a server restart. It performs a clean `disconnect()` followed by a fresh `connect()` and clears the cached tool list. Call `discover_tools()` again after reconnecting. ```python try: adapter.invoke("create_issue", {"title": "Bug"}) except RuntimeError: # Connection dropped — attempt recovery adapter.reconnect(timeout=10.0) adapter.discover_tools() ``` If the new connection attempt fails or times out, `reconnect()` raises `ConnectionError`. ## ToolRegistry Integration Discovered MCP tools can be bulk-registered into any `ToolRegistry` via `register_tools(registry, namespace)`. Each tool is registered with the name `{namespace}/{tool_name}`. Re-registration after tool list changes replaces stale entries automatically. Registered tools always carry `source="mcp"` and `source_metadata={"server": ""}` for provenance tracking. `checkpointable` is always `False` for MCP tools — external server calls cannot be rolled back transactionally. ## Capability Inference MCP tools expose limited metadata (name, description, inputSchema). The adapter automatically infers extended `ToolCapability` metadata using name-based heuristics: | Tool name keywords | Inferred capability | |---|---| | `read`, `get`, `list`, `search`, `find` | `read_only: true` | | `write`, `create`, `update`, `delete`, `set` | `writes: true` | | Both read and write keywords | `writes: true` (write takes precedence) | | Neither | `read_only: false`, `writes: false` | Inferences are applied automatically when registering tools via `register_tools()`. They can be overridden via the `overrides` block in tool or skill YAML. Use `MCPToolAdapter.infer_capabilities(tool_name)` directly to check what would be inferred for a given tool name. ## Error Classification | Error Type | When | Exception / Field | |------------|------|-------------------| | Connection failure | `connect()` with unreachable server | `ConnectionError` | | Not connected | `invoke()` / `discover_tools()` before `connect()` | `RuntimeError` | | Tool not found | `invoke()` with unknown tool name | `result.error` contains "not found" | | Validation failure | `invoke()` with invalid input | `result.error` contains "validation" | | Timeout | Server call exceeds deadline | `result.error` contains "timeout" | | Server error | Server returns `isError: true` | `result.error` contains "server error" | ## Transport Layer The `MCPTransport` base class defines the abstract interface. Concrete implementations handle stdio (child process) and HTTP (SSE / streamable-http) protocols. For testing, provide a mock transport to the adapter constructor. ## Thread Safety `MCPToolAdapter` uses `threading.RLock` internally. All public methods are safe to call from multiple threads concurrently.