Skip to content

fix(client): unblock streamable HTTP calls on early SSE close#3052

Draft
Sehlani042 wants to merge 1 commit into
modelcontextprotocol:mainfrom
Sehlani042:codex/streamable-http-call-tool-disconnect
Draft

fix(client): unblock streamable HTTP calls on early SSE close#3052
Sehlani042 wants to merge 1 commit into
modelcontextprotocol:mainfrom
Sehlani042:codex/streamable-http-call-tool-disconnect

Conversation

@Sehlani042

Copy link
Copy Markdown

Summary

Fixes a streamable HTTP client hang when a POST request receives an SSE response that closes before sending a JSON-RPC response.

This targets #1577. It overlaps with the older #1578, but keeps the current-main patch narrow: preserve the existing reconnect behavior when a resumable event id is available, and only resolve the pending request with the existing SDK CONNECTION_CLOSED error when there is no response and no resumable event to follow.

Root Cause

_handle_sse_response() consumed the POST SSE stream and returned silently if the stream ended before a response and no Last-Event-ID had been observed. Because no JSONRPCError or transport exception was written to the read stream, the JSON-RPC dispatcher kept the corresponding call_tool() waiter pending forever.

Changes

  • Send a correlated JSONRPCError(CONNECTION_CLOSED) when a POST SSE response closes before a reply and cannot be resumed.
  • Also resolve the pending request with CONNECTION_CLOSED if reconnection attempts are exhausted.
  • Add a non-SDK server regression test that closes an SSE response without a JSON-RPC reply and asserts call_tool() raises instead of hanging.

Validation

  • uv run --frozen pytest tests/client/test_notification_response.py::test_empty_post_sse_response_unblocks_pending_tool_call -q
  • uv run --frozen pytest tests/client/test_notification_response.py -q
  • uv run --frozen pytest tests/shared/test_streamable_http.py -q
  • uv run --frozen ruff format src/mcp/client/streamable_http.py tests/client/test_notification_response.py --check
  • uv run --frozen ruff check src/mcp/client/streamable_http.py tests/client/test_notification_response.py
  • uv run --frozen pyright src/mcp/client/streamable_http.py tests/client/test_notification_response.py
  • uv run --frozen coverage erase && uv run --frozen coverage run -m pytest tests/client/test_notification_response.py tests/shared/test_streamable_http.py && uv run --frozen coverage combine && uv run --frozen coverage report --include='src/mcp/client/streamable_http.py' --fail-under=0 && UV_FROZEN=1 uv run --frozen strict-no-cover

@Sehlani042 Sehlani042 force-pushed the codex/streamable-http-call-tool-disconnect branch from d988475 to 194f0dc Compare July 2, 2026 09:34
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.

1 participant