Skip to content

Use JSON-RPC error envelope for StreamableHTTPTransport errors#371

Open
koic wants to merge 1 commit into
modelcontextprotocol:mainfrom
koic:use_json_rpc_envelope_for_transport_errors
Open

Use JSON-RPC error envelope for StreamableHTTPTransport errors#371
koic wants to merge 1 commit into
modelcontextprotocol:mainfrom
koic:use_json_rpc_envelope_for_transport_errors

Conversation

@koic
Copy link
Copy Markdown
Member

@koic koic commented Jun 4, 2026

Motivation and Context

PR #347 introduced a single JSON-RPC error envelope response for unsupported MCP-Protocol-Version headers, while the rest of the transport-level error responses (Accept, Content-Type, Invalid JSON, session management, method not allowed, internal server error) still returned plain JSON of the form { "error": "..." }. The Python SDK (src/mcp/server/streamable_http.py) and TypeScript SDK (packages/server/src/server/streamableHttp.ts) consistently use a JSON-RPC error envelope for all transport-level errors. Unify the Ruby SDK with them.

Behavior

All transport-level error responses now return a JSON-RPC error envelope:

{
  "jsonrpc": "2.0",
  "id": null,
  "error": {
    "code": -32600,
    "message": "..."
  }
}

Affected helpers in lib/mcp/server/transports/streamable_http_transport.rb:

  • validate_content_type (HTTP 415)
  • not_acceptable_response (HTTP 406)
  • parse_request_body error (HTTP 400, PARSE_ERROR -32700)
  • method_not_allowed_response (HTTP 405)
  • missing_session_id_response (HTTP 400)
  • session_not_found_response (HTTP 404)
  • session_already_connected_response (HTTP 409)
  • Internal server error fallback in handle_post (HTTP 500, INTERNAL_ERROR -32603)
  • validate_protocol_version_header (HTTP 400, dedup with shared helper)

A new private helper json_rpc_error_response(status:, code:, message:) centralizes the envelope construction.

The "Invalid JSON" message wording is updated to "Parse error: Invalid JSON" to match the JSON-RPC 2.0 PARSE_ERROR semantics.

How Has This Been Tested?

Updated all affected tests in test/mcp/server/transports/streamable_http_transport_test.rb to assert the new envelope shape (body["error"]["message"] instead of body["error"]).

Breaking Changes

Clients that parsed the previous plain {"error": "..."} shape will need to read body["error"]["message"] (or body["error"]["code"]). The HTTP status codes are unchanged, only the response body structure changed.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

## Motivation and Context

PR modelcontextprotocol#347 introduced a single JSON-RPC error envelope response for
unsupported `MCP-Protocol-Version` headers, while the rest of the
transport-level error responses (Accept, Content-Type, Invalid JSON,
session management, method not allowed, internal server error) still
returned plain JSON of the form `{ "error": "..." }`. The Python SDK
(`src/mcp/server/streamable_http.py`) and TypeScript SDK
(`packages/server/src/server/streamableHttp.ts`) consistently use
a JSON-RPC error envelope for all transport-level errors.
Unify the Ruby SDK with them.

## Behavior

All transport-level error responses now return a JSON-RPC error envelope:

```json
{
  "jsonrpc": "2.0",
  "id": null,
  "error": {
    "code": -32600,
    "message": "..."
  }
}
```

Affected helpers in `lib/mcp/server/transports/streamable_http_transport.rb`:

- `validate_content_type` (HTTP 415)
- `not_acceptable_response` (HTTP 406)
- `parse_request_body` error (HTTP 400, `PARSE_ERROR` `-32700`)
- `method_not_allowed_response` (HTTP 405)
- `missing_session_id_response` (HTTP 400)
- `session_not_found_response` (HTTP 404)
- `session_already_connected_response` (HTTP 409)
- Internal server error fallback in `handle_post` (HTTP 500, `INTERNAL_ERROR` `-32603`)
- `validate_protocol_version_header` (HTTP 400, dedup with shared helper)

A new private helper `json_rpc_error_response(status:, code:, message:)`
centralizes the envelope construction.

The "Invalid JSON" message wording is updated to "Parse error: Invalid JSON"
to match the JSON-RPC 2.0 `PARSE_ERROR` semantics.

## How Has This Been Tested?

Updated all affected tests in `test/mcp/server/transports/streamable_http_transport_test.rb` to
assert the new envelope shape (`body["error"]["message"]` instead of `body["error"]`).

## Breaking Changes

Clients that parsed the previous plain `{"error": "..."}` shape will need to read
`body["error"]["message"]` (or `body["error"]["code"]`).
The HTTP status codes are unchanged, only the response body structure changed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant