Skip to content

Expose an SSE event size limit in Streamable HTTP clients - #3600

Merged
Kludex merged 5 commits into
mainfrom
codex/add-sse-event-size
Oct 1, 2026
Merged

Kludex merged 5 commits into
mainfrom
codex/add-sse-event-size

Conversation

@Kludex

@Kludex Kludex commented Sep 30, 2026 •

Copy link
Copy Markdown
Member

Fixes #3332

Motivation and Context

httpx2 limits each SSE event to 1 MiB by default, which rejects larger MCP tool results. Expose max_sse_event_size on streamable_http_client and StreamableHttpParameters while preserving the 1 MiB default. Callers can raise the limit or pass None to disable it. The setting applies to POST responses, GET streams, resumption, and reconnection. Oversized request events return a clear error; the background GET stream retries after a failed event.

This requires httpx2>=2.10.0. JSON responses and the legacy SSE transport are unchanged.

How Has This Been Tested?

  • ./scripts/test: 5983 passed, 9 skipped, 1 xfailed; 100% coverage and strict-no-cover passed.
  • uv run --frozen ruff check ., uv run --frozen ruff format --check ., uv run --frozen pyright, and uv lock --check --offline passed.

Breaking Changes

None. The existing 1 MiB SSE event default remains.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Documentation update

Checklist

  • I am assigned to the linked issue
  • I have disclosed AI assistance and can explain the change in my own words
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

AI Disclaimer

This PR was developed with the assistance of either Claude or Codex. I've reviewed and verified the changes.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@github-actions

github-actions Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

📚 Documentation preview

Preview https://pr-3600.mcp-python-docs.pages.dev
Deployment https://e7efd894.mcp-python-docs.pages.dev
Commit 0829741
Triggered by @Kludex
Updated 2026-10-01 13:57:18 UTC

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

All reported issues were addressed across 11 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread docs/client/transports.md Outdated
Comment thread tests/client/test_streamable_http.py Outdated

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One optional note from this repository's REVIEW.md or CLAUDE.md checks was not posted as a comment, over this review's limit for such notes; it is on this commit's check card.

Findings marked 🟡 are optional suggestions and need no follow-up push.

Comment thread src/mcp/client/streamable_http.py Outdated
Comment thread src/mcp/client/streamable_http.py Outdated
Comment thread tests/client/test_streamable_http.py Outdated
Comment thread tests/client/test_streamable_http.py Outdated
Comment thread src/mcp/client/streamable_http.py
Comment thread src/mcp/shared/_httpx_utils.py

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nothing blocking. The comments below are optional suggestions. There is no need to push a fix for them before merging.

Thanks for the follow-up commit: re-reading the current code, the GET stream now falls through to the existing reconnect loop on an oversized event, the reconnect path only fails the request when the reply is actually text/event-stream (both branches have tests), and the three error assertions now check only the SDK-authored prefix. Beyond the inline nit, I also checked that the httpx2>=2.10.0 floor matches the version already pinned in uv.lock, so the lowest-direct matrix resolves the same release the lock already tests.

Extended reasoning...

The PR adds a keyword-only max_sse_event_size to StreamableHTTPTransport, streamable_http_client, sse_within_origin and StreamableHttpParameters, threads it into every EventSource construction in src/mcp/client/streamable_http.py, adds SSEError handling on the POST, resumption and reconnection paths, raises the httpx2 floor to 2.10.0, and adds docs plus nine behaviour tests. It touches no auth, crypto or injection surface; the sensitive part is the client's stream-recovery logic, which the second commit reworked in response to the earlier review. A verified test-quality nit is posted inline and the change alters public API signatures and a dependency floor, both maintainer design decisions, so a human look is still warranted rather than approval.

Still open from earlier reviews (2):

  • Unresolved: 2 minor or pre-existing.

Comment thread tests/client/test_streamable_http.py

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

All reported issues were addressed across 3 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread tests/client/test_streamable_http.py

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I re-reviewed the latest push and found no new bugs; the points I raised earlier are addressed in the code (GET-stream errors now fall through to reconnection, the reconnect path checks the content type before failing the request, and the tests assert only the SDK-owned prefix). A human look is still worthwhile because this changes the transport's error and reconnection behaviour and raises a dependency floor.

What was reviewed:

  • The four SSE reader sites in src/mcp/client/streamable_http.py (POST SSE, GET stream, resumption, reconnection) and the is_sse_response sniff at :570-571 — the recursive _handle_reconnection call stays bounded by attempt + 1 and the nested call has its own handlers, so the new except httpx2.SSEError cannot loop.
  • The PR description still says the default is 16 MiB (and lists that as a behaviour change), but after "Preserve the 1 MiB SSE event default" the code, docs and docs/migration.md all say 1 MiB — worth updating the description before merge.
  • The httpx2>=2.10.0 floor: uv.lock already resolved 2.10.0 before this PR, but I could not confirm from this checkout that 2.10.0 is the first release with EventSource(max_event_size=...), so a maintainer should check that against the dependency policy.
Extended reasoning...

The change adds a max_sse_event_size knob to StreamableHTTPTransport, streamable_http_client and StreamableHttpParameters, threads it through every EventSource construction, adds httpx2.SSEError handling on the POST-SSE, resumption and reconnection paths, raises the httpx2 floor to 2.10.0, and adds docs plus nine tests. It touches no auth, crypto or injection surface; the sensitive part is transport reliability (which requests get resolved with CONNECTION_CLOSED versus retried). All of my earlier inline findings are addressed by commits d3d0ff4 and 3e831d6, but there are unresolved cubic-dev-ai inline threads (docs/client/transports.md:59 and tests/client/test_streamable_http.py:119) with no independent resolution, the PR description is stale about the default, and the dependency-floor claim could not be verified here, so I deferred rather than approved.

Still open from earlier reviews (3):

  • Unresolved: 3 minor or pre-existing.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I re-reviewed the latest push and found no bugs; the points raised in my earlier reviews are now handled in the code, and a human look is still worthwhile because this changes transport reconnection behaviour and raises a dependency floor.

What was reviewed:

  • handle_get_stream now lets an oversized event fall through to the reconnect loop, and _handle_reconnection only resolves the request on an SSEError when the reply was actually text/event-stream; both paths have tests with retry: 0 priming so no wall-clock sleeps.
  • The three error-message assertions now check only the SDK's "SSE stream failed: " prefix with a comment that httpx2 owns the remainder; the raw-peer tests state why the typed server cannot produce the scenario.
  • max_sse_event_size is validated and threaded to all four EventSource sites; StreamableHttpParameters mirrors it with gt=0; uv.lock pins httpx2==2.10.0 matching the new floor. I could not independently confirm 2.10.0 is the first release exposing EventSource(max_event_size=), and docs/migration.md gets a one-line signature update to an existing entry — a maintainer may want to confirm both are acceptable.
Extended reasoning...

The diff adds a configurable per-event SSE byte cap to the Streamable HTTP client (src/mcp/client/streamable_http.py, src/mcp/shared/_httpx_utils.py, src/mcp/client/session_group.py), raises the httpx2 floor from 2.5.0 to 2.10.0 in pyproject.toml/uv.lock, updates docs/client/transports.md, docs/migration.md and a new docs_src tutorial, and adds roughly 320 lines of tests. It touches no auth, crypto or injection surface; the new logic lives in SSE error handling for POST, GET, resumption and reconnection streams. Approval was not chosen because the reconnection changes are behavioural rather than mechanical, the dependency-floor justification could not be verified from this checkout, migration.md is a file AGENTS.md treats as closed to new entries, and two cubic-dev-ai inline threads remain unresolved in the metadata (though later commits followed them). The bug hunt exited on dry_streak with no findings, and every item from the prior three reviews is addressed in the current code.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code review found no issues

No high-confidence issues detected in this change.

@maxisbey maxisbey left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

approved with one non blocking comment

Comment thread pyproject.toml
@Kludex
Kludex merged commit 7fdc944 into main Oct 1, 2026
42 checks passed
@Kludex
Kludex deleted the codex/add-sse-event-size branch October 1, 2026 14:00
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.

[v2] Expose the SSE max_event_size setting in Streamable HTTP clients

2 participants