Skip to content

Handler-generated HeaderMismatch responses use HTTP 200 instead of 400 #1225

Description

@lucarlig

Describe the bug

When a modern Streamable HTTP request reaches a ServerHandler and the handler returns ErrorData::header_mismatch(...), RMCP serializes the expected JSON-RPC HeaderMismatch error (-32020) but sends it with HTTP 200.

The modern response path derives the HTTP status through jsonrpc_http_status, which maps several protocol errors to HTTP 400 but currently falls through to HTTP 200 for ErrorCode::HEADER_MISMATCH. Transport-generated header validation errors do not show the bug because header_mismatch_jsonrpc_response constructs an HTTP 400 response directly.

To Reproduce

  1. Implement a ServerHandler request method that returns Err(ErrorData::header_mismatch("header does not match request parameter", None)).
  2. Send a valid modern Streamable HTTP JSON-RPC request using protocol version 2026-07-28, so the request reaches the handler.
  3. Observe an HTTP 200 response whose JSON-RPC body contains error code -32020.

Expected behavior

Handler-generated HeaderMismatch errors on the modern per-request path should use HTTP 400 while preserving JSON-RPC error code -32020, as required by the Streamable HTTP server-validation rules:

https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http#server-validation

Logs

actual:   HTTP 200, JSON-RPC error -32020
expected: HTTP 400, JSON-RPC error -32020

Additional context

The missing mapping is in:

https://github.com/modelcontextprotocol/rust-sdk/blob/main/crates/rmcp/src/transport/streamable_http_server/tower.rs

Related work such as #1083 covers mismatches detected by the transport before handler dispatch. This issue is specifically about HeaderMismatch returned by application handlers after dispatch.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High: significant functionality gap or spec violationT-bugBug fixes and error correctionsT-transportTransport layer changes

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions