Skip to content

fix: send JSONRPCError instead of bare exceptions in streamable HTTP client#2005

Open
Kludex wants to merge 4 commits intomainfrom
fix/streamable-http-jsonrpc-errors
Open

fix: send JSONRPCError instead of bare exceptions in streamable HTTP client#2005
Kludex wants to merge 4 commits intomainfrom
fix/streamable-http-jsonrpc-errors

Conversation

@Kludex
Copy link
Member

@Kludex Kludex commented Feb 7, 2026

Summary

Test plan

  • test_unexpected_content_type_sends_jsonrpc_error — server returns text/plain, client gets MCPError immediately (no timeout)
  • test_invalid_json_response_sends_jsonrpc_error — server returns invalid JSON body, client gets MCPError immediately
  • uv run --frozen ruff check passes
  • uv run --frozen pyright passes

…client

When the streamable HTTP client encountered errors (unexpected content type,
JSON parse failure, SSE parse failure), it sent bare Exception objects that
never resolved the pending send_request() — causing the caller to hang
indefinitely until timeout.

Send JSONRPCError with the request's id so the response stream unblocks
immediately, following the pattern already used by the 404 handler.
@claude
Copy link

claude bot commented Feb 7, 2026

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a hang in the Streamable HTTP client by ensuring transport-layer failures (unexpected Content-Type, JSON parse errors, SSE parse errors) are surfaced to the session as JSONRPCError responses tied to the original request id, allowing send_request() to resolve immediately instead of waiting for a timeout.

Changes:

  • Emit JSONRPCError (with request id) for unexpected response Content-Type and JSON body parse failures in the Streamable HTTP client.
  • Emit JSONRPCError (with request id) when an SSE message event can’t be parsed, unblocking the pending request.
  • Add tests covering unexpected content types and invalid JSON responses for non-SDK servers.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
src/mcp/client/streamable_http.py Converts previously “bare exception sent to stream” cases into JSONRPCError responses keyed by request id.
src/mcp/types/jsonrpc.py Aligns JSONRPCError.id typing with RequestId.
tests/client/test_notification_response.py Reworks test server setup to ASGITransport and adds regression tests for immediate MCPError on bad responses.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

@felixweinberger felixweinberger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fix!

nit: no test for the SSE parse failure path (lines 167-175), though it's pragma: no cover and follows the same pattern as the two tested paths. Not blocking.

looks like CI failures are just about coverage checks. ready to stamp once that's fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cannot handle Unexpected content type when initializing MCP session streamable_http client call_tool hangs when receiving invalid JSONRPCMessage

2 participants