Skip to content

fix(client): count clean-EOF reconnects toward retry budget - #3415

Closed
mturac wants to merge 1 commit into
modelcontextprotocol:mainfrom
mturac:fix/issue-3307
Closed

fix(client): count clean-EOF reconnects toward retry budget#3415
mturac wants to merge 1 commit into
modelcontextprotocol:mainfrom
mturac:fix/issue-3307

Conversation

@mturac

@mturac mturac commented Aug 30, 2026

Copy link
Copy Markdown

Summary

Fixes #3307 — Streamable HTTP clean-EOF reconnections can exceed the request retry budget, causing infinite reconnection loops for long-lived listeners.

Root cause: _handle_reconnection recurses with attempt=0 on the clean-EOF path (stream closed after emitting only a priming event, no JSON-RPC response). The exception path correctly passes attempt + 1, but the normal EOF path resets the counter. A no-timeout caller such as subscriptions/listen can therefore reconnect indefinitely instead of resolving with CONNECTION_CLOSED after MAX_RECONNECTION_ATTEMPTS.

Fix: Pass attempt + 1 on both paths so clean EOFs and transport exceptions consume the same retry budget.

Changed files

  • src/mcp/client/streamable_http.py — pass attempt + 1 instead of 0 in the clean-EOF recursion of _handle_reconnection (+1 -1 line)
  • tests/client/test_streamable_http.py — add regression test test_clean_eof_without_response_counts_toward_reconnection_budget that verifies clean-EOF reconnections respect MAX_RECONNECTION_ATTEMPTS

Test plan

  • uv run --frozen pytest tests/client/test_streamable_http.py -q — 29/29 passed
  • uv run --frozen ruff check — all checks passed
  • uv run --frozen pyright — 0 errors

_handle_reconnection recurses with attempt=0 on the clean-EOF path
(stream closed after emitting only a priming event, no JSON-RPC
response). The exception path correctly passes attempt+1, but the
normal EOF path resets the counter. A no-timeout caller such as
subscriptions/listen can therefore reconnect indefinitely instead of
resolving with CONNECTION_CLOSED after MAX_RECONNECTION_ATTEMPTS.

Pass attempt+1 on both paths so clean EOFs and transport exceptions
consume the same budget.

Fixes modelcontextprotocol#3307
@github-actions github-actions Bot added the missing-issue-link Auto-closed: PR needs a linked issue assigned to its author (see CONTRIBUTING.md) label Aug 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

This PR has been closed automatically. This repo only keeps pull requests open when they come from a maintainer, or from a contributor a maintainer has assigned to the linked issue, and you aren't currently assigned to #3307.

If a maintainer assigns you to #3307, this PR reopens on its own and there's nothing more you need to do here. Assignment is a maintainer call based on capacity; comments that only ask to be assigned don't factor in. What does help is engaging on the issue itself by confirming the repro, explaining why it matters for your use case, or describing the approach you'd take.

You're welcome to keep pushing commits here (just avoid force-pushing, since GitHub can't reopen a rewritten branch), but that on its own won't get the PR reviewed or the issue assigned, and realistically most auto-closed PRs stay closed. There's no need to open a new PR either way.

CONTRIBUTING.md has the full reasoning, but in short:

  • We're a small team with very little capacity to review community PRs right now.
  • Many recent PRs are AI-generated with little human review, and reviewing one carefully still costs a maintainer as much time as it ever did. A well-described issue is usually more useful to us than the code.

Maintainers: reopen, remove missing-issue-link, or add bypass-issue-check to override.

@github-actions github-actions Bot closed this Aug 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

missing-issue-link Auto-closed: PR needs a linked issue assigned to its author (see CONTRIBUTING.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Streamable HTTP clean EOF reconnects can exceed the request retry budget

1 participant