--- id: review-001-mcp-body-limit name: Cap the /mcp nest body size (SRV-03, gated on mcp feature) status: pending depends_on: [] scope: narrow risk: low impact: component level: implementation tags: [server, review-001, security, mcp] --- ## Description Review 001 finding SRV-03 (mcp feature only): `src/server/adapter.rs:141-150` nests rmcp's `StreamableHttpService`; the bearer middleware only stashes identity. axum's 2 MiB `DefaultBodyLimit` applies to axum *extractors*, but the nested rmcp service collects the raw body itself (`body.collect().await`, verified against rmcp 1.8.0) with no cap — a single multi-GB chunked `POST /mcp` is buffered entirely in memory; a few concurrent requests OOM the process. Gateway routes are correctly capped at 2 MiB by the extractors; `/mcp` is the one uncapped surface. Fix: wrap the `/mcp` nest with an explicit `DefaultBodyLimit` (or an equivalent body-limit layer) sized for MCP traffic. Pick and document the limit (a JSON-RPC batch is the largest legitimate body; something in the 2–8 MiB range is defensible) rather than leaving it at hyper's unlimited default. ## Acceptance Criteria - [ ] Explicit body limit applied to the `/mcp` nest; limit value documented in code and ADR-039 or http-server.md if touched - [ ] Test: oversized `POST /mcp` body → 413 (Content-Length and streaming/chunked variants) - [ ] Normal-size MCP initialize + tools/call round-trip still passes - [ ] `cargo test --all-features` passes (feature-gated code) ## References - docs/reviews/001-initial-implementation-review.md (Part A, SRV-03) - docs/architecture/decisions/039-http-server-and-client-host-colocated.md ## Notes > Agent fills during implementation. ## Summary > Filled on completion.