|
| 1 | +# ADR 0005: MCP Streamable HTTP Transport |
| 2 | + |
| 3 | +## Status |
| 4 | + |
| 5 | +Accepted for P2 implementation. |
| 6 | + |
| 7 | +## Decision |
| 8 | + |
| 9 | +Expose the TeaAgent workspace tool pack to MCP clients over stdio JSON-RPC |
| 10 | +and Streamable HTTP (POST/GET/DELETE on `/mcp`) with `Mcp-Session-Id` session |
| 11 | +management, bearer-token/OAuth 2.1 guardrails, and Origin allowlisting. |
| 12 | + |
| 13 | +## Rationale |
| 14 | + |
| 15 | +- stdio JSON-RPC (`serve_mcp_stdio`) provides zero-config integration with |
| 16 | + MCP clients that launch the server as a subprocess (Claude Desktop, Zed, etc.). |
| 17 | +- Streamable HTTP (`serve_mcp_http`) enables remote IDE agents, web-based |
| 18 | + clients, and multi-session scenarios. It follows the MCP Streamable HTTP |
| 19 | + draft with SSE-based streaming on GET and JSON-RPC on POST. |
| 20 | +- Session management via `Mcp-Session-Id` header prevents cross-session |
| 21 | + confusion and supports session termination via DELETE. |
| 22 | +- Authentication is enforced at two layers: |
| 23 | + 1. CLI layer: refuses non-loopback binds without `--auth-token` or OAuth. |
| 24 | + 2. Library layer: `build_mcp_http_server()` raises `ValueError` on |
| 25 | + non-loopback binds without `auth_token` or `oauth_server`. |
| 26 | + |
| 27 | +## Consequences |
| 28 | + |
| 29 | +- The server uses `ThreadingHTTPServer` from stdlib with a simple in-memory |
| 30 | + `MCPSessionStore`. This is sufficient for single-machine use but not for |
| 31 | + high-concurrency production deployments. |
| 32 | +- TLS is not implemented natively; a reverse proxy (nginx, Caddy) must |
| 33 | + terminate TLS for external access. |
| 34 | +- DPoP nonce negotiation and OAuth metadata endpoints are served under the |
| 35 | + same HTTP handler, enabling fully featured MCP authorization. |
| 36 | +- Batch JSON-RPC requests are supported; notifications (no `id`) return HTTP 202. |
| 37 | + |
| 38 | +## Alternatives Considered |
| 39 | + |
| 40 | +- **WebSocket transport**: MCP specification favors Streamable HTTP over |
| 41 | + WebSocket for simpler HTTP semantics. SSE provides server-to-client push |
| 42 | + without the WebSocket upgrade handshake. |
| 43 | +- **gRPC**: Rejected — MCP is JSON-RPC-based; gRPC would require a separate |
| 44 | + protocol definition and client SDK. |
| 45 | +- **aiohttp/FastAPI**: Rejected — adds framework dependencies for what is |
| 46 | + a single-path HTTP handler. `ThreadingHTTPServer` is sufficient for the |
| 47 | + target scale (single-digit concurrent MCP clients). |
0 commit comments