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
christianclaudio added a commit to christianclaudio/mcp-server-snowflake that referenced this pull request Oct 10, 2026
## Why

Template v1.7.0 (#82) raised the FastMCP floor to 4.1.0 and mcp to 2.3.0. This copies both floors here so the product matches the template. Nothing in `src/` or `tests/` needed to change.

## Changes

- `pyproject.toml` (core), `fastmcp.json`: `fastmcp>=4.0.11` becomes `>=4.1.0` and `mcp>=2.2.0` becomes `>=2.3.0`.
- `uv.lock`: refreshed with `uv lock --upgrade-package fastmcp --upgrade-package mcp` only. No other package was upgraded.
- `README.md`: the template's idle-session line, added as a bullet under "Known limits" in the Streamable HTTP section, because this README documents serving Streamable HTTP in the default stateful mode.

No source or test changes. No version bump.

## Audit (src, tests, docs, README)

- Tool Search ([#5467](PrefectHQ/fastmcp#5467)): `RegexSearchTransform()` is opt-in (`--enable-tool-search`, `src/snowflake_mcp/server.py:377`); the tests only list `search_tools`/`call_tool` and pass no pattern. A client sending a lookaround or backreference now gets an empty result instead of an error. The lookarounds and backreferences in `errors.py` belong to the redaction patterns. Python's `re` compiles them, not Tool Search, so they are unaffected.
- Code Mode: No Code Mode in this repo; no `CodeMode(` or `max_duration_secs`.
- HTTP idle expiry ([#5229](PrefectHQ/fastmcp#5229)): `session_idle_timeout` is not set anywhere, so stateful HTTP deployments now expire sessions after 30 idle minutes (HTTP 404, and the client starts a new session). The HTTP tests build stateless apps, and the `stateless_http=False` assertions only check the arguments passed to `run()`, so the tests are unaffected. The README line documents this.
- No `x-mcp-header` annotations ([#3620](modelcontextprotocol/python-sdk#3620)), no `ctx.meta` / `ctx.params` reads ([#3628](modelcontextprotocol/python-sdk#3628)), no `MultiAuth`, no skills, and no OpenAPI `.`/`..` path parameters.

## FastMCP 4.1.0 ([release](https://github.com/PrefectHQ/fastmcp/releases/tag/v4.1.0)) and mcp 2.3.0 ([release](https://github.com/modelcontextprotocol/python-sdk/releases/tag/v2.3.0))

The items that apply here are the Tool Search engine change, the 30-minute idle expiry and the Monty 1.1 rename above. The other breaking items in 4.1.0 (MultiAuth client IDs, skill file paths, OpenAPI path parameters, Python 3.15) touch nothing used here. In mcp 2.3.0, `httpx2>=2.10.0` ([#3600](modelcontextprotocol/python-sdk#3600)) was already satisfied. [#3630](modelcontextprotocol/python-sdk#3630) (`Mcp-Param-*` lookup by name) and [#3635](modelcontextprotocol/python-sdk#3635) (OAuth login vs request timeouts, client side) need nothing here.

## Lock changes

| Package | Before | After |
|---|---|---|
| fastmcp | 4.0.11 | 4.1.0 |
| fastmcp-slim | 4.0.11 | 4.1.0 |
| mcp | 2.2.0 | 2.3.0 |
| mcp-types | 2.2.0 | 2.3.0 |
| beartype | 0.22.9 | 0.22.9 (Python < 3.15) and 0.23.0 (Python >= 3.15) |

**Why beartype is locked twice:** this is deliberate, not drift, and it matches template v1.7.0. `fastmcp-slim` 4.1.0 adds `beartype>=0.23.0rc2; python_version >= "3.15"` ([#5558](PrefectHQ/fastmcp#5558)), so uv forks the resolution at 3.15. Below 3.15, only `py-key-value-aio`'s `beartype>=0.20.0` applies, and uv keeps the 0.22.9 already locked because beartype wasn't upgraded. Python 3.10 to 3.13, the versions CI runs, still install 0.22.9.

## Tests

No test changes. On Python 3.10, 3.11, 3.12 and 3.13, with `CI=true` and `--extra dev`, 667 passed, 1 deselected (the deselected one is the opt-in e2e test), at 100% coverage. The 3.12 run gave the same result with `SNOWFLAKE_MCP_AUTH_TOKEN` and `SNOWFLAKE_MCP_ALLOW_UNAUTHENTICATED_BIND` exported in the shell.

## Gates

- `ruff check .` and `ruff format --check .`: clean
- `mypy src/`: clean
- `uv lock --check`: clean
- `scripts/check_tool_contract.py`: passed
- `scripts/check_snowflake_drift.py`: passed
- `scripts/check_version.py` (on a fresh `uv build`): passed
- `scripts/check_conformance.sh`: the baseline check passed (12 passed; all 20 failures are expected and in the baseline)
christianclaudio added a commit to christianclaudio/mcp-server-sigma that referenced this pull request Oct 10, 2026
## Why

Template v1.7.0 (#82) raised the FastMCP floor to 4.1.0 and mcp to 2.3.0. This copies both floors here so the product matches the template. Nothing in `src/` or `tests/` needed to change.

## Changes

- `pyproject.toml` (core and both `code-mode` / `dev` extras), `fastmcp.json`: `fastmcp>=4.0.11` becomes `>=4.1.0` and `mcp>=2.2.0` becomes `>=2.3.0`.
- `uv.lock`: refreshed with `uv lock --upgrade-package fastmcp --upgrade-package mcp` only. No other package was upgraded.
- `README.md`: the template's idle-session line, added as a bullet under the HTTP authentication list, because this README documents serving Streamable HTTP in the default stateful mode.

No source or test changes. No version bump.

## Audit (src, tests, docs, README)

- Tool Search ([#5467](PrefectHQ/fastmcp#5467)): Regex (default) or BM25 Tool Search is opt-in (`src/sigma_mcp/server.py:415`). Test patterns are plain words (`workbooks_`, `workbooks_list`) and `\b<name>\b` in `tests/test_client_surface.py:204`; the rust-regex engine supports `\b`, and that test passes on 4.1.0. The lookarounds and backreferences in `errors.py` belong to the redaction patterns. Python's `re` compiles them, not Tool Search, so they are unaffected.
- Code Mode: `CodeMode()` is called with no arguments (`src/sigma_mcp/server.py`), and `max_duration_secs` appears nowhere, so the Monty 1.1 rename to `max_feed_duration_secs` (default 30.0) needs no change; Code Mode inherits the new default.
- HTTP idle expiry ([#5229](PrefectHQ/fastmcp#5229)): `session_idle_timeout` is not set anywhere, so stateful HTTP deployments now expire sessions after 30 idle minutes (HTTP 404, and the client starts a new session). The HTTP tests build stateless apps, and the `stateless_http=False` assertions only check the arguments passed to `run()`, so the tests are unaffected. The README line documents this.
- No `x-mcp-header` annotations ([#3620](modelcontextprotocol/python-sdk#3620)), no `ctx.meta` / `ctx.params` reads ([#3628](modelcontextprotocol/python-sdk#3628)), no `MultiAuth`, no skills, and no OpenAPI `.`/`..` path parameters.

## FastMCP 4.1.0 ([release](https://github.com/PrefectHQ/fastmcp/releases/tag/v4.1.0)) and mcp 2.3.0 ([release](https://github.com/modelcontextprotocol/python-sdk/releases/tag/v2.3.0))

The items that apply here are the Tool Search engine change, the 30-minute idle expiry and the Monty 1.1 rename above. The other breaking items in 4.1.0 (MultiAuth client IDs, skill file paths, OpenAPI path parameters, Python 3.15) touch nothing used here. In mcp 2.3.0, `httpx2>=2.10.0` ([#3600](modelcontextprotocol/python-sdk#3600)) was already satisfied. [#3630](modelcontextprotocol/python-sdk#3630) (`Mcp-Param-*` lookup by name) and [#3635](modelcontextprotocol/python-sdk#3635) (OAuth login vs request timeouts, client side) need nothing here.

## Lock changes

| Package | Before | After |
|---|---|---|
| fastmcp | 4.0.11 | 4.1.0 |
| fastmcp-slim | 4.0.11 | 4.1.0 |
| mcp | 2.2.0 | 2.3.0 |
| mcp-types | 2.2.0 | 2.3.0 |
| pydantic-monty | 0.0.21 | 1.1.0 |
| pydantic-monty-client | 0.0.21 | 1.1.0 |
| pydantic-monty-runtime | 0.0.21 | 1.1.0 |
| beartype | 0.22.9 | 0.22.9 (Python < 3.15) and 0.23.0 (Python >= 3.15) |

**Why beartype is locked twice:** this is deliberate, not drift, and it matches template v1.7.0. `fastmcp-slim` 4.1.0 adds `beartype>=0.23.0rc2; python_version >= "3.15"` ([#5558](PrefectHQ/fastmcp#5558)), so uv forks the resolution at 3.15. Below 3.15, only `py-key-value-aio`'s `beartype>=0.20.0` applies, and uv keeps the 0.22.9 already locked because beartype wasn't upgraded. Python 3.10 to 3.13, the versions CI runs, still install 0.22.9.

## Tests

No test changes. On Python 3.10, 3.11, 3.12 and 3.13, with `CI=true` and `--extra dev --extra code-mode`, 830 passed, 9 skipped, 1 deselected (the deselected one is the opt-in e2e test), at 100% coverage. The 3.12 run gave the same result with `SIGMA_MCP_AUTH_TOKEN` and `SIGMA_MCP_ALLOW_UNAUTHENTICATED_BIND` exported in the shell.

## Gates

- `ruff check .` and `ruff format --check .`: clean
- `mypy --strict src/`: clean
- `uv lock --check`: clean
- `scripts/check_tool_contract.py`: passed
- `scripts/check_openapi_drift.py`: the local HTTP 400 came from the review machine's network (DNS), not Sigma's servers. `curl` gets 200 from the spec URLs, and CI's drift job is green on this PR and on `main`.
- `scripts/check_version.py` (on a fresh `uv build`): passed
- `scripts/check_conformance.sh`: the baseline check passed (12 passed; all 20 failures are expected and in the baseline)
christianclaudio added a commit to christianclaudio/mcp-server-smartsheet-rm that referenced this pull request Oct 10, 2026
## Why

Template v1.7.0 (#82) raised the FastMCP floor to 4.1.0 and mcp to 2.3.0. This copies both floors here so the product matches the template. Nothing in `src/` or `tests/` needed to change.

## Changes

- `pyproject.toml` (core and both `code-mode` / `dev` extras), `fastmcp.json`: `fastmcp>=4.0.11` becomes `>=4.1.0` and `mcp>=2.2.0` becomes `>=2.3.0`.
- `uv.lock`: refreshed with `uv lock --upgrade-package fastmcp --upgrade-package mcp` only. No other package was upgraded.
- `README.md`: the template's idle-session line, added as a paragraph after the endpoint line in "Streamable HTTP", because this README documents serving Streamable HTTP in the default stateful mode.

No source or test changes. No version bump.

## Audit (src, tests, docs, README)

- Tool Search ([#5467](PrefectHQ/fastmcp#5467)): Regex (default) or BM25 Tool Search is opt-in (`src/smartsheet_rm_mcp/server.py:294`). Test patterns are plain words (`projects_`, `time_list`). The lookarounds and backreferences in `errors.py` belong to the redaction patterns. Python's `re` compiles them, not Tool Search, so they are unaffected.
- Code Mode: `CodeMode()` is called with no arguments (`src/smartsheet_rm_mcp/server.py`), and `max_duration_secs` appears nowhere, so the Monty 1.1 rename to `max_feed_duration_secs` (default 30.0) needs no change; Code Mode inherits the new default.
- HTTP idle expiry ([#5229](PrefectHQ/fastmcp#5229)): `session_idle_timeout` is not set anywhere, so stateful HTTP deployments now expire sessions after 30 idle minutes (HTTP 404, and the client starts a new session). The HTTP tests build stateless apps, and the `stateless_http=False` assertions only check the arguments passed to `run()`, so the tests are unaffected. The README line documents this.
- No `x-mcp-header` annotations ([#3620](modelcontextprotocol/python-sdk#3620)), no `ctx.meta` / `ctx.params` reads ([#3628](modelcontextprotocol/python-sdk#3628)), no `MultiAuth`, no skills, and no OpenAPI `.`/`..` path parameters.

## FastMCP 4.1.0 ([release](https://github.com/PrefectHQ/fastmcp/releases/tag/v4.1.0)) and mcp 2.3.0 ([release](https://github.com/modelcontextprotocol/python-sdk/releases/tag/v2.3.0))

The items that apply here are the Tool Search engine change, the 30-minute idle expiry and the Monty 1.1 rename above. The other breaking items in 4.1.0 (MultiAuth client IDs, skill file paths, OpenAPI path parameters, Python 3.15) touch nothing used here. In mcp 2.3.0, `httpx2>=2.10.0` ([#3600](modelcontextprotocol/python-sdk#3600)) was already satisfied. [#3630](modelcontextprotocol/python-sdk#3630) (`Mcp-Param-*` lookup by name) and [#3635](modelcontextprotocol/python-sdk#3635) (OAuth login vs request timeouts, client side) need nothing here.

## Lock changes

| Package | Before | After |
|---|---|---|
| fastmcp | 4.0.11 | 4.1.0 |
| fastmcp-slim | 4.0.11 | 4.1.0 |
| mcp | 2.2.0 | 2.3.0 |
| mcp-types | 2.2.0 | 2.3.0 |
| pydantic-monty | 0.0.21 | 1.1.0 |
| pydantic-monty-client | 0.0.21 | 1.1.0 |
| pydantic-monty-runtime | 0.0.21 | 1.1.0 |
| beartype | 0.22.9 | 0.22.9 (Python < 3.15) and 0.23.0 (Python >= 3.15) |

**Why beartype is locked twice:** this is deliberate, not drift, and it matches template v1.7.0. `fastmcp-slim` 4.1.0 adds `beartype>=0.23.0rc2; python_version >= "3.15"` ([#5558](PrefectHQ/fastmcp#5558)), so uv forks the resolution at 3.15. Below 3.15, only `py-key-value-aio`'s `beartype>=0.20.0` applies, and uv keeps the 0.22.9 already locked because beartype wasn't upgraded. Python 3.10 to 3.13, the versions CI runs, still install 0.22.9.

## Tests

No test changes. On Python 3.10, 3.11, 3.12 and 3.13, with `CI=true` and `--extra dev --extra code-mode`, 625 passed, 1 deselected (the deselected one is the opt-in e2e test), at 100% coverage. The 3.12 run gave the same result with `SMARTSHEET_RM_MCP_AUTH_TOKEN` and `SMARTSHEET_RM_MCP_ALLOW_UNAUTHENTICATED_BIND` exported in the shell.

## Gates

- `ruff check .` and `ruff format --check .`: clean
- `mypy --strict src/`: clean
- `uv lock --check`: clean
- `scripts/check_tool_contract.py`: passed
- `scripts/check_openapi_drift.py`: passed (103 operations)
- `scripts/check_version.py` (on a fresh `uv build`): passed
- `scripts/check_conformance.sh`: the baseline check passed (12 passed; all 20 failures are expected and in the baseline)
christianclaudio added a commit to christianclaudio/mcp-server-espn that referenced this pull request Oct 10, 2026
## Why

Template v1.7.0 (#82) raised the FastMCP floor to 4.1.0 and mcp to 2.3.0. This copies both floors here so the product matches the template. Nothing in `src/` or `tests/` needed to change.

## Changes

- `pyproject.toml` (core), `fastmcp.json`: `fastmcp>=4.0.11` becomes `>=4.1.0` and `mcp>=2.2.0` becomes `>=2.3.0`.
- `uv.lock`: refreshed with `uv lock --upgrade-package fastmcp --upgrade-package mcp` only. No other package was upgraded.
- `README.md`: the template's idle-session line, added as a paragraph after the endpoint line in the HTTP transport section, because this README documents serving Streamable HTTP in the default stateful mode.

No source or test changes. No version bump.

## Audit (src, tests, docs, README)

- Tool Search ([#5467](PrefectHQ/fastmcp#5467)): `RegexSearchTransform()` is opt-in (`src/espn_mcp/server.py:185`); no test or doc passes a pattern. The lookarounds and backreferences in `errors.py` belong to the redaction patterns. Python's `re` compiles them, not Tool Search, so they are unaffected.
- Code Mode: No Code Mode in this repo; no `CodeMode(` or `max_duration_secs`.
- HTTP idle expiry ([#5229](PrefectHQ/fastmcp#5229)): `session_idle_timeout` is not set anywhere, so stateful HTTP deployments now expire sessions after 30 idle minutes (HTTP 404, and the client starts a new session). The HTTP tests build stateless apps, and the `stateless_http=False` assertions only check the arguments passed to `run()`, so the tests are unaffected. The README line documents this.
- No `x-mcp-header` annotations ([#3620](modelcontextprotocol/python-sdk#3620)), no `ctx.meta` / `ctx.params` reads ([#3628](modelcontextprotocol/python-sdk#3628)), no `MultiAuth`, no skills, and no OpenAPI `.`/`..` path parameters.

## FastMCP 4.1.0 ([release](https://github.com/PrefectHQ/fastmcp/releases/tag/v4.1.0)) and mcp 2.3.0 ([release](https://github.com/modelcontextprotocol/python-sdk/releases/tag/v2.3.0))

The items that apply here are the Tool Search engine change, the 30-minute idle expiry and the Monty 1.1 rename above. The other breaking items in 4.1.0 (MultiAuth client IDs, skill file paths, OpenAPI path parameters, Python 3.15) touch nothing used here. In mcp 2.3.0, `httpx2>=2.10.0` ([#3600](modelcontextprotocol/python-sdk#3600)) was already satisfied. [#3630](modelcontextprotocol/python-sdk#3630) (`Mcp-Param-*` lookup by name) and [#3635](modelcontextprotocol/python-sdk#3635) (OAuth login vs request timeouts, client side) need nothing here.

## Lock changes

| Package | Before | After |
|---|---|---|
| fastmcp | 4.0.11 | 4.1.0 |
| fastmcp-slim | 4.0.11 | 4.1.0 |
| mcp | 2.2.0 | 2.3.0 |
| mcp-types | 2.2.0 | 2.3.0 |
| beartype | 0.22.9 | 0.22.9 (Python < 3.15) and 0.23.0 (Python >= 3.15) |

**Why beartype is locked twice:** this is deliberate, not drift, and it matches template v1.7.0. `fastmcp-slim` 4.1.0 adds `beartype>=0.23.0rc2; python_version >= "3.15"` ([#5558](PrefectHQ/fastmcp#5558)), so uv forks the resolution at 3.15. Below 3.15, only `py-key-value-aio`'s `beartype>=0.20.0` applies, and uv keeps the 0.22.9 already locked because beartype wasn't upgraded. Python 3.10 to 3.13, the versions CI runs, still install 0.22.9.

## Tests

No test changes. On Python 3.10, 3.11, 3.12 and 3.13, with `CI=true` and `--extra dev`, 474 passed, 1 deselected (the deselected one is the opt-in e2e test), at 100% coverage. The 3.12 run gave the same result with `ESPN_MCP_AUTH_TOKEN` and `ESPN_MCP_ALLOW_UNAUTHENTICATED_BIND` exported in the shell.

## Gates

- `ruff check .` and `ruff format --check .`: clean
- `mypy --strict src`: clean
- `uv lock --check`: clean
- `scripts/check_tool_contract.py`: passed
- `scripts/check_openapi_drift.py`: passed
- `scripts/check_version.py` (on a fresh `uv build`): passed
- `scripts/check_conformance.sh`: the baseline check passed (12 passed; all 20 failures are expected and in the baseline)
christianclaudio added a commit to christianclaudio/mcp-server-kalshi that referenced this pull request Oct 10, 2026
## Why

Template v1.7.0 (#82) raised the FastMCP floor to 4.1.0 and mcp to 2.3.0. This copies both floors here so the product matches the template. Nothing in `src/` or `tests/` needed to change.

## Changes

- `pyproject.toml` (core), `fastmcp.json`: `fastmcp>=4.0.11` becomes `>=4.1.0` and `mcp>=2.2.0` becomes `>=2.3.0`.
- `uv.lock`: refreshed with `uv lock --upgrade-package fastmcp --upgrade-package mcp` only. No other package was upgraded.
- `README.md`: the template's idle-session line, added as a bullet under "Known limits" in the Streamable HTTP section, because this README documents serving Streamable HTTP in the default stateful mode.

No source or test changes. No version bump.

## Audit (src, tests, docs, README)

- Tool Search ([#5467](PrefectHQ/fastmcp#5467)): No Tool Search transform is used. The lookarounds and backreferences in `errors.py` belong to the redaction patterns. Python's `re` compiles them, not Tool Search, so they are unaffected.
- Code Mode: No Code Mode in this repo; no `CodeMode(` or `max_duration_secs`.
- HTTP idle expiry ([#5229](PrefectHQ/fastmcp#5229)): `session_idle_timeout` is not set anywhere, so stateful HTTP deployments now expire sessions after 30 idle minutes (HTTP 404, and the client starts a new session). The HTTP tests build stateless apps, and the `stateless_http=False` assertions only check the arguments passed to `run()`, so the tests are unaffected. The README line documents this.
- No `x-mcp-header` annotations ([#3620](modelcontextprotocol/python-sdk#3620)), no `ctx.meta` / `ctx.params` reads ([#3628](modelcontextprotocol/python-sdk#3628)), no `MultiAuth`, no skills, and no OpenAPI `.`/`..` path parameters.
- `src/mcp_server_kalshi/server.py:172-176,1250` builds `experimental_capabilities={}` for the low-level stdio path. Under mcp 2.3.0 ([#3614](modelcontextprotocol/python-sdk#3614)) an empty `experimental` is left out of `initialize`. No test or client here reads it; the protocol and conformance runs pass.

## FastMCP 4.1.0 ([release](https://github.com/PrefectHQ/fastmcp/releases/tag/v4.1.0)) and mcp 2.3.0 ([release](https://github.com/modelcontextprotocol/python-sdk/releases/tag/v2.3.0))

The items that apply here are the Tool Search engine change, the 30-minute idle expiry and the Monty 1.1 rename above. The other breaking items in 4.1.0 (MultiAuth client IDs, skill file paths, OpenAPI path parameters, Python 3.15) touch nothing used here. In mcp 2.3.0, `httpx2>=2.10.0` ([#3600](modelcontextprotocol/python-sdk#3600)) was already satisfied. [#3630](modelcontextprotocol/python-sdk#3630) (`Mcp-Param-*` lookup by name) and [#3635](modelcontextprotocol/python-sdk#3635) (OAuth login vs request timeouts, client side) need nothing here.

## Lock changes

| Package | Before | After |
|---|---|---|
| fastmcp | 4.0.11 | 4.1.0 |
| fastmcp-slim | 4.0.11 | 4.1.0 |
| mcp | 2.2.0 | 2.3.0 |
| mcp-types | 2.2.0 | 2.3.0 |
| beartype | 0.22.9 | 0.22.9 (Python < 3.15) and 0.23.0 (Python >= 3.15) |

**Why beartype is locked twice:** this is deliberate, not drift, and it matches template v1.7.0. `fastmcp-slim` 4.1.0 adds `beartype>=0.23.0rc2; python_version >= "3.15"` ([#5558](PrefectHQ/fastmcp#5558)), so uv forks the resolution at 3.15. Below 3.15, only `py-key-value-aio`'s `beartype>=0.20.0` applies, and uv keeps the 0.22.9 already locked because beartype wasn't upgraded. Python 3.10 to 3.13, the versions CI runs, still install 0.22.9.

## Tests

No test changes. On Python 3.10, 3.11, 3.12 and 3.13, with `CI=true` and `--all-extras`, 639 passed, 1 deselected (the deselected one is the opt-in e2e test), at 100% coverage. The 3.12 run gave the same result with `KALSHI_MCP_AUTH_TOKEN` and `KALSHI_MCP_ALLOW_UNAUTHENTICATED_BIND` exported in the shell.

## Gates

- `ruff check .` and `ruff format --check .`: clean
- `black --check src tests`: clean
- `mypy`: clean
- `uv lock --check`: clean
- `scripts/check_tool_contract.py`: passed
- `scripts/check_openapi_drift.py`: passed
- `scripts/check_version.py` (on a fresh `uv build`): passed
- `scripts/check_conformance.sh`: the baseline check passed (12 passed; all 20 failures are expected and in the baseline)
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