# MCP Server Exposure Implementation Plan

## Overview

Expose the PydanticAI Multi-Tenant Platform as an MCP server, allowing MCP clients (Claude Desktop, Cursor, etc.) to call platform agents via the MCP protocol.

## Architecture

```
┌─────────────────────────────────────────────────────────────────┐
│                    MCP Clients                                   │
│  (Claude Desktop, Cursor, custom MCP clients)                   │
└─────────────────────────────────────────────────────────────────┘
                              │
            ┌─────────────────┼─────────────────┐
            │                 │                 │
            ▼                 ▼                 ▼
      ┌──────────┐     ┌──────────┐      ┌──────────┐
      │  stdio   │     │   SSE    │      │   HTTP   │
      │ transport│     │ transport│      │ transport│
      └──────────┘     └──────────┘      └──────────┘
            │                 │                 │
            └─────────────────┼─────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                    FastMCP Server                                │
│  Tools: chat, list_agents, get_usage, list_conversations       │
│  Auth: Tenant API key passed as tool argument or header         │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│               Existing Platform Services                         │
│  ConversationService, AgentRegistry, TenantService              │
└─────────────────────────────────────────────────────────────────┘
```

## Authentication Strategy

Two approaches for MCP auth:

**Option A: API key as tool argument (simpler, chosen)**
- Each MCP tool accepts an `api_key` parameter
- Client passes their tenant API key with each call
- Works with all transports (stdio, SSE, HTTP)

**Option B: HTTP header auth (for HTTP/SSE only)**
- Client passes `Authorization: Bearer sk-tenant-xxx` header
- Only works with HTTP transports
- More secure but less universal

We'll implement **Option A** with optional **Option B** support for HTTP transports.

## MCP Tools to Expose

| Tool | Description | Parameters |
|------|-------------|------------|
| `chat` | Send a message to an agent | `api_key`, `prompt`, `agent?`, `conversation_id?` |
| `list_agents` | List available agents | `api_key` |
| `get_usage` | Get usage statistics | `api_key`, `days?` |
| `list_conversations` | List recent conversations | `api_key`, `limit?` |
| `get_conversation` | Get conversation history | `api_key`, `conversation_id` |
| `clear_conversation` | Clear a conversation | `api_key`, `conversation_id` |

## Implementation Steps

### Phase 1: Add FastMCP Dependency

1. Add `fastmcp>=2.0.0` to `pyproject.toml` dependencies
2. Run `uv sync` to update lock file

### Phase 2: Create MCP Server Module

Create `src/pydanticai_multiagent/mcp/server.py`:

```python
from fastmcp import FastMCP
from fastmcp.server.dependencies import get_http_request

mcp = FastMCP(
    name="PydanticAI Platform",
    instructions="Multi-tenant AI agent platform. Use your API key for authentication.",
)

@mcp.tool
async def chat(
    api_key: str,
    prompt: str,
    agent: str | None = None,
    conversation_id: str | None = None,
) -> dict:
    """Send a message to an AI agent and get a response."""
    ...

@mcp.tool
async def list_agents(api_key: str) -> list[dict]:
    """List all agents available to your tenant."""
    ...
```

### Phase 3: Integrate with Platform Services

- Create helper to validate API key and get tenant
- Reuse existing `ConversationService`, `AgentRegistry`, `TenantService`
- Handle errors gracefully with MCP-friendly error messages

### Phase 4: Mount on FastAPI

Update `src/pydanticai_multiagent/api/app.py`:

```python
from pydanticai_multiagent.mcp import mcp_server

# In create_app():
mcp_app = mcp_server.http_app(path='/mcp')
app.mount("/mcp", mcp_app)
```

### Phase 5: Add CLI Command for Stdio Transport

Update `src/pydanticai_multiagent/cli/main.py`:

```python
# Add mcp-serve command
mcp_parser = subparsers.add_parser("mcp-serve", help="Run MCP server (stdio)")

def run_mcp_server():
    from pydanticai_multiagent.mcp import mcp_server
    mcp_server.run()  # Runs with stdio transport by default
```

### Phase 6: Update Documentation

- Update README with MCP section
- Add Claude Desktop config example
- Add Cursor config example

## File Structure

```
src/pydanticai_multiagent/
├── mcp/
│   ├── __init__.py           # Export mcp_server
│   ├── server.py             # FastMCP server with tools
│   └── auth.py               # API key validation helper
└── ...

docs/
└── mcp-integration.md        # MCP usage documentation
```

## Configuration Examples

### Claude Desktop (`claude_desktop_config.json`)

```json
{
  "mcpServers": {
    "pydanticai-platform": {
      "command": "pydanticai-platform",
      "args": ["mcp-serve"]
    }
  }
}
```

### Remote HTTP Connection

```json
{
  "mcpServers": {
    "pydanticai-platform": {
      "url": "https://your-platform.fly.dev/mcp",
      "transport": "streamable-http"
    }
  }
}
```

## Testing Plan

1. Unit tests for MCP tools
2. Integration test: stdio transport
3. Integration test: HTTP transport
4. Manual test with Claude Desktop

## Security Considerations

- API keys validated on every tool call
- Rate limiting applied per tenant
- Token limits enforced
- Invalid keys return clear error (not 500)

## Future Enhancements (Phase 2 - Platform-wide MCP servers)

After this implementation, we can add:
- Platform-wide MCP servers that agents can use as toolsets
- Admin API to configure shared MCP servers
- Agent-specific MCP server bindings
