fix: drain accepted JSON-RPC requests after read EOF

Closed
MA
3mo ago
+129-7

Fixes #2678.

This changes the JSON-RPC dispatcher shutdown path so read EOF does not immediately cancel request handlers that were already accepted. The dispatcher now:

  • marks the connection closed and wakes outbound waiters after read EOF,
  • keeps the write stream open briefly for accepted inbound requests to finish their response writes,
  • bounds that drain window to avoid hanging shutdown,
  • tracks active inbound requests through the response write window, not just while they are present in _in_flight.

This targets stdio servers driven with redirected stdin, where EOF can arrive immediately after the last JSON-RPC request is read while an async tool call is still mid-await. In that case the response should be flushed to stdout before shutdown.

Validation:

  • python3 -m py_compile src/mcp/shared/jsonrpc_dispatcher.py tests/shared/test_jsonrpc_dispatcher.py passed on the patched files.
  • Added a dispatcher-level regression test that accepts a request, closes the read side, and asserts the response is still written.