Repository navigation
Stdio client stops processing responses after rejecting a malformed response #1157
Description
Bug description
The stdio client stops processing responses after receiving either of these malformed JSON-RPC responses:
- A response without
jsonrpc - A response containing both
resultanderror
The SDK logs a validation error, but the affected tool call does not fail immediately. It times out, and a subsequent ping on the same client also times out.
I reproduced both cases three times with SDK 2.0.1. Streamable HTTP rejected the same responses and continued processing requests normally.
This is separate from #1156, where a response with "jsonrpc": "1.0" is accepted.
Environment
- MCP Java SDK: 2.0.1
- Java: 21.0.9
- Maven: 3.9.11
- Protocol version: 2025-11-25
- Client: Synchronous
- Transport: stdio
- Server:
mcp-failure-lab@0.11.0 - OS: Linux arm64 container
- Spring AI: Not used
- Vector store: Not applicable
Steps to reproduce
- Initialize a synchronous Java SDK client over stdio.
- Send a tool request.
- Return a response with the matching request ID that either:
- omits
jsonrpc, or - contains both
resultanderror.
- omits
- Observe that the tool call times out.
- Call
pingon the same client. - Observe that
pingalso times out.
For the missing jsonrpc case, the client logs:
Cannot construct instance of io.modelcontextprotocol.spec.McpSchema$JSONRPCResponse:
jsonrpc must not be empty
For the response containing both fields, it logs:
Cannot construct instance of io.modelcontextprotocol.spec.McpSchema$JSONRPCResponse:
MCP responses MUST either have a result or error
Expected behavior
The malformed response should fail its matching request without stopping the stdio client from processing later messages. A subsequent ping should complete normally.
Minimal Complete Reproducible example
The pinned test harness is here:
http://github.com/anilloutombam/mcp-failure-lab/tree/main/experiments/java-sdk
Run it with:
git clone http://github.com/anilloutombam/mcp-failure-lab.git
cd mcp-failure-lab
docker build -t mcp-failure-lab-java-sdk ./experiments/java-sdk
mkdir -p work/java-sdk-results
docker run --rm \
-v "$PWD/work/java-sdk-results:/results" \
mcp-failure-lab-java-sdkThe relevant cases are:
missing-jsonrpc-recoveryresult-with-error-recovery
Test code:
Full results:
http://github.com/anilloutombam/mcp-failure-lab/blob/main/docs/compatibility/java-sdk-2.0.1.md
Activity
hpdkhoa commentedon Oct 2, 2026
I have a fix for this and will open a PR. Here is the scope so you can redirect me before review.
The change is in StdioClientTransport only. A message that fails to deserialize no longer ends the inbound loop. If the line is a response with a usable id, the transport emits a JSON-RPC error response for that id, so the matching request fails at once and no longer waits for its timeout. A line that is not JSON is logged and skipped. Later messages are still read.
Two choices I would like your view on:
The test starts a server process that sends a response without jsonrpc, a response with both result and error, a line that is not JSON, and then a valid response. It checks that the two malformed responses fail their requests and the valid one still arrives. All mcp-core tests pass locally. I did not run the Docker and npx based suites.