Skip to content

[Server] stdio parse errors use id:"" instead of preserving the request id or returning null #333

@cclabadmin

Description

@cclabadmin

Describe the bug

When the stdio server receives JSON-RPC input that exceeds PHP's JSON nesting limit, it returns a JSON-RPC parse error with id:"".

That response is hard for clients to correlate with the original request. In the repro below, the malformed request had a numeric id such as 900512, but the server response used an empty-string id like:

{"jsonrpc":"2.0","id":"","error":{"code":-32700,"message":"Maximum stack depth exceeded"}}

The server process stayed alive and later ping requests succeeded, so this is not a crash report. The issue is the response id used for recoverable parse-error handling on stdio.

  • Environment:
    • Reproduced with stable release v0.5.0 (fb2c8c2ee4ab2791239c5f534bb07bfb7589d4e8)
    • Also reproduced with a main snapshot from 2026-05-26 (293a5880e44b36c2120b114d175b6ddc4d7d1b06)
    • Transport: stdio HTTP server

To Reproduce

Steps to reproduce the behavior:

  1. Start a PHP SDK MCP server over stdio. I used the discovery calculator example.
  2. Complete a normal initialize request followed by notifications/initialized.
  3. Send a JSON-RPC request with a numeric id and a deeply nested object value. The example below uses a nested initialize.params.capabilities object at depth 512.
  4. Observe the JSON-RPC error response id.

Expected behavior

For JSON-RPC errors, the response id should be the same as the request id when the id is known. If the id cannot be determined after a parse failure, JSON-RPC error responses conventionally use null for an unknown id. Returning id:"" introduces an id value that was not present in the request and is difficult for clients to correlate.

I would expect returing the parse error with id:null if the request id is not recoverable.

Logs

-> init payload depth=512:
   {"jsonrpc":"2.0","id":900512,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{... deeply nested object ...}}}

<- {"jsonrpc":"2.0","id":"","error":{"code":-32700,"message":"Maximum stack depth exceeded"}}

-> health after deep payload 512:
   {"jsonrpc":"2.0","id":7,"method":"ping","params":{}}

<- {"jsonrpc":"2.0","id":7,"result":{}}

The same id:"" parse-error behavior appeared for deeper inputs as well, including depths 1024, 2048, 4096, 8192, and 10000. The server process stayed alive.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions