# v3.1.0 — MCP Adapter & Tool Router

External tool server integration and LLM provider normalization.

---

## MCP Adapter

The Model Context Protocol adapter connects CleverAgents to external tool servers.

### Supported Transports

| Transport | Description | Config Required |
|-----------|-------------|-----------------|
| `stdio` | Spawns subprocess | `command` |
| `sse` | Server-Sent Events HTTP | `url` |
| `streamable-http` | Streamable HTTP | `url` |

### Configuration & Usage

```python
from cleveragents.mcp.adapter import MCPToolAdapter, MCPServerConfig

config = MCPServerConfig(
    name="my-tools", transport="stdio", command="python",
    args=["-m", "my_mcp_server"], env={"API_KEY": "secret"},
)
adapter = MCPToolAdapter(config)
adapter.connect(timeout=10.0)
tools = adapter.discover_tools()
result = adapter.invoke("create_issue", {"title": "Bug"})
# result: {success: true, data: {"issue_id": 42}, duration_ms: 145.3}
adapter.disconnect()
```

### ToolRegistry Integration

```python
from cleveragents.tool.registry import ToolRegistry
registry = ToolRegistry()
adapter.register_tools(registry, namespace="my-tools")
# Tools available as "my-tools/<tool_name>"
```

### Capability Inference (name-based heuristics)

- `read`, `get`, `list`, `search`, `find` — inferred as read-only
- `write`, `create`, `update`, `delete`, `set` — inferred as writable

### Reconnect on Failure

```python
try: adapter.invoke("tool", {"arg": "x"})
except RuntimeError:
    adapter.reconnect(timeout=10.0)
    adapter.discover_tools()
```

---

## Tool Router

Normalizes LLM provider tool calls into a unified internal representation.

### Supported Provider Formats

| Provider | Shape | Arguments Key | Type |
|----------|-------|---------------|------|
| OpenAI | `{"name": "...", "arguments": "..."}` | `arguments` | JSON string |
| Anthropic | `{"name": "...", "input": {...}}` | `input` | dict |
| LangChain | `{"name": "...", "type": "tool_call", "args": {...}}` | `args` | dict |

### Usage

```python
from cleveragents.tool.router import ToolCallRouter
router = ToolCallRouter(registry, runner, plan_id="plan-001")
result = router.route({"name": "files/read_file", 'arguments': '{"path": "a.py"}'})
# result.provider_format: "openai"  result.tool_call_id: "tc_<24-hex>"

# Stable IDs: generate_tool_call_id("plan-001", 0) always returns same value
```

---

## See Also

- [MCP Tool Adapter Reference](../../reference/mcp_adapter.md)
- [Tool Call Router Reference](../../reference/tool_router.md)
- [ADR-011](../../adr/ADR-011-tool-system.md): Tool System
- [ADR-029](../../adr/ADR-029-model-context-protocol.md): MCP Adoption
