mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-23 05:54:19 +02:00
v4 docs quality pass: stale task/era claims, broken links, polish (#4619)
* v4 docs quality pass: fix stale task/era claims, broken links, writing polish * whats-new: add the client-side protocol negotiation story The page told the server half of the era story (serves every era) but never the client half — that a default Client(url) now negotiates the modern era, where earlier versions pinned the handshake. Completes the mental model and links to the client negotiation docs. * Address review: drop 'complete' over-claim; link mounted-state to Session State
This commit is contained in:
parent
078c44d835
commit
f896f5acb5
10 changed files with 18 additions and 12 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
||||
|
|
|
|||
|
|
@ -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.**
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,9 @@ Following the pun-title convention (`v<version>: <pun>`), 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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
<Note>
|
||||
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.
|
||||
</Note>
|
||||
|
||||
## 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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ These parameters tune how the server processes requests and communicates with cl
|
|||
<ParamField body="strict_input_validation" type="bool" default="False">
|
||||
<VersionBadge version="2.13.0" />
|
||||
|
||||
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
|
||||
</ParamField>
|
||||
|
||||
<ParamField body="mask_error_details" type="bool | None">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue