You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Streamable HTTP: malformed requests return raw pydantic errors to the client #3698
When the Streamable HTTP POST handler rejects a malformed body, it returns the raw exception text to the client (streamable_http.py L580-L596):
No "jsonrpc" field → "Validation error: 6 validation errors for union[JSONRPCRequest,...] ... input_value={...} ... https://errors.pydantic.dev/2.14/v/missing"
Not JSON → "Parse error: EOF while parsing a value at line 1 column 27"
A security audit of our MCP server flagged this: the errors reveal that the backend is Python, using pydantic (down to the exact version) and the MCP Python SDK, which helps an attacker enumerate the environment.
Expected: fixed messages (Parse error, Invalid JSON-RPC message), with detail in the server log only. The 2026-07-28 path already does this (_streamable_http_modern.py L415).
The same code is on v1.x, which we run. I’d like to fix both if assigned: a few lines plus tests, with no new API.
Related: #3557 (error code on these lines), #3572 (same pydantic text in tool-argument errors).
Disclosure: this issue was drafte by Claude Code and reviewed/iterated by myself and another senior developer. I ran the reproduction and verified the output myself.
streamable_http.py still interpolates the exception at L583 (f"Parse error: {str(e)}") and L591 (f"Validation error: {str(e)}"), same on v1.x at L537 and L545.
JSON-RPC 2.0 supports dropping the detail too: the message "SHOULD be limited to a concise single sentence", and data "may be omitted". https://www.jsonrpc.org/specification
A local in-process reproduction confirms the response-body leak on 2af9e3089ac66b35c1550c500aae86a82efb1e17 (Python 3.14.6, Pydantic 2.12.5, protocol header 2025-06-18). A missing jsonrpc field returns HTTP 400 with Validation error: 6 validation errors for union[...], including input values and Pydantic diagnostic links. Truncated JSON also includes parser details.
There is a small test-only patch strengthening the two existing HTTP validation tests: five malformed bodies in both JSON and SSE response modes. It asserts the full JSON-RPC error envelope with the issue's requested Parse error / Invalid JSON-RPC message text and no diagnostic data fields. On the unchanged SDK, all ten cases fail at the public-message assertion, while the other 71 tests in that file pass; two runs give the same result. A temporary local sanitization/logging demo makes all 81 pass, but is not included in the proposed test diff. This does not establish that an upstream fix has landed.
As the issue distinguishes, #3557 concerns error-code selection and #3572 concerns tool-argument errors. This patch leaves the current codes unchanged and does not cover tool arguments or claim v1.x validation.
Would sharing the test-only patch with the reporter, or a coordinated test-only PR if useful and permitted by the contribution gate, help? The reporter has already offered to implement the fix; this is not a competing implementation. Are those exact messages and omitted error.data the intended contract? Should the tests also require server-side exception logging, or leave log shape/level and input redaction to a separate decision?
AI disclosure: OpenCode generated the reproduction, tests, and this draft, and executed the local checks described above.
Activity
sattyamjjain commentedon Oct 17, 2026
There is a precedent in the same SDK for the fix you describe. The legacy SSE transport logs the detail and returns a fixed message: sse.py L273-276 at 9f66f37 does
logger.exception("Failed to parse message")thenResponse("Could not parse message", status_code=400). The modern transport also already uses a fixedmessage=" Parse error"(_streamable_http_modern.py L415).https://github.com/modelcontextprotocol/python-sdk/blob/9f66f376d486e84e9810b368cf8be9d5908661ab/src/mcp/server/sse.py
streamable_http.py still interpolates the exception at L583 (
f"Parse error: {str(e)}") and L591 (f"Validation error: {str(e)}"), same on v1.x at L537 and L545.JSON-RPC 2.0 supports dropping the detail too: the message "SHOULD be limited to a concise single sentence", and
data"may be omitted".https://www.jsonrpc.org/specification
EngineeringWithJay commentedon Oct 17, 2026
A local in-process reproduction confirms the response-body leak on
2af9e3089ac66b35c1550c500aae86a82efb1e17(Python 3.14.6, Pydantic 2.12.5, protocol header2025-06-18). A missingjsonrpcfield returns HTTP 400 withValidation error: 6 validation errors for union[...], including input values and Pydantic diagnostic links. Truncated JSON also includes parser details.There is a small test-only patch strengthening the two existing HTTP validation tests: five malformed bodies in both JSON and SSE response modes. It asserts the full JSON-RPC error envelope with the issue's requested
Parse error/Invalid JSON-RPC messagetext and no diagnostic data fields. On the unchanged SDK, all ten cases fail at the public-message assertion, while the other 71 tests in that file pass; two runs give the same result. A temporary local sanitization/logging demo makes all 81 pass, but is not included in the proposed test diff. This does not establish that an upstream fix has landed.As the issue distinguishes, #3557 concerns error-code selection and #3572 concerns tool-argument errors. This patch leaves the current codes unchanged and does not cover tool arguments or claim v1.x validation.
Would sharing the test-only patch with the reporter, or a coordinated test-only PR if useful and permitted by the contribution gate, help? The reporter has already offered to implement the fix; this is not a competing implementation. Are those exact messages and omitted
error.datathe intended contract? Should the tests also require server-side exception logging, or leave log shape/level and input redaction to a separate decision?AI disclosure: OpenCode generated the reproduction, tests, and this draft, and executed the local checks described above.