Bump starlette from 0.49.1 to 1.3.1 by dependabot[bot] · Pull Request #3116 · modelcontextprotocol/python-sdk · GitHub
Skip to content

Bump starlette from 0.49.1 to 1.3.1 - #3116

Closed
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/uv/starlette-1.3.1
Closed

dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/uv/starlette-1.3.1

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Jul 16, 2026 •

Copy link
Copy Markdown
Contributor

Bumps starlette from 0.49.1 to 1.3.1.

Release notes

Sourced from starlette's releases.

Version 1.3.1

What's Changed

Full Changelog: Kludex/starlette@1.3.0...1.3.1

Version 1.3.0

What's Changed

New Contributors

Full Changelog: Kludex/starlette@1.2.1...1.3.0

Version 1.2.1

What's Changed

New Contributors

Full Changelog: Kludex/starlette@1.2.0...1.2.1

Version 1.2.0

What's Changed

Full Changelog: Kludex/starlette@1.1.0...1.2.0

Version 1.1.0

... (truncated)

Changelog

Sourced from starlette's changelog.

1.3.1 (June 12, 2026)

Fixed

  • Enforce max_fields and max_part_size in FormParser #3329.
  • Enforce FormParser limits in parser callbacks #3331.

1.3.0 (June 11, 2026)

Added

  • Add httpx2 to the full extra #3323.
  • Annotate the URLPath protocol parameter with Literal #3285.

Fixed

  • Build request.url from structured components #3326.
  • Clamp oversized suffix ranges in FileResponse #3307.
  • Catch OSError alongside MultiPartException when closing temp files #3191.
  • Avoid collapsing exception groups raised from user code #2830.
  • Use removeprefix to strip the weak ETag indicator in is_not_modified #3193.
  • Fix IndexError in URL.replace() on a URL with no authority #3317.
  • Adjust testclient typing and warnings #3322.

1.2.1 (May 31, 2026)

Fixed

  • Use httpx2 for type checking in the testclient module #3304.
  • Add assert error for requires() when the request parameter is not a Request type #3298.

1.2.0 (May 28, 2026)

Added

  • Support httpx2 in the test client #3291.

1.1.0 (May 23, 2026)

Added

  • Use "application/octet-stream" as the FileResponse media type fallback #3283.

Fixed

  • Only dispatch standard HTTP verbs in HTTPEndpoint #3286.
  • Reject absolute paths in StaticFiles.lookup_path #3287.

1.0.1 (May 21, 2026)

... (truncated)

Commits
  • 8ebffd0 Version 1.3.1 (#3330)
  • 25b8e17 Enforce FormParser limits in parser callbacks (#3331)
  • dba1c4b Enforce max_fields and max_part_size in FormParser (#3329)
  • 45e51dc Use StarletteDeprecationWarning instead of DeprecationWarning (#3119)
  • 5f8610c Version 1.3.0 (#3327)
  • 167b585 Build request.url from structured components (#3326)
  • 3730925 Use removeprefix to strip weak ETag indicator in is_not_modified (#3193)
  • e6f7ad1 avoid collapsing exception groups from user code (#2830)
  • 115228f Annotate URLPath protocol parameter with Literal (#3285)
  • 113f193 docs: replace inline ASGI server list with link to canonical implemen… (#3204)
  • Additional commits viewable in compare view

@dependabot dependabot Bot added dependencies Pull requests that update a dependency file python:uv Pull requests that update python:uv code labels Jul 16, 2026

@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.

LGTM — lockfile-only Dependabot bump of starlette to 1.3.1. The SDK's own constraint (starlette>=0.27, unbounded) means end users already resolve 1.3.1; this only updates the CI/dev pin, and the full test matrix runs against it. The one inline note is a non-blocking follow-up suggestion, not a merge blocker.

Extended reasoning...

Overview

This PR is a single-file Dependabot change: uv.lock bumps starlette from 0.49.1 to 1.3.1. No source code, no pyproject.toml constraint change. The SDK's runtime requirement remains starlette>=0.27 (>=0.48 on 3.14) with no upper bound, so published-package users already resolve 1.3.1 today — this pin only affects the SDK's own CI/dev environment.

Security risks

The delta is upstream hardening (FormParser max_fields/max_part_size enforcement, StaticFiles absolute-path rejection, FileResponse range clamping) — security-positive rather than risky. The one behavioral interaction found is the inline nit: starlette's new 1 MB form-field limit raises an HTTPException(400) that the OAuth handlers' except ValidationError blocks don't translate into the RFC 6749 JSON error shape. The trigger is adversarial (>1 MB field or >1000 fields), the status code is still a correct 400, and the exposure exists independently of this PR given the unbounded floor — so it's a follow-up, not a blocker.

Level of scrutiny

Lockfile-only dependency bumps warrant moderate scrutiny focused on behavioral deltas in the upgraded package, which the bug hunting system performed: all imported starlette symbols verified present in 1.3.1, removed 1.0 APIs (on_startup/on_event/@app.route/WSGIMiddleware) confirmed unused, sse-starlette 3.0.2 compatibility checked, and the request.url structured-components change confirmed not to touch server-side SDK code. The full CI matrix (3.10–3.14 × ubuntu/windows, 100% coverage gate) runs against the new pin, which is the definitive compatibility check.

Other factors

No human reviewer comments and no prior bot reviews on this PR. The major-version jump (0.49 → 1.3) looks larger than it is — the audited delta shows no removed APIs in use and the repo does not use starlette's multipart/form features outside the OAuth handlers flagged inline. Approving with the inline nit standing as a suggested follow-up.

Comment thread uv.lock
Comment on lines 2470 to 2480

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.

🟡 Starlette 1.3.1 newly enforces max_part_size=1MB / max_fields=1000 on application/x-www-form-urlencoded bodies (Kludex/starlette#3329, #3331), raising an HTTPException(400) that the SDK's OAuth handlers (token.py, revoke.py, authorize.py POST, client_auth.py) don't catch — they only catch pydantic ValidationError around request.form(), so oversized posts to /token or /revoke now return a text/plain 400 instead of the RFC 6749 §5.2 JSON error object. Not a merge blocker (pyproject's unbounded starlette>=0.27 floor means users can already resolve 1.3.1, and the trigger is adversarial: a >1MB field or >1000 fields), but a follow-up could catch starlette's HTTPException around request.form() in these handlers and translate it into the OAuth invalid_request JSON shape.

Extended reasoning...

What changed in starlette

In starlette 0.49.1, FormParser (the parser for application/x-www-form-urlencoded bodies) had no size limits — Request._get_form simply ran FormParser(self.headers, self.stream()); await form_parser.parse() with no exception path. Starting in 1.3.1 (Kludex/starlette#3329 and #3331), FormParser enforces max_fields=1000 and max_part_size=1MB per field (verified in the installed wheel, formparsers.py:82-97). Exceeding either limit raises MultiPartException, which Request._get_form converts into a starlette HTTPException(status_code=400, detail='Field exceeded maximum size of 1024KB.' / 'Too many fields...') when app is in scope (requests.py:296-308).

Why the SDK's OAuth handlers are affected

The SDK's OAuth handlers all call await request.form() inside try blocks that catch only pydantic ValidationError (or AuthenticationError further up):

  • src/mcp/server/auth/handlers/token.py:121
  • src/mcp/server/auth/handlers/revoke.py:50
  • src/mcp/server/auth/handlers/authorize.py:150 (POST branch)
  • src/mcp/server/auth/middleware/client_auth.py:54 (called by token/revoke handlers)

These handlers deliberately construct RFC 6749 §5.2-conformant JSON error objects (TokenErrorResponse / RevocationErrorResponse via PydanticJSONResponse, with Cache-Control: no-store). The new starlette HTTPException is not caught by any of them, so it escapes to the Starlette app's ExceptionMiddleware and is rendered as a text/plain 400 response. If the handlers are composed as raw ASGI without a Starlette app in scope, the raw MultiPartException propagates and produces a 500 instead.

Step-by-step proof

  1. A client POSTs to /token with Content-Type: application/x-www-form-urlencoded and a body containing one field larger than 1 MiB (e.g. a huge client_assertion value): grant_type=client_credentials&client_assertion=AAAA...(>1MB).
  2. TokenHandler.handle (token.py:121) calls await request.form() inside try: ... except ValidationError.
  3. In starlette 1.3.1, FormParser.parse() accumulates the field value, hits the 1 MiB max_part_size check added in Enforce FormParser limits in parser callbacks Kludex/starlette#3331, and raises MultiPartException('Field exceeded maximum size of 1024KB.').
  4. Request._get_form catches it and re-raises as starlette.exceptions.HTTPException(400) (because the request is served by a Starlette app).
  5. This is not a ValidationError, so the handler's except doesn't fire — the carefully built TokenErrorResponse(error='invalid_request', ...) JSON path is bypassed.
  6. ExceptionMiddleware catches the HTTPException and returns 400 with body Field exceeded maximum size of 1024KB. as text/plain — violating RFC 6749 §5.2, which requires the token endpoint to return a JSON error object.

Under 0.49.1, the same request parses successfully (unbounded buffering) and reaches the handler's normal validation path — so the changed error shape is introduced by this bump.

Why this is not a merge blocker

  • pyproject.toml constrains starlette>=0.27 with no upper bound, so end users installing the published mcp package already resolve 1.3.1 today regardless of this PR — the lockfile only pins the SDK's own CI/dev environment. Blocking this bump would shield no one.
  • The trigger is adversarial or an extreme edge case: no realistic OAuth client sends a single >1 MiB form field or >1000 fields (even large RFC 7523 client_assertion JWTs are orders of magnitude below 1 MiB). The status code is still an RFC-correct 400; only the body shape/content-type differ.
  • The upstream change is intentional DoS hardening — 0.49.1's unbounded in-memory buffering of urlencoded bodies was strictly worse. Real deployments behind reverse proxies (e.g. nginx's 1 MB default body limit) would often preempt the app with a 413 anyway.

Suggested follow-up fix

In the four handlers listed above, catch starlette's HTTPException (or MultiPartException) around await request.form() and translate it into the OAuth invalid_request JSON error shape, e.g. TokenErrorResponse(error='invalid_request', error_description='request body too large') with status 400. Alternatively, pass explicit max_part_size/max_fields to request.form() and handle the failure there.

For completeness: the rest of the 0.49.1 → 1.3.1 delta was audited against SDK usage and no other affected paths were found — all imported starlette symbols still exist, removed 1.0 APIs (on_startup/on_event/@app.route/WSGIMiddleware) are unused, sse-starlette 3.0.2's imports remain valid, and request.url host-header behavior changes (starlette#3326) don't touch server-side SDK code.

Bumps [starlette](https://github.com/Kludex/starlette) from 0.49.1 to 1.3.1.
- [Release notes](https://github.com/Kludex/starlette/releases)
- [Changelog](https://github.com/Kludex/starlette/blob/main/docs/release-notes.md)
- [Commits](Kludex/starlette@0.49.1...1.3.1)

---
updated-dependencies:
- dependency-name: starlette
  dependency-version: 1.3.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot changed the title chore(deps): bump starlette from 0.49.1 to 1.3.1 Bump starlette from 0.49.1 to 1.3.1 Jul 25, 2026
@dependabot
dependabot Bot force-pushed the dependabot/uv/starlette-1.3.1 branch from 4d84b63 to 52eb078 Compare July 25, 2026 22:25
@maxisbey maxisbey closed this Aug 10, 2026
@dependabot @github

dependabot Bot commented on behalf of github Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

@dependabot
dependabot Bot deleted the dependabot/uv/starlette-1.3.1 branch August 10, 2026 18:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file python:uv Pull requests that update python:uv code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant