You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

124 lines
3.0 KiB
Markdown

# MCP Runbook
## Scope
This runbook covers the MCP adapter exposed by `app.mcp_main`.
## Endpoint
- Streamable HTTP endpoint: `POST /mcp` (mounted under `app.mcp_main`)
When using Docker Compose:
- Base URL: `http://127.0.0.1:8001/mcp`
## Runtime modes
Local:
```bash
uv run uvicorn app.mcp_main:app --host 0.0.0.0 --port 8001
```
Docker Compose service:
- `personal-agent-mcp`
## Tool surface
Always enabled:
- `check_availability`
Optional mutation tools (disabled by default):
- `scan_mailbox`
- `list_unsubscribe_candidates`
- `execute_unsubscribe`
Enable optional tools with:
```bash
MCP_ENABLE_MUTATION_TOOLS=true
```
## Authorization and scope gates
MCP tools call the shared auth backend and read auth headers from request context.
MCP auth mode resolution:
- `MCP_AUTH_MODE=inherit` (default): use `AUTH_MODE`
- `MCP_AUTH_MODE=api_key|jwt|hybrid|oauth`: override only for MCP
Supported auth headers:
- `X-API-Key`
- `Authorization: Bearer ...`
For `MCP_AUTH_MODE=oauth`, bearer tokens are validated via OAuth token introspection:
- `MCP_RESOURCE_SERVER_URL` (required canonical MCP URL, for RFC 9728 metadata/challenges)
- `MCP_OAUTH_INTROSPECTION_URL` (required)
- `MCP_OAUTH_CLIENT_ID` / `MCP_OAUTH_CLIENT_SECRET` (optional; use for introspection endpoint auth)
- `MCP_OAUTH_ISSUER` (optional strict `iss` match)
- `MCP_OAUTH_AUDIENCE` (optional required audience value)
- `MCP_OAUTH_TIMEOUT_SECONDS` (default `8`)
When OAuth mode is enabled, FastMCP exposes protected resource metadata at:
- `/.well-known/oauth-protected-resource/mcp`
and returns OAuth-compliant `WWW-Authenticate: Bearer ...` challenges for unauthenticated requests.
Required scopes:
- `check_availability`: `availability:read`
- `scan_mailbox`: `mail:scan`
- `list_unsubscribe_candidates`: `unsubscribe:read`
- `execute_unsubscribe`: `unsubscribe:execute`
## Tool verification
Verify tool list from Python:
```bash
uv run python - <<'PY'
import asyncio
from app.mcp.server import mcp
async def main():
tools = await mcp.list_tools()
print([t.name for t in tools])
asyncio.run(main())
PY
```
Expected output by mode:
- default: `['check_availability']`
- with `MCP_ENABLE_MUTATION_TOOLS=true`: all four tools
## Protocol notes
- The server uses FastMCP Streamable HTTP.
- Basic GET to `/mcp` is not a health endpoint; MCP expects protocol-compliant requests.
- In local development, FastMCP may enforce host/origin checks. If you see `421 Misdirected Request`, verify host/port and reverse-proxy headers.
## Troubleshooting
If tools fail with auth errors:
- Check `AUTH_MODE` and credentials
- Check `MCP_AUTH_MODE` override and related `MCP_OAUTH_*` variables
- Verify `MCP_RESOURCE_SERVER_URL` matches the public MCP endpoint (for example `https://mcp.example.com/mcp`)
- Confirm JWT contains required scopes
- For API key mode, verify `AGENT_API_KEY`
If tool calls fail with Google errors:
- Verify OAuth file mounts in Docker:
- `GOOGLE_CLIENT_SECRETS_FILE`
- `GOOGLE_TOKEN_FILE`