FastMCP 3 RC1 means we believe the API is stable. Beta 2 drew a wave of real-world adoption — production deployments, migration reports, integration testing — and the feedback overwhelmingly confirmed that the architecture works. This release closes gaps that surfaced under load: auth flows that needed to be async, background tasks that needed reliable notification delivery, and APIs still carrying beta-era naming. If nothing unexpected surfaces, this is what 3.0.0 looks like.
🚨 Breaking Changes — The ui= parameter is now app= with a unified AppConfig class (matching the feature's actual name), and 16 FastMCP() constructor kwargs have finally been removed. If you've been ignoring months of deprecation warnings (not you, reader, I'm talking about other users), you'll get a TypeError with specific migration instructions.
🔐 Auth Improvements — Three changes that together round out FastMCP's auth story for production. auth= checks can now be async, so you can hit databases or external services during authorization — previously, passing an async function silently passed because the unawaited coroutine was truthy. Static Client Registration lets clients provide a pre-registered client_id/client_secret directly, bypassing DCR for servers that don't support it. And Azure OBO flows are now declarative via dependency injection:
from fastmcp.server.auth.providers.azure import EntraOBOToken
@mcp.tool()
async def get_emails(
graph_token: str = EntraOBOToken(["https://graph.microsoft.com/Mail.Read"]),
):
# OBO exchange already happened — just use the token
...⚡ Concurrent Sampling — When an LLM returns multiple tool calls in a single response, context.sample() can now execute them in parallel. Opt in with tool_concurrency=0 for unlimited parallelism, or set a bound. Tools that aren't safe to parallelize can declare sequential=True.
📡 Background Task Notifications — Background tasks now reliably push progress updates and elicit user input through the standard MCP protocol. A distributed Redis queue replaces polling (7,200 round-trips/hour → one blocking call), and ctx.elicit() in background tasks automatically relays through the client's standard elicitation_handler.
✅ OpenAPI Output Validation — When backends don't conform to their own OpenAPI schemas, the MCP SDK rejects the response and the tool fails. validate_output=False disables strict schema checking while still passing structured JSON to clients — a necessary escape hatch for imperfect APIs.
What's Changed
Enhancements 🔧
- generate-cli: auto-generate SKILL.md agent skill by @jlowin in #3115
- Scope Martian triage to bug-labeled issues for jlowin by @jlowin in #3124
- Add Azure OBO dependencies, auth token injection, and documentation by @jlowin in #2918
- feat: add Static Client Registration (#3085) by @martimfasantos in #3086
- Add concurrent tool execution with sequential flag by @strawgate in #3022
- Add validate_output option for OpenAPI tools by @jlowin in #3134
- Relay task elicitation through standard MCP protocol by @chrisguidry in #3136
- Bump py-key-value-aio to >=0.4.0,<0.5.0 by @strawgate in #3143
- Support async auth checks by @jlowin in #3152
- Make $ref dereferencing optional via FastMCP(dereference_refs=...) by @jlowin in #3151
- Expose local_provider property, deprecate FastMCP.remove_tool() by @jlowin in #3155
- Add helpers for converting FunctionTool and TransformedTool to SamplingTool by @strawgate in #3062
- Updates to github actions / workflows for claude by @strawgate in #3157
Fixes 🐞
- Updated deprecation URL for V3 by @SrzStephen in #3108
- Fix Windows test timeouts in OAuth proxy provider tests by @strawgate in #3123
- Fix session visibility marks leaking across sessions by @jlowin in #3132
- Fix unhandled exceptions in OpenAPI POST tool calls by @jlowin in #3133
- feat: distributed notification queue + BLPOP elicitation for background tasks by @gfortaine in #2906
- fix: snapshot access token for background tasks (#3095) by @gfortaine in #3138
- Stop duplicating path parameter descriptions into tool prose by @jlowin in #3149
- fix: guard client pagination loops against misbehaving servers by @jlowin in #3167
- Fix stale get_* references in docs and examples by @jlowin in #3168
- Support non-serializable values in Context.set_state by @jlowin in #3171
- Fix stale request context in StatefulProxyClient handlers by @jlowin in #3172
Breaking Changes 🛫
- Rename ui= to app= and consolidate ToolUI/ResourceUI into AppConfig by @jlowin in #3117
- Remove deprecated FastMCP() constructor kwargs by @jlowin in #3148
Docs 📚
- Update docs to reference beta 2 by @jlowin in #3112
- docs: add pre-registered OAuth clients to v3-features by @jlowin in #3129
- docs: update all references from 3.0.0b2 to 3.0.0rc1 by @jlowin in #3173
Dependencies 📦
- chore(deps): bump cryptography from 46.0.3 to 46.0.5 in /examples/testing_demo in the uv group across 1 directory by @dependabot[bot] in #3140
Other Changes 🦾
- docs: add v3.0.0rc1 features to v3-features tracking by @jlowin in #3145
- docs: remove nonexistent MSALApp from rc1 notes by @jlowin in #3146
New Contributors
- @martimfasantos made their first contribution in #3086
Full Changelog: v3.0.0b2...v3.0.0rc1