Skip to content

Answer an HTTP request whose reply cannot be generated with Internal error - #629

Merged
koic merged 1 commit into
modelcontextprotocol:mainfrom
koic:answer_an_http_request_whose_reply_cannot_be_encoded
Oct 23, 2026
Merged

koic merged 1 commit into
modelcontextprotocol:mainfrom
koic:answer_an_http_request_whose_reply_cannot_be_encoded

Conversation

@koic

@koic koic commented Oct 22, 2026

Copy link
Copy Markdown
Member

Motivation and Context

A response can hold a string that is not valid UTF-8 when the request carried one and the SDK or a handler repeated it, for example a tool name in its Tool not found error, since the JSON parser passes such bytes in a string value through. Generating that response raised JSON::GeneratorError. On the Streamable HTTP legacy path the error escaped while the SSE body was being written, cutting the response off; in JSON response mode and on the 2026-07-28 path the transport's rescue answered 500 with the error reported, for a failure that belongs to the one request.

JsonRpcHandler.handle_json now answers such a request with -32603 Internal error carrying the request id, and the 2026-07-28 path does the same before it writes the response.

The error carries the request id when the response has one. In a batch each item that cannot be generated is replaced on its own, so the other items keep their results. The failure is passed to the exception reporter, since the Internal error sent to the client no longer shows what went wrong. Over stdio a batch is now answered by handle_json as well, with the request id, ahead of the transport's own fallback, which answered it without one.

How Has This Been Tested?

test/json_rpc_handler_test.rb and test/mcp/server/transports/streamable_http_transport_test.rb (the legacy SSE path, JSON response mode, and the 2026-07-28 path, each with a tool whose reply cannot be generated). Against the previous library the handler test raises JSON::GeneratorError, the SSE body raises it while it is written, and the other two answer 500.

The handler test for a batch in which one item cannot be generated fails against the previous library, which has no on_generate_error:. The transport tests check that the failure reaches the exception reporter. The stdio batch test expects the item's id accordingly.

Breaking Changes

None.

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

…error

## Motivation and Context

A response can hold a string that is not valid UTF-8 when the request carried one and the SDK or a handler
repeated it, for example a tool name in its `Tool not found` error, since the JSON parser passes such bytes in
a string value through. Generating that response raised `JSON::GeneratorError`. On the Streamable HTTP legacy
path the error escaped while the SSE body was being written, cutting the response off; in JSON response mode
and on the 2026-07-28 path the transport's rescue answered 500 with the error reported, for a failure that
belongs to the one request.

`JsonRpcHandler.handle_json` now answers such a request with `-32603` Internal error carrying the request id, and
the 2026-07-28 path does the same before it writes the response.

The error carries the request id when the response has one. In a batch each item that cannot be generated is
replaced on its own, so the other items keep their results. The failure is passed to the exception reporter,
since the Internal error sent to the client no longer shows what went wrong.
Over stdio a batch is now answered by `handle_json` as well, with the request id, ahead of the transport's own
fallback, which answered it without one.

## How Has This Been Tested?

`test/json_rpc_handler_test.rb` and `test/mcp/server/transports/streamable_http_transport_test.rb` (the legacy
SSE path, JSON response mode, and the 2026-07-28 path, each with a tool whose reply cannot be generated).
Against the previous library the handler test raises `JSON::GeneratorError`, the SSE body raises it while it is
written, and the other two answer 500.

The handler test for a batch in which one item cannot be generated fails against the previous library, which
has no `on_generate_error:`. The transport tests check that the failure reaches the exception reporter.
The stdio batch test expects the item's id accordingly.

## Breaking Changes

None.
@koic
koic merged commit 37270d6 into modelcontextprotocol:main Oct 23, 2026
11 checks passed
@koic
koic deleted the answer_an_http_request_whose_reply_cannot_be_encoded branch October 23, 2026 21:48
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.

2 participants