Add Streamable HTTP request body limits - #3095
Merged
Merged
Claude / Claude Code Review
completed
Jul 14, 2026 in 12m 52s
Code review found 2 important issues
Found 5 candidates, confirmed 2. See review comments for details.
Details
| Severity | Count |
|---|---|
| 🔴 Important | 2 |
| 🟡 Nit | 0 |
| 🟣 Pre-existing | 0 |
| Severity | File:Line | Issue |
|---|---|---|
| 🔴 Important | src/mcp/server/streamable_http_manager.py:99-106 |
Public handle_request() bypasses max_request_body_size, contradicting migration-doc claim |
| 🔴 Important | src/mcp/server/streamable_http_manager.py:395-409 |
Body-limit middleware caches one dict per ASGI message, allowing large memory amplification via tiny chunks |
Annotations
Check failure on line 106 in src/mcp/server/streamable_http_manager.py
claude / Claude Code Review
Public handle_request() bypasses max_request_body_size, contradicting migration-doc claim
The new `max_request_body_size` limit is enforced only through the new `manager.asgi_app` wrapper — `StreamableHTTPSessionManager.handle_request` remains a public, documented ASGI entry point with no size check, so existing code that mounts `handle_request` directly (as the SDK's own tests and, until this PR, `examples/stories/legacy_routing/README.md` do) silently gets no limit. That contradicts docs/migration.md's unconditional claim that "V2 applies a 4 MiB default limit" and the class docstr
Check failure on line 409 in src/mcp/server/streamable_http_manager.py
claude / Claude Code Review
Body-limit middleware caches one dict per ASGI message, allowing large memory amplification via tiny chunks
RequestBodyLimitMiddleware caps only the sum of body bytes but caches one ASGI message dict (~220 bytes of object overhead) per `http.request` message, so a client trickling a chunked POST in 1-byte segments can force ~4M cached dicts (~1 GB resident) per request before the default 4 MiB limit trips — a ~200x amplification of exactly the memory bound this PR adds. Coalescing the cached body chunks into a single `bytearray` and replaying one synthesized message would bound memory at `max_body_siz
Loading