Repository navigation
Commit 9416795
committed
Reject server messages that are not JSON-RPC 2.0 in the client transports
## Motivation and Context
Issue #589 reports that `MCP::Client#call_tool` returns normally when the server's response omits `jsonrpc` or
sets it to `"1.0"`. The bundled transports never read that member of an incoming message, while the server side of
this SDK answers `-32600` to such a request and the TypeScript, Python, Go, and C# SDKs validate every incoming message
against a schema whose `jsonrpc` is the literal `"2.0"`.
`MCP::Client::Stdio` and `MCP::Client::HTTP` now check it. A response that is not a JSON object carrying
`"jsonrpc": "2.0"` fails the request with `RequestHandlerError` instead of being returned: over stdio the frame answering
the awaited id, over HTTP the JSON body or the first response-shaped SSE event, on a resumed stream as well.
Over HTTP that is what the Python client does with the answer to a request, and the TypeScript client with a JSON body.
Over stdio both of them report the message as an error and keep reading; this transport reads synchronously and
its `read_timeout` defaults to none, so reading on would wait forever, and the request fails at once instead.
A server-to-client request that is not JSON-RPC 2.0 is ignored: a `ping` is not answered and a handler is not called.
Frames for other ids keep being skipped, the body answering a notification is not checked, and under `mode: :auto`
a rejected `server/discover` answer falls back to the legacy handshake like any other probe failure.
An empty or `null` JSON body of a 200 is still handed over as `nil`, as before.
The check lives in the transports, not in `MCP::Client#request`, so a custom transport keeps handing over
whatever Hash it builds.
The HTTP client tests stubbed most JSON bodies as `{ result: ... }` without the member, which the transport now rejects,
so those 54 stubs and three whole-response assertions carry `jsonrpc: "2.0"`.
Closes #589.
## How Has This Been Tested?
test/mcp/client/stdio_test.rb and test/mcp/client/http_test.rb. Against the library before this change,
20 of the 22 new tests fail; the other two pin behavior that stays the same.
## Breaking Changes
A server whose responses lack `"jsonrpc": "2.0"` no longer works with the bundled transports, and neither does
a test that stubs such a response for them: the member has to be sent, and there is no opt-out. Servers built
with an MCP SDK send it already, and `MCP::Client` over a custom transport or a test double is unaffected.1 parent d4202c2 commit 9416795
5 files changed
Lines changed: 625 additions & 62 deletions
File tree
- docs/_client
- lib/mcp/client
- test/mcp/client
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
13 | 18 | | |
14 | 19 | | |
15 | 20 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
202 | 202 | | |
203 | 203 | | |
204 | 204 | | |
205 | | - | |
206 | | - | |
207 | | - | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
208 | 209 | | |
209 | 210 | | |
210 | 211 | | |
| |||
426 | 427 | | |
427 | 428 | | |
428 | 429 | | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
429 | 434 | | |
430 | 435 | | |
431 | 436 | | |
| |||
1172 | 1177 | | |
1173 | 1178 | | |
1174 | 1179 | | |
| 1180 | + | |
| 1181 | + | |
| 1182 | + | |
| 1183 | + | |
| 1184 | + | |
| 1185 | + | |
| 1186 | + | |
| 1187 | + | |
| 1188 | + | |
| 1189 | + | |
| 1190 | + | |
| 1191 | + | |
| 1192 | + | |
| 1193 | + | |
1175 | 1194 | | |
1176 | 1195 | | |
1177 | 1196 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
442 | 442 | | |
443 | 443 | | |
444 | 444 | | |
445 | | - | |
446 | | - | |
447 | | - | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
448 | 448 | | |
449 | 449 | | |
450 | 450 | | |
451 | 451 | | |
452 | 452 | | |
453 | 453 | | |
| 454 | + | |
454 | 455 | | |
455 | | - | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
456 | 461 | | |
457 | 462 | | |
458 | 463 | | |
| |||
475 | 480 | | |
476 | 481 | | |
477 | 482 | | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
478 | 487 | | |
479 | 488 | | |
480 | 489 | | |
| |||
532 | 541 | | |
533 | 542 | | |
534 | 543 | | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
535 | 554 | | |
536 | 555 | | |
537 | 556 | | |
0 commit comments