diff --git a/docs/clients/tasks.mdx b/docs/clients/tasks.mdx index 80eee5564..71a1384c9 100644 --- a/docs/clients/tasks.mdx +++ b/docs/clients/tasks.mdx @@ -110,6 +110,8 @@ Without an `elicitation_handler`, a task that asks for input raises `ToolError` ## Example +Putting it together, here is a client that submits a background task with `call_tool_task` and awaits its result: + ```python import asyncio from fastmcp import Client diff --git a/docs/development/v4-notes/background-tasks.mdx b/docs/development/v4-notes/background-tasks.mdx index c8ac0a93f..a342138af 100644 --- a/docs/development/v4-notes/background-tasks.mdx +++ b/docs/development/v4-notes/background-tasks.mdx @@ -6,7 +6,7 @@ title: Background Tasks (SEP-2663) ## TL;DR -Background tasks are not dead. The MCP spec moved them out of core and into a **Final, merged** extension — `io.modelcontextprotocol/tasks` (SEP-2663) — that keeps the polling model FastMCP already implements. **No SDK, in any language, ships a runtime for it yet.** FastMCP owns the only production-shaped execution engine (Docket/Redis) built for a near-identical protocol. +Background tasks live on. The MCP spec moved them out of core and into a **Final, merged** extension — `io.modelcontextprotocol/tasks` (SEP-2663) — that keeps the polling model FastMCP already implements. **No SDK, in any language, ships a runtime for it yet.** FastMCP owns the only production-shaped execution engine (Docket/Redis) built for a near-identical protocol. The plan: **rebuild task support on SEP-2663 as `fastmcp-tasks`, an in-repo optional package**, gated by `task=True` exactly as MCP Apps is gated by `app=True`. Remove the SEP-1686 *wire layer*; keep and re-home the *execution engine*. Along the way, introduce a **FastMCP-native server extension API** so tasks (and later Apps) plug in through one documented mechanism instead of bespoke surgery on core. diff --git a/docs/development/v4-notes/change-register.mdx b/docs/development/v4-notes/change-register.mdx index 58445d9fe..457cebf30 100644 --- a/docs/development/v4-notes/change-register.mdx +++ b/docs/development/v4-notes/change-register.mdx @@ -433,8 +433,8 @@ The push-style Context features that require the server to call back into the cl | Tools, resources, prompts, completions | Supported | Supported | | `ctx.elicit` (imperative) | Supported | Not on the back-channel — use [elicitation on the modern protocol](/servers/elicitation#elicitation-on-the-modern-protocol) | | `ctx.sample` / `ctx.sample_step` | Supported (deprecated) | Removed — call an LLM server-side | -| `ctx.list_roots` | Supported | Not yet — MRTR rewrite pending | -| Tasks (via the FastMCP client) | Supported | Not yet | +| `ctx.list_roots` | Supported | Via the [guard pattern](/servers/elicitation#elicitation-on-the-modern-protocol) | +| Background tasks (`task=True`) | Runs synchronously — never tasked | Supported via the tasks extension | Tools that rely on `ctx.elicit` or `ctx.list_roots` continue to work against clients on the session-based eras. On the modern era, elicitation is reachable through the multi-round "guard" pattern instead (a tool returns an `InputRequiredResult`; see the New entry below). Sampling is the exception: it is deprecated on every era and will not return on modern connections (see the Deprecated entry below). diff --git a/docs/development/v4-notes/feature-program.mdx b/docs/development/v4-notes/feature-program.mdx index 349bdf5a1..289a26778 100644 --- a/docs/development/v4-notes/feature-program.mdx +++ b/docs/development/v4-notes/feature-program.mdx @@ -11,7 +11,7 @@ The migration is the foundation. The forward v4 program is a sequence of post-me Code blocks marked as sketches show the *intended* API and do not resolve against the current tree. -## Sampling: deprecate now, remove in 4.0 +## Sampling removal **Status: Deprecation and era-gating shipped (#4448); removal slated for 4.0.** diff --git a/docs/development/v4-notes/index.mdx b/docs/development/v4-notes/index.mdx index d00bd570f..a320bb6e7 100644 --- a/docs/development/v4-notes/index.mdx +++ b/docs/development/v4-notes/index.mdx @@ -32,7 +32,9 @@ Following the pun-title convention (`v: `), the v4 line runs a sin | Release | Codename | The nod | | --- | --- | --- | | `4.0.0a1` (alpha) | **Fourst Contact** | _first contact_ — the first, cautious look at the new engine | +| `4.0.0a2` (alpha) | **Back and Fourth** | _back and forth_ — the second pass, where background tasks and stateless state land | | `4.0.0b1` (beta) | **Fourgone Conclusion** | _foregone conclusion_ — once the MCP SDK went v2, v4 was inevitable | +| `4.0.0b2` (beta) | **Fourmidable** | _formidable_ — held in reserve for a second beta if one is needed | | `4.0.0` (stable) | **Fast Fourward** | _fast forward_ — full speed onto the new foundation | ## How to read the register diff --git a/docs/development/v4-notes/protocol-2026.mdx b/docs/development/v4-notes/protocol-2026.mdx index dd8abc299..73b73ac38 100644 --- a/docs/development/v4-notes/protocol-2026.mdx +++ b/docs/development/v4-notes/protocol-2026.mdx @@ -4,7 +4,7 @@ title: 2026-07-28 Protocol Support FastMCP v4 serves the sessionless `2026-07-28` protocol era and the session-based handshake eras from a single server, with per-connection auto-detection. This page catalogs what FastMCP provides for the modern era — both the protocol machinery it inherits from the MCP Python SDK and the capabilities FastMCP implements itself on top of that layer. It is the reference for what a v4 deployment can actually do on the modern protocol today. -## Identity assertion (SEP-990): a complete server-side implementation +## Identity assertion (SEP-990) SEP-990 defines enterprise "on-behalf-of" access: a corporate identity provider (Okta, Microsoft Entra, etc.) issues a signed *ID-JAG* asserting an employee's identity, the employee's agent presents it at the MCP authorization server's token endpoint via the RFC 7523 `jwt-bearer` grant, and receives a short-lived access token — no browser login, no per-user consent screen, and revocation lives at the IdP. diff --git a/docs/getting-started/upgrading/from-fastmcp-3.mdx b/docs/getting-started/upgrading/from-fastmcp-3.mdx index b562c94c7..797632960 100644 --- a/docs/getting-started/upgrading/from-fastmcp-3.mdx +++ b/docs/getting-started/upgrading/from-fastmcp-3.mdx @@ -252,7 +252,7 @@ Sampling is the exception that does not come back, and the reason is the protoco | `ctx.list_roots` | Supported | Via the guard pattern (`input_requests` carries roots requests) | | `Middleware.on_initialize` | Runs on connect | Never runs — there is no `initialize` handshake | | Session state (`ctx.set_state` across calls) | Persists for the session | Does not persist — every request is a fresh connection | -| Tasks (via the FastMCP client) | Supported | Not yet | +| Background tasks (`task=True`) | Runs synchronously — never tasked | Supported via the tasks extension | If your tools rely on `ctx.elicit` or `ctx.list_roots`, they continue to work against clients on the earlier eras; on the modern era, reach for the guard pattern instead (see [Elicitation on the modern protocol](/servers/elicitation#elicitation-on-the-modern-protocol)). Sampling is deprecated on every era and will not return on modern connections — migrate those tools to server-side LLM calls. diff --git a/docs/getting-started/whats-new.mdx b/docs/getting-started/whats-new.mdx index c0a83dd59..f369be50d 100644 --- a/docs/getting-started/whats-new.mdx +++ b/docs/getting-started/whats-new.mdx @@ -8,7 +8,7 @@ icon: sparkles FastMCP 4 is a major version because its engine changed. The framework is now built on the MCP Python SDK v2, a ground-up rebuild of the protocol layer, and on that foundation it adds a new protocol era, first-class extensions, stateless state, enterprise identity, and more. Most FastMCP 3 servers run on it untouched — the major version signals how much moved underneath, and what that movement unlocks. -FastMCP 4 is in **alpha**. Everything below is available today except background tasks, which arrive in the next alpha. Pin an exact version and expect sharp edges. +FastMCP 4 is in **alpha**. Pin an exact version and expect sharp edges. ## Built on the MCP Python SDK v2 @@ -23,6 +23,8 @@ The rebuild also pulls the protocol's recent evolution forward in a single step. A FastMCP 4 server answers clients across the protocol transition from one deployment. The MCP SDK negotiates the era per connection — the sessionless `2026-07-28` protocol for clients that have moved forward, the session-based handshake for everyone else — and any replica behind a plain load balancer can serve a modern request. This supersedes FastMCP's earlier "latest protocol only" stance: you adopt the new protocol without forking your deployment or gating clients by version. +The same negotiation runs from the client, and its default flipped. A plain `Client(url)` now probes for the modern protocol and adopts it when the server offers it, falling back to the handshake otherwise — where every earlier FastMCP version pinned the handshake outright. That flip is what brings the modern capabilities within reach of ordinary client code: a task-enabled tool hands back a handle to poll, and multi-round-trip elicitation resolves across successive requests, neither requiring the caller to opt in. Set `mode="legacy"` to pin the handshake when you need the session-based back-channel or the classic `initialize` result. See [Protocol negotiation](/clients/client#protocol-negotiation). + The modern protocol is sessionless, so it drops the server's ability to call back into the client mid-request (SEP-2577). Imperative `ctx.elicit` and `ctx.list_roots` move to a request-shaped pattern on modern connections, and server-initiated sampling — which has no such replacement — is [deprecated](/servers/sampling). Everything else about writing a server is unchanged. ## State without a session @@ -33,7 +35,7 @@ Two shapes cover the cases. `UserSession` is injected like `Context` and keyed t ## Background tasks -Long-running work runs as a background task: the server accepts the call, returns a handle, and the client polls for the result while the work proceeds. Tasks left the core MCP spec during the SDK v2 rebuild and returned as the `io.modelcontextprotocol/tasks` extension (SEP-2663), which FastMCP 4 implements end to end in the optional `fastmcp-tasks` package. The durable execution engine that made FastMCP 3's tasks reliable carries straight over, and `@mcp.tool(task=True)` remains the only authoring surface — so the wire protocol modernizing underneath costs you no code change. See [Background Tasks](/development/v4-notes/background-tasks) for the design; the runtime arrives in the next alpha. +Long-running work runs as a background task: the server accepts the call, returns a handle, and the client polls for the result while the work proceeds. Tasks left the core MCP spec during the SDK v2 rebuild and returned as the `io.modelcontextprotocol/tasks` extension (SEP-2663), which FastMCP implements end to end in the optional `fastmcp-tasks` package. The durable execution engine that made FastMCP 3's tasks reliable — [Docket](https://github.com/chrisguidry/docket) — carries straight over, and `@mcp.tool(task=True)` remains the authoring surface, so the wire protocol modernizing underneath costs you no code change. See [Background Tasks](/servers/tasks). ## Server extensions diff --git a/docs/servers/middleware.mdx b/docs/servers/middleware.mdx index 09b9667e9..af7d17e42 100644 --- a/docs/servers/middleware.mdx +++ b/docs/servers/middleware.mdx @@ -84,7 +84,7 @@ parent.mount(child, namespace="child") Requests to `child_tool` flow through the parent's `AuthMiddleware` first, then through the child's `LoggingMiddleware`. -Middleware-stored state does not automatically cross mount boundaries. If `AuthMiddleware` on the parent calls `ctx.set_state("user_id", ...)`, a tool on the child server calling `ctx.get_state("user_id")` will get `None` — each `FastMCP` instance owns its own session state store. To share state across the mount, either pass the same `session_state_store` to both servers or use `serializable=False` for request-scoped values. See [State and Mounted Servers](/servers/context#state-and-mounted-servers) for details. +Middleware-stored state does not automatically cross mount boundaries. If `AuthMiddleware` on the parent calls `ctx.set_state("user_id", ...)`, a tool on the child server calling `ctx.get_state("user_id")` will get `None` — each `FastMCP` instance owns its own session state store. To share state across the mount, either pass the same `session_state_store` to both servers or use `serializable=False` for request-scoped values. See [Session State](/servers/sessions) for details. ## Hooks @@ -350,7 +350,7 @@ async def on_request(self, context: MiddlewareContext, call_next): return await call_next(context) ``` -For HTTP-specific data (headers, client IP) when using HTTP transports, see [HTTP Requests](/servers/context#http-requests). +For HTTP-specific data (headers, client IP) when using HTTP transports, see [HTTP Request](/servers/dependency-injection#http-request). ## Built-in Middleware @@ -819,7 +819,7 @@ def get_user_data(ctx: Context) -> str: return f"Data for user: {user_id}" ``` -See [Context State Management](/servers/context#state-management) for details. +See [Request State](/servers/context#request-state) for details. ### Constructor Parameters diff --git a/docs/servers/server.mdx b/docs/servers/server.mdx index 71bd425b4..9f6dbe8fa 100644 --- a/docs/servers/server.mdx +++ b/docs/servers/server.mdx @@ -175,7 +175,7 @@ These parameters tune how the server processes requests and communicates with cl - When `False` (default), FastMCP uses Pydantic's flexible validation that coerces compatible inputs (e.g., `"10"` → `10` for int parameters). When `True`, validates inputs against the exact JSON Schema before calling your function, rejecting type mismatches. See [Input Validation Modes](/servers/tools#input-validation-modes) for details + When `False` (default), FastMCP uses Pydantic's flexible validation that coerces compatible inputs (e.g., `"10"` → `10` for int parameters). When `True`, validates inputs against the exact JSON Schema before calling your function, rejecting type mismatches. See [Validation Modes](/servers/tools#validation-modes) for details