Skip to content

Handler-generated invalid params errors use HTTP 400 on the modern Streamable HTTP path #1320

Description

@DaleSeo

Describe the bug

On the modern (2026-07-28) Streamable HTTP path, jsonrpc_http_status maps every ErrorCode::INVALID_PARAMS (-32602) response to HTTP 400. This includes ordinary application errors that the spec defines as -32602 and that are not transport validation failures:

The 2026-07-28 Streamable HTTP spec requires HTTP 400 only for HeaderMismatch, UnsupportedProtocolVersionError, and MissingRequiredClientCapabilityError, and HTTP 404 for -32601. Its backward-compatibility rules tell a client that receives HTTP 400 to inspect the body and fall back to initialize when it is not one of those recognized modern errors. A spec-compliant client could therefore treat a 400 carrying a "resource not found" -32602 as a legacy server and downgrade.

To Reproduce

  1. Implement a ServerHandler whose read_resource returns Err(ErrorData::resource_not_found(...)) (or ErrorData::invalid_params(...) from get_prompt / call_tool).
  2. Send a valid modern Streamable HTTP request with protocol version 2026-07-28 that reaches the handler.
  3. Observe HTTP 400 with a JSON-RPC body containing error code -32602.

Expected behavior

Handler-generated -32602 errors should be sent with HTTP 200 as in-band JSON-RPC errors, like other handler errors that jsonrpc_http_status does not map.

Logs

actual:   HTTP 400, JSON-RPC error -32602 "Resource not found for URI: ui://widget/nope"
expected: HTTP 200, JSON-RPC error -32602

Found with rmcp 3.5.0 by MCPJam's modern-resource-not-found-invalid-params check (@mcpjam/sdk 8.20.1, profile mcp-protocol@2026-08-21.1), which expects an in-band error. The official conformance suite (0.2.0-alpha.11) does not check the status code for this case.

Additional context

The mapping is in jsonrpc_http_status:

https://github.com/modelcontextprotocol/rust-sdk/blob/8f9a28ecdb5f/crates/rmcp/src/transport/streamable_http_server/tower.rs#L646-L660

Transport-generated malformed-request errors, such as a missing protocolVersion in _meta, already build their HTTP 400 response directly in invalid_params_jsonrpc_response, so removing INVALID_PARAMS from this mapper should not change those responses.

#1303 is related. It makes malformed params for spec methods return -32602 instead of -32601, which fixes the 404, but with the current mapper those responses become HTTP 400.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P1High: significant functionality gap or spec violationT-transportTransport layer changesbugSomething is not workingready for workIssue is well-defined and ready to be picked up

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions