Skip to content

Stdio server leaves some malformed JSON-RPC requests unanswered while the session remains alive #976

@cclabadmin

Description

@cclabadmin

Describe the bug

Some malformed JSON-RPC requests sent over stdio receive no JSON-RPC error response even though the request carries an id and the server continues processing later requests.

The clearest case is an empty method name. After this request, the server gives no response for id=5, but later ping requests still succeed on the same stdio session. This looks like a recoverable request-dispatch path.

I am filing this as a conformance and robustness issue, not as a security issue. Malformed requests should be rejected, but requests with ids should receive a correlated JSON-RPC error response when the session can continue.

Environment tested:

  • Stable release: v1.6.1 (d454bbaf06a342aee5336df3370321d9cdec2478)
  • main snapshot from 2026-05-26: c044cdb734d8d321d596f5b6077072798dce4ad6
  • Server used: conformance/everything-server
  • Transport: stdio

To Reproduce

Steps to reproduce the behavior:

  1. Start the Go SDK stdio server.
  2. Complete a normal init handshake.
  3. Send this malformed request:
{"jsonrpc":"2.0","id":5,"method":"","params":{}}
  1. Observe that no response is returned for that request.
  2. Send later ping request and observe that the server still responds.

Expected behavior

For the primary case, I would expect a JSON-RPC error response for id=5, most likely -32601 Method not found or -32600 Invalid Request depending on how strictly the SDK wants to validate method names.

Reasoning:

  • JSON-RPC 2.0 requests include an id; notifications omit id and do not require a response.
  • method is a string in both JSON-RPC and MCP. If an empty method name is invalid at the MCP layer, this still looks like a recoverable request-dispatch error rather than a transport read failure, because the session continues.

Observed behavior

The primary repro case produced no JSON-RPC response for id=5, and a later ping health check succeeded on the same session.

Additional context

The same isolated test also found other malformed request cases. I am including them for completeness because they show the boundary between recoverable no-response behavior and connection-fatal behavior.

Case Request Observed behavior
id as null {"jsonrpc":"2.0","id":null,"method":"ping","params":{}} No JSON-RPC response for id=null; later ping requests still succeeded.
Wrong JSON-RPC version {"jsonrpc":"1.0","id":3,"method":"ping","params":{}} No JSON-RPC response; process exited with Server failed: invalid message version tag "1.0"; expected "2.0".
Missing jsonrpc field {"id":4,"method":"ping","params":{}} No JSON-RPC response; process exited with Server failed: invalid message version tag ""; expected "2.0".
method as number {"jsonrpc":"2.0","id":8,"method":12345,"params":{}} No JSON-RPC response; process exited with Server failed: unmarshaling jsonrpc message: json: cannot unmarshal ... into Go struct field ... method of type string.
  • The id:null case may be another recoverable MCP-level rejection case. JSON-RPC 2.0 treats id:null as distinct from an omitted id, although null ids are discouraged. MCP narrows request ids to string or number.

  • The other three cases are structurally invalid JSON-RPC envelopes: jsonrpc must be "2.0" and method must be a string. If the Go SDK intentionally treats these decoder/envelope failures as fatal stdio read errors, documenting that policy would help clients distinguish expected connection teardown from a lost response.

Related prior issue: #179 was closed in the v0.3.0 milestone and appears to cover a narrower malformed trailing-garbage case. The isolated cases above still reproduce on v1.6.1 and current main.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions