Skip to content

Skip a stdio ping whose id cannot be encoded - #628

Merged
koic merged 1 commit into
modelcontextprotocol:mainfrom
koic:skip_a_stdio_ping_whose_id_cannot_be_encoded
Oct 22, 2026
Merged

koic merged 1 commit into
modelcontextprotocol:mainfrom
koic:skip_a_stdio_ping_whose_id_cannot_be_encoded

Conversation

@koic

@koic koic commented Oct 22, 2026

Copy link
Copy Markdown
Member

Motivation and Context

MCP::Client::Stdio answers a server's ping inline while it waits for a response, and it already skips a ping whose id is not a JSON-RPC id. A String id holding bytes that are not valid UTF-8 passed that check, and the pong echoing it failed in JSON.generate with JSON::GeneratorError. The pong's own rescue covers only a pong that cannot be written, so the error escaped and failed the unrelated request whose response the loop was reading.

Such a ping is now skipped like one with a malformed id, since a pong could not carry the id back.

A number such as 1e400 fails the same way: the parser reads it as an infinite Float, which JSON.generate refuses, so a ping carrying one is skipped as well. A String id that is not valid UTF-8 can arrive in a plain ASCII frame too: the json gem's 2.x releases decode a lone surrogate escape into one.

How Has This Been Tested?

test/mcp/client/stdio_test.rb: a ping whose id is not valid UTF-8 is not answerable, and one with a valid id still is. Against the previous library the first is answerable. A ping whose id is 1e400, sent ahead of the awaited response, is not answered and the request completes; against the previous library it raises JSON::GeneratorError.

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

## Motivation and Context

`MCP::Client::Stdio` answers a server's `ping` inline while it waits for a response, and it already skips a ping
whose id is not a JSON-RPC id. A String id holding bytes that are not valid UTF-8 passed that check, and the pong
echoing it failed in `JSON.generate` with `JSON::GeneratorError`. The pong's own rescue covers only a pong that
cannot be written, so the error escaped and failed the unrelated request whose response the loop was reading.

Such a ping is now skipped like one with a malformed id, since a pong could not carry the id back.

A number such as `1e400` fails the same way: the parser reads it as an infinite Float, which `JSON.generate`
refuses, so a ping carrying one is skipped as well. A String id that is not valid UTF-8 can arrive in
a plain ASCII frame too: the json gem's 2.x releases decode a lone surrogate escape into one.

## How Has This Been Tested?

`test/mcp/client/stdio_test.rb`: a ping whose id is not valid UTF-8 is not answerable, and one with a valid id
still is. Against the previous library the first is answerable.
A ping whose id is `1e400`, sent ahead of the awaited response, is not answered and the request completes;
against the previous library it raises `JSON::GeneratorError`.

## Breaking Changes

None.
@koic
koic merged commit 648c6ac into modelcontextprotocol:main Oct 22, 2026
11 checks passed
@koic
koic deleted the skip_a_stdio_ping_whose_id_cannot_be_encoded branch October 22, 2026 18:40
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