github PrefectHQ/fastmcp v4.0.0b1
v4.0.0b1: Fourgone Conclusion

pre-release3 hours ago

FastMCP 4 rebuilds the framework on the MCP Python SDK v2, and this beta is the first release to run on the SDK's stable 2.0.

The change is mostly one you can't see. The SDK v2 rewrote the protocol layer end to end — protocol types moved into a standalone mcp_types package (still importable as mcp.types), every model field renamed from camelCase to snake_case in Python, and the server's request-handling model replaced. FastMCP absorbs nearly all of it, so most FastMCP 3 servers run untouched. The major version is how we signal that the behavior underneath moved, rather than slipping a new engine in under a patch release.

On that foundation, v4 steps into the protocol's next era. One server answers both the sessionless 2026-07-28 protocol and the older session-based handshake, negotiated per connection — so you adopt the new protocol without forking your deployment or gating clients by version.

🌐 Every protocol era — modern and legacy clients served simultaneously, and any replica behind a plain load balancer can answer a modern request.

💾 State without a sessionUserSession and SessionId give tools durable per-user state on a protocol that deliberately has none (SEP-2567), stored server-side and keyed to the authenticated user.

Background tasks — the io.modelcontextprotocol/tasks extension (SEP-2663), shipped in the new fastmcp-tasks package on the same Docket engine FastMCP 3 used. @mcp.tool(task=True) is still the whole authoring surface.

🧩 Server extensionsadd_extension() turns capability-negotiated protocol features (SEP-2133) into a supported plugin surface instead of surgery on core.

🔐 Enterprise auth — complete server-side identity assertion (SEP-990), plus require_roles, incremental-authorization step-up challenges (SEP-2350), DCR application_type (SEP-837), and routable transport headers for gateways (SEP-2243).

⌨️ Argument completion — a @mcp.completion handler answers autocomplete for prompt arguments and resource-template parameters, and can narrow suggestions using the arguments already supplied.

Breaking changes. Server-initiated sampling and roots are removed from the server API: both pushed a request down a live connection, which the sessionless protocol no longer has, and a method that only works against old clients is a trap. Elicitation continues in a request-shaped form, and generation belongs in your server — call an LLM directly. The 3.x-era compatibility shims are also gone. The upgrade guide walks through every change.

Install the beta by pinning it explicitly:

pip install "fastmcp==4.0.0b1"

This is a beta released for testing ahead of 4.0. Pin an exact version and expect sharp edges.

What's Changed

New Features 🎉

  • Migrate to MCP Python SDK v2 by @jlowin in #4437
  • Teach fastmcp.Client the modern protocol: mode negotiation, MRTR driver, response cache by @jlowin in #4450
  • Forward-port Hugging Face auth provider by @jlowin in #4475
  • Add server-side identity assertion (SEP-990 ID-JAG) by @jlowin in #4483
  • Add guard-mode multi-round-trip tools (SEP-2322) by @jlowin in #4544
  • Add FastMCP-native server extension API (SEP-2133) by @jlowin in #4602
  • Add stateless session state (UserSession / SessionId) by @jlowin in #4604
  • Add background tasks via the io.modelcontextprotocol/tasks extension (SEP-2663) by @jlowin in #4603

Breaking Changes ⚠️

  • Emit one SERVER span per request and adopt spec-correct error codes by @jlowin in #4445
  • Remove 3.x deprecated module shims and dead parameters by @jlowin in #4447
  • Remove 3.0-deprecated FastMCP server methods by @jlowin in #4451
  • Remove 3.x deprecated parameters and object-mode decorators by @jlowin in #4453
  • Migrate to MCP SDK v2.0.0b2 (httpx2) by @jlowin in #4503
  • Fix typos by @szepeviktor in #4498
  • Stop proxies from validating backend results or mutating shared transports by @jlowin in #4552
  • Surface resource, prompt, and proxy errors on the modern protocol by @jlowin in #4579
  • Negotiate the best mutual protocol era by default by @jlowin in #4572
  • Remove server-initiated sampling and roots from the server API by @jlowin in #4648
  • Remove 3.x-era compatibility shims by @jlowin in #4661

Enhancements ✨

  • Deprecate ctx.sample and add clear errors for push features on 2026 connections by @jlowin in #4448
  • Add server-level cache hints (SEP-2549) by @jlowin in #4464
  • Add KeyValueResponseCacheStore for distributed client response caching by @jlowin in #4479
  • Test lifespan fires once per process over HTTP by @jlowin in #4480
  • Add telemetry off-switch and mcp.protocol.version span attribute by @jlowin in #4481
  • Trace client task management requests by @jlowin in #4525
  • Stabilize upgraded ty checks by @jlowin in #4526
  • Improve DescopeProvider scope discovery and well-known URL support by @gaokevin1 in #4489
  • Add examples/ to the ty static-analysis gate by @jlowin in #4466
  • Expose telemetry attributes on span start by @zzstoatzz in #4487
  • Fix-issue-4284 : Add Auth0MCPProvider for Auth0 Auth for MCP by @vijaydeepsinha in #4411
  • Run FastMCP middleware for every inbound message by @jlowin in #4553
  • Add 'prs welcome' label to waive the PR assignment gate by @jlowin in #4557
  • Rename martian workflows to marvin by @jlowin in #4558
  • Bump pinned Claude models to current versions by @jlowin in #4561
  • Make the unit suite fast: in-process HTTP tests, no real sleeps, parallel Windows CI by @jlowin in #4554
  • Mirror the frontend's protocol era on a proxy's backend connection by @jlowin in #4573
  • Drop forked client protocol helpers in favor of the SDK's by @jlowin in #4574
  • Bring the v4 developer notes up to date with what shipped by @jlowin in #4581
  • Trim fastmcp.types to FastMCP-unique types by @jlowin in #4584
  • Let a server answer argument-completion requests by @jlowin in #4582
  • Add machine-to-machine client authentication by @jlowin in #4583
  • Expose era-neutral client server metadata by @zzstoatzz in #4599
  • Support routable transport headers for gateways (SEP-2243) by @jlowin in #4622
  • Emit scope step-up challenges for incremental authorization (SEP-2350) by @jlowin in #4623
  • Honor OAuth application_type in DCR (SEP-837) by @jlowin in #4621
  • Drop stale label-noting instructions from CLAUDE.md by @jlowin in #4654
  • Add require_roles auth check by @jlowin in #4656
  • Add valid_scopes parameter to OIDC proxy valid scopes by @Educg550 in #4660
  • feat: Add telemetry interop mode for FastMCP by @strawgate in #4046
  • Note that review comment threads should get an acknowledgement by @jlowin in #4678
  • Soften the review-comment reply guidance by @jlowin in #4683
  • Resolve review threads on fix, reply on decline by @jlowin in #4685
  • Move to the stable MCP Python SDK 2.0.0 by @jlowin in #4655

Security 🔒

  • Drive the FastMCP lifespan through the SDK session manager by @jlowin in #4446
  • Route skill file access through SDK path-security primitives by @jlowin in #4449
  • Screen templated resource parameters for path traversal by default by @jlowin in #4482
  • [codex] Add OAuthProxy RFC 9207 issuer responses by @jlowin in #4438
  • Apply app visibility where no host can by @jlowin in #4692

Fixes 🐞

  • Capture SharedContext for task-enabled Docket servers by @jlowin in #4443
  • Fix stale mcp.types imports in examples by @jlowin in #4452
  • Forward-port HTTP host guard compatibility by @jlowin in #4474
  • Fix Azure scope fallback by @zzstoatzz in #4469
  • fix(server): omit ScalarElicitationType wrapper title from elicitation schemas by @syf2211 in #4502
  • Skip unsupported JWKS keys instead of failing the whole key set (#4515) by @earfman in #4517
  • Don't mutate the caller's schema in compress_schema by @winklemad in #4492
  • Forward upstream instructions through create_proxy by @verdie-g in #4512
  • Serialize deep object query parameters by @jlowin in #4523
  • Reject positional-only tool parameters by @jlowin in #4524
  • Clarify PR-reopen flow and fix label-race that broke auto-reopen by @jlowin in #4518
  • Clean up disconnected task sessions by @jlowin in #4519
  • Handle expired OAuth client registrations by @jlowin in #4520
  • Fix OAuth request annotation after httpx2 migration by @jlowin in #4534
  • Fix docs banner contrast by @jlowin in #4522
  • Preserve component metadata in response cache by @jlowin in #4521
  • Clean up task sessions on connection exit by @jlowin in #4535
  • Include scopes in auth challenges by @jlowin in #4527
  • Make examples/ actually trigger the ty gate by @jlowin in #4541
  • Add subject field to AccessToken initialization by @piaudonn in #4267
  • Restore Mintlify's fixed banner positioning by @jlowin in #4542
  • Fix #4292: SSRF guard breaks OAuth/JWKS fetches behind a corporate HTTP proxy by @endofcake in #4412
  • Preserve telemetry attributes when a sampler does not forward them by @jlowin in #4539
  • Speed up the unit test suite, and fix the task-notification race it surfaced by @jlowin in #4550
  • Fix label triage applying no labels, and make blocked tool calls fail by @jlowin in #4555
  • Fix AI workflow allowlists being destroyed by tokenization by @jlowin in #4560
  • Make transformed tool required order deterministic by @Kludex in #4564
  • Stop gather() from creating coroutines it may never schedule by @jlowin in #4559
  • Restore upgraded dependency checks by @zzstoatzz in #4576
  • Fix skill frontmatter parsing with UTF-8 BOM by @hxaxd in #4533
  • Fix File helper extension handling by @VectorPeak in #4531
  • Fix percent-encoded skill file names unreadable in resources mode by @jlowin in #4590
  • Fix flaky stdio crash-recovery tests by @jlowin in #4594
  • Bridge camelCase ToolAnnotations reads by @zzstoatzz in #4597
  • Preserve raw CallToolResult tool returns by @LarryHu0217 in #4587
  • Advertise only supported token endpoint auth methods in OAuthProxy metadata by @jlowin in #4608
  • Fix OAuth proxy override typing by @zzstoatzz in #4612
  • Pin burner-redis below the Windows-crashing 0.1.7 release by @jlowin in #4618
  • fix : canonical mime type mapping from formats to remove inconsistency #4627 by @Aman071106 in #4628
  • fix: accept callable roots handlers by @ShuyingZhang in #4639
  • Pass the MCP conformance suite's draft and pending scenarios by @jlowin in #4650
  • Use issuer_url for OAuth issuer identity by @jlowin in #4652
  • Fix the ty failure blocking upgrade checks on main by @jlowin in #4657
  • Bind CIMD assertion audience to the advertised token endpoint by @jlowin in #4659
  • Record effective scopes on the OAuth transaction by @jlowin in #4670
  • Copy schemas iteratively so deep nesting still compresses by @jlowin in #4671
  • Fix OpenAPI allOf reference fields by @hxaxd in #4653
  • Flatten OpenAPI discriminator subtypes into request bodies by @jlowin in #4677
  • Let maintenance releases publish without fastmcp-tasks by @jlowin in #4676
  • Read CLI-scanned MCP config files as UTF-8 explicitly by @jlowin in #4690
  • Late-bind app tool names so UIs survive composition by @jlowin in #4682

Docs 📚

  • Docs: forward-port v3.4.4 changelog entries by @jlowin in #4476
  • Document icon theme support by @jlowin in #4537
  • Add missing 4.0.0 version badge to Path Security docs by @jlowin in #4540
  • Align server component docs by @strawgate in #4260
  • Align CLI, deployment, and config docs by @strawgate in #4259
  • Align client, Apps, and integration docs by @strawgate in #4261
  • Fix stale MRTR/elicitation framing in client and upgrade docs by @jlowin in #4551
  • docs: quote pip extras install examples by @RachGranville in #4568
  • Document Windows CI parallelism and the subprocess_heavy marker by @jlowin in #4575
  • Document v3->v4 removals and add upgrade-reality tests by @jlowin in #4585
  • Archive v3 docs and publish v4 as the primary version by @jlowin in #4613
  • Document targeted v4 prerelease installation by @zzstoatzz in #4598
  • Fix stale Mac/Windows-vs-Linux OAuth key/storage docs by @jlowin in #4617
  • v4 docs quality pass: stale task/era claims, broken links, polish by @jlowin in #4619
  • whats-new: add the argument completion capability by @jlowin in #4620
  • docs: fix ProxyProvider docstring example calling nonexistent with_namespace() by @andrew-stelmach-fleet in #4633
  • Unpublish v4 development notes; prep docs for beta 1 by @jlowin in #4644
  • Expand the FAQ for the v4 transition by @jlowin in #4649
  • Document the issuer_url identity change for upgraders by @jlowin in #4658
  • Cover require_roles in the v4 highlights by @jlowin in #4666
  • Fix FAQ: sampling/roots/elicitation legacy-mode advice, SessionProvider registration by @jlowin in #4672
  • Audit v4 docs: fix missing version badges, fill whats-new gaps by @jlowin in #4668
  • Docs: add v3.4.5 changelog entries to main by @jlowin in #4674
  • Split the SDK upgrade guides by SDK version by @jlowin in #4684
  • Add v4.0.0b1 changelog and updates entries by @jlowin in #4681

Dependencies 📦

  • chore(deps): bump mcp from 1.26.0 to 1.27.2 in /examples/testing_demo in the uv group across 1 directory by @dependabot[bot] in #4514
  • chore(deps): bump actions/setup-node from 6 to 7 by @dependabot[bot] in #4546
  • Bump actions/upload-artifact from 4 to 7 by @dependabot[bot] in #4640
  • Bump actions/setup-python from 6 to 7 by @dependabot[bot] in #4641
  • chore(deps): bump mcp from 1.27.2 to 1.28.1 in /examples/testing_demo in the uv group across 1 directory by @dependabot[bot] in #4614

Other Changes 🦾

  • Test: HTTP lifespan fires once per process across sessions by @jlowin in #4470

New Contributors

Full Changelog: v3.4.5...v4.0.0b1

Don't miss a new fastmcp release

NewReleases is sending notifications on new releases.