From 803da5319cacf679d75a58a30fe2f069c24a8773 Mon Sep 17 00:00:00 2001
From: "marvin-context-protocol[bot]"
<225465937+marvin-context-protocol[bot]@users.noreply.github.com>
Date: Thu, 6 Aug 2026 19:56:40 -0400
Subject: [PATCH] chore: Update SDK documentation (#4679)
---
docs/python-sdk-pages.json | 23 +
docs/python-sdk/fastmcp-apps-app.mdx | 20 +-
docs/python-sdk/fastmcp-apps-config.mdx | 35 +-
docs/python-sdk/fastmcp-exceptions.mdx | 36 +-
docs/python-sdk/fastmcp-mcp_config.mdx | 38 +-
docs/python-sdk/fastmcp-server-caching.mdx | 48 +
.../python-sdk/fastmcp-server-completions.mdx | 41 +
docs/python-sdk/fastmcp-server-context.mdx | 711 ++++++++++++++
.../fastmcp-server-dependencies.mdx | 614 ++++++++++++
.../python-sdk/fastmcp-server-elicitation.mdx | 152 +++
.../python-sdk/fastmcp-server-event_store.mdx | 78 ++
docs/python-sdk/fastmcp-server-extensions.mdx | 194 ++++
docs/python-sdk/fastmcp-server-http.mdx | 144 +++
docs/python-sdk/fastmcp-server-lifespan.mdx | 101 ++
docs/python-sdk/fastmcp-server-low_level.mdx | 106 +++
docs/python-sdk/fastmcp-server-mixins.mdx | 9 +
docs/python-sdk/fastmcp-server-providers.mdx | 34 +
docs/python-sdk/fastmcp-server-server.mdx | 891 ++++++++++++++++++
...tmcp-server-session_scoped_event_store.mdx | 31 +
docs/python-sdk/fastmcp-server-sessions.mdx | 319 +++++++
docs/python-sdk/fastmcp-server-telemetry.mdx | 117 +++
docs/python-sdk/fastmcp-server-transforms.mdx | 193 ++++
docs/python-sdk/fastmcp-settings.mdx | 8 +-
docs/python-sdk/fastmcp-telemetry.mdx | 70 +-
.../fastmcp-utilities-docstring_parsing.mdx | 4 +-
.../fastmcp-utilities-exceptions.mdx | 44 +-
docs/python-sdk/fastmcp-utilities-inspect.mdx | 10 +-
.../fastmcp-utilities-json_schema.mdx | 18 +-
docs/python-sdk/fastmcp-utilities-logging.mdx | 6 +-
docs/python-sdk/fastmcp-utilities-prefab.mdx | 61 ++
30 files changed, 4066 insertions(+), 90 deletions(-)
create mode 100644 docs/python-sdk/fastmcp-server-caching.mdx
create mode 100644 docs/python-sdk/fastmcp-server-completions.mdx
create mode 100644 docs/python-sdk/fastmcp-server-context.mdx
create mode 100644 docs/python-sdk/fastmcp-server-dependencies.mdx
create mode 100644 docs/python-sdk/fastmcp-server-elicitation.mdx
create mode 100644 docs/python-sdk/fastmcp-server-event_store.mdx
create mode 100644 docs/python-sdk/fastmcp-server-extensions.mdx
create mode 100644 docs/python-sdk/fastmcp-server-http.mdx
create mode 100644 docs/python-sdk/fastmcp-server-lifespan.mdx
create mode 100644 docs/python-sdk/fastmcp-server-low_level.mdx
create mode 100644 docs/python-sdk/fastmcp-server-mixins.mdx
create mode 100644 docs/python-sdk/fastmcp-server-providers.mdx
create mode 100644 docs/python-sdk/fastmcp-server-server.mdx
create mode 100644 docs/python-sdk/fastmcp-server-session_scoped_event_store.mdx
create mode 100644 docs/python-sdk/fastmcp-server-sessions.mdx
create mode 100644 docs/python-sdk/fastmcp-server-telemetry.mdx
create mode 100644 docs/python-sdk/fastmcp-server-transforms.mdx
create mode 100644 docs/python-sdk/fastmcp-utilities-prefab.mdx
diff --git a/docs/python-sdk-pages.json b/docs/python-sdk-pages.json
index eb525313d..32abc995c 100644
--- a/docs/python-sdk-pages.json
+++ b/docs/python-sdk-pages.json
@@ -31,6 +31,28 @@
}
]
},
+ {
+ "group": "fastmcp.server",
+ "pages": [
+ "python-sdk/fastmcp-server-caching",
+ "python-sdk/fastmcp-server-completions",
+ "python-sdk/fastmcp-server-context",
+ "python-sdk/fastmcp-server-dependencies",
+ "python-sdk/fastmcp-server-elicitation",
+ "python-sdk/fastmcp-server-event_store",
+ "python-sdk/fastmcp-server-extensions",
+ "python-sdk/fastmcp-server-http",
+ "python-sdk/fastmcp-server-lifespan",
+ "python-sdk/fastmcp-server-low_level",
+ "python-sdk/fastmcp-server-mixins",
+ "python-sdk/fastmcp-server-providers",
+ "python-sdk/fastmcp-server-server",
+ "python-sdk/fastmcp-server-session_scoped_event_store",
+ "python-sdk/fastmcp-server-sessions",
+ "python-sdk/fastmcp-server-telemetry",
+ "python-sdk/fastmcp-server-transforms"
+ ]
+ },
{
"group": "fastmcp.utilities",
"pages": [
@@ -79,6 +101,7 @@
"python-sdk/fastmcp-utilities-mime",
"python-sdk/fastmcp-utilities-openapi",
"python-sdk/fastmcp-utilities-pagination",
+ "python-sdk/fastmcp-utilities-prefab",
"python-sdk/fastmcp-utilities-skills",
"python-sdk/fastmcp-utilities-tasks",
"python-sdk/fastmcp-utilities-tests",
diff --git a/docs/python-sdk/fastmcp-apps-app.mdx b/docs/python-sdk/fastmcp-apps-app.mdx
index 99dc73528..4d2e8a421 100644
--- a/docs/python-sdk/fastmcp-apps-app.mdx
+++ b/docs/python-sdk/fastmcp-apps-app.mdx
@@ -35,7 +35,7 @@ Usage::
## Classes
-### `FastMCPApp`
+### `FastMCPApp`
A Provider that represents an MCP application.
@@ -48,19 +48,19 @@ can find them by original name even when transforms have been applied.
**Methods:**
-#### `tool`
+#### `tool`
```python
tool(self, name_or_fn: F) -> F
```
-#### `tool`
+#### `tool`
```python
tool(self, name_or_fn: str | None = None) -> Callable[[F], F]
```
-#### `tool`
+#### `tool`
```python
tool(self, name_or_fn: str | AnyFunction | None = None) -> Any
@@ -83,19 +83,19 @@ Supports multiple calling patterns::
def save(name: str): ...
-#### `ui`
+#### `ui`
```python
ui(self, name_or_fn: F) -> F
```
-#### `ui`
+#### `ui`
```python
ui(self, name_or_fn: str | None = None) -> Callable[[F], F]
```
-#### `ui`
+#### `ui`
```python
ui(self, name_or_fn: str | AnyFunction | None = None) -> Any
@@ -119,7 +119,7 @@ Supports multiple calling patterns::
def dashboard() -> Component: ...
-#### `add_tool`
+#### `add_tool`
```python
add_tool(self, tool: Tool | Callable[..., Any]) -> Tool
@@ -130,13 +130,13 @@ Add a tool to this app programmatically.
The tool is tagged with this app's name for routing.
-#### `lifespan`
+#### `lifespan`
```python
lifespan(self) -> AsyncIterator[None]
```
-#### `run`
+#### `run`
```python
run(self, transport: Literal['stdio', 'http', 'sse', 'streamable-http'] | None = None, **kwargs: Any) -> None
diff --git a/docs/python-sdk/fastmcp-apps-config.mdx b/docs/python-sdk/fastmcp-apps-config.mdx
index 9d0c3acf1..a7b9d6151 100644
--- a/docs/python-sdk/fastmcp-apps-config.mdx
+++ b/docs/python-sdk/fastmcp-apps-config.mdx
@@ -15,7 +15,7 @@ UI metadata for clients that support interactive app rendering.
## Functions
-### `app_config_to_meta_dict`
+### `app_config_to_meta_dict`
```python
app_config_to_meta_dict(app: AppConfig | dict[str, Any]) -> dict[str, Any]
@@ -25,9 +25,32 @@ app_config_to_meta_dict(app: AppConfig | dict[str, Any]) -> dict[str, Any]
Convert an AppConfig or dict to the wire-format dict for ``meta["ui"]``.
+### `is_model_visible`
+
+```python
+is_model_visible(component: FastMCPComponent) -> bool
+```
+
+
+Whether a component may be shown to, or invoked by, the model.
+
+Visibility is a declaration, and the MCP Apps spec puts the filtering on
+the host — so ``tools/list`` carries app-only tools and the host keeps
+them from the model. That division only works where a host stands between
+the server and the model.
+
+It does not hold for surfaces a server drives itself. A search result or
+a code-mode catalog reaches the model as ordinary tool output, and a
+call-tool proxy invokes on a name the model supplies; nothing downstream
+can filter either. Those surfaces have to apply the declaration here.
+
+A component with no ``visibility`` is visible: the field marks the
+exception, and the spec's default is both audiences.
+
+
## Classes
-### `ResourceCSP`
+### `ResourceCSP`
Content Security Policy for MCP App resources.
@@ -37,7 +60,7 @@ load resources from. Hosts use these declarations to build the
``Content-Security-Policy`` header for the sandboxed iframe.
-### `ResourcePermissions`
+### `ResourcePermissions`
Iframe sandbox permissions for MCP App resources.
@@ -48,7 +71,7 @@ iframe. Hosts MAY honour these; apps should use JS feature detection
as a fallback.
-### `AppConfig`
+### `AppConfig`
Configuration for MCP App tools and resources.
@@ -63,7 +86,7 @@ values appear on the wire. Aliases match the MCP Apps wire format
(camelCase).
-### `PrefabAppConfig`
+### `PrefabAppConfig`
App configuration for Prefab tools with sensible defaults.
@@ -83,7 +106,7 @@ Example::
**Methods:**
-#### `model_post_init`
+#### `model_post_init`
```python
model_post_init(self, __context: Any) -> None
diff --git a/docs/python-sdk/fastmcp-exceptions.mdx b/docs/python-sdk/fastmcp-exceptions.mdx
index a6ef59df9..151f0f10a 100644
--- a/docs/python-sdk/fastmcp-exceptions.mdx
+++ b/docs/python-sdk/fastmcp-exceptions.mdx
@@ -10,7 +10,7 @@ Custom exceptions for FastMCP.
## Functions
-### `to_mcp_error`
+### `to_mcp_error`
```python
to_mcp_error(exc: Exception) -> MCPError
@@ -38,71 +38,61 @@ explicit code chosen upstream survives translation.
## Classes
-### `FastMCPDeprecationWarning`
-
-
-Deprecation warning for FastMCP APIs.
-
-Subclass of DeprecationWarning so that standard warning filters
-still apply, but FastMCP can selectively enable its own warnings
-without affecting other libraries in the process.
-
-
-### `FastMCPError`
+### `FastMCPError`
Base error for FastMCP.
-### `ValidationError`
+### `ValidationError`
Error in validating parameters or return values.
-### `ResourceError`
+### `ResourceError`
Error in resource operations.
-### `ToolError`
+### `ToolError`
Error in tool operations.
-### `PromptError`
+### `PromptError`
Error in prompt operations.
-### `InvalidSignature`
+### `InvalidSignature`
Invalid signature for use with FastMCP.
-### `ClientError`
+### `ClientError`
Error in client operations.
-### `NotFoundError`
+### `NotFoundError`
Object not found.
-### `DisabledError`
+### `DisabledError`
Object is disabled.
-### `ResourceSecurityError`
+### `ResourceSecurityError`
A templated resource parameter failed path-security screening.
@@ -114,13 +104,13 @@ for a resource that does not exist, and never reveals which parameter
or policy tripped.
-### `AuthorizationError`
+### `AuthorizationError`
Error when authorization check fails.
-### `InsufficientScopeError`
+### `InsufficientScopeError`
Authorization failed because the token is missing required OAuth scopes.
diff --git a/docs/python-sdk/fastmcp-mcp_config.mdx b/docs/python-sdk/fastmcp-mcp_config.mdx
index 44e287d46..70f0978ff 100644
--- a/docs/python-sdk/fastmcp-mcp_config.mdx
+++ b/docs/python-sdk/fastmcp-mcp_config.mdx
@@ -32,7 +32,7 @@ Example configuration:
## Functions
-### `infer_transport_type_from_url`
+### `infer_transport_type_from_url`
```python
infer_transport_type_from_url(url: str | AnyUrl) -> Literal['http', 'sse']
@@ -42,7 +42,7 @@ infer_transport_type_from_url(url: str | AnyUrl) -> Literal['http', 'sse']
Infer the appropriate transport type from the given URL.
-### `update_config_file`
+### `update_config_file`
```python
update_config_file(file_path: Path, server_name: str, server_config: CanonicalMCPServerTypes) -> None
@@ -57,7 +57,7 @@ worry about transforming server objects here.
## Classes
-### `StdioMCPServer`
+### `StdioMCPServer`
MCP server configuration for stdio transport.
@@ -67,19 +67,19 @@ This is the canonical configuration format for MCP servers using stdio transport
**Methods:**
-#### `to_transport`
+#### `to_transport`
```python
-to_transport(self) -> StdioTransport
+to_transport(self) -> StdioTransport | FastMCPTransport
```
-### `TransformingStdioMCPServer`
+### `TransformingStdioMCPServer`
A Stdio server with tool transforms.
-### `RemoteMCPServer`
+### `RemoteMCPServer`
MCP server configuration for HTTP/SSE transport.
@@ -89,19 +89,19 @@ This is the canonical configuration format for MCP servers using remote transpor
**Methods:**
-#### `to_transport`
+#### `to_transport`
```python
-to_transport(self) -> StreamableHttpTransport | SSETransport
+to_transport(self) -> StreamableHttpTransport | SSETransport | FastMCPTransport
```
-### `TransformingRemoteMCPServer`
+### `TransformingRemoteMCPServer`
A Remote server with tool transforms.
-### `MCPConfig`
+### `MCPConfig`
A configuration object for MCP Servers that conforms to the canonical MCP configuration format
@@ -113,7 +113,7 @@ For an MCPConfig that is strictly canonical, see the `CanonicalMCPConfig` class.
**Methods:**
-#### `wrap_servers_at_root`
+#### `wrap_servers_at_root`
```python
wrap_servers_at_root(cls, values: dict[str, Any]) -> dict[str, Any]
@@ -122,7 +122,7 @@ wrap_servers_at_root(cls, values: dict[str, Any]) -> dict[str, Any]
If there's no mcpServers key but there are server configs at root, wrap them.
-#### `add_server`
+#### `add_server`
```python
add_server(self, name: str, server: MCPServerTypes) -> None
@@ -131,7 +131,7 @@ add_server(self, name: str, server: MCPServerTypes) -> None
Add or update a server in the configuration.
-#### `from_dict`
+#### `from_dict`
```python
from_dict(cls, config: dict[str, Any]) -> Self
@@ -140,7 +140,7 @@ from_dict(cls, config: dict[str, Any]) -> Self
Parse MCP configuration from dictionary format.
-#### `to_dict`
+#### `to_dict`
```python
to_dict(self) -> dict[str, Any]
@@ -149,7 +149,7 @@ to_dict(self) -> dict[str, Any]
Convert MCPConfig to dictionary format, preserving all fields.
-#### `write_to_file`
+#### `write_to_file`
```python
write_to_file(self, file_path: Path) -> None
@@ -158,7 +158,7 @@ write_to_file(self, file_path: Path) -> None
Write configuration to JSON file.
-#### `from_file`
+#### `from_file`
```python
from_file(cls, file_path: Path) -> Self
@@ -167,7 +167,7 @@ from_file(cls, file_path: Path) -> Self
Load configuration from JSON file.
-### `CanonicalMCPConfig`
+### `CanonicalMCPConfig`
Canonical MCP configuration format.
@@ -178,7 +178,7 @@ The format is designed to be client-agnostic and extensible for future use cases
**Methods:**
-#### `add_server`
+#### `add_server`
```python
add_server(self, name: str, server: CanonicalMCPServerTypes) -> None
diff --git a/docs/python-sdk/fastmcp-server-caching.mdx b/docs/python-sdk/fastmcp-server-caching.mdx
new file mode 100644
index 000000000..d4e76a033
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-caching.mdx
@@ -0,0 +1,48 @@
+---
+title: caching
+sidebarTitle: caching
+---
+
+# `fastmcp.server.caching`
+
+
+Server-level cache hints for FastMCP (SEP-2549).
+
+A FastMCP server opts every SDK-cacheable result it emits into client-side
+caching by setting `cache_ttl` (seconds) and, optionally, `cache_scope` on the
+`FastMCP` constructor. The hint is uniform by construction: one server-level
+value applies to `tools/list`, `prompts/list`, `resources/list`,
+`resources/templates/list`, `resources/read`, and `server/discover` alike — no
+per-component surface and no aggregation.
+
+FastMCP does not hand-set the wire fields. It passes the hint through to the SDK
+low-level `Server(cache_hints=...)`, whose runner fills `ttlMs`/`cacheScope` on
+every cacheable result via `apply_cache_hint`, leaving any field a handler set
+explicitly untouched. Honoring is modern-only and opt-in on the client: a hinted
+server is inert unless the client passes `cache=` and negotiates `2026-07-28`.
+
+
+## Functions
+
+### `build_cache_hints`
+
+```python
+build_cache_hints(cache_ttl: int | None, cache_scope: CacheScope | None) -> dict[CacheableMethod, CacheHint] | None
+```
+
+
+Build the per-method `CacheHint` map for the SDK low-level server.
+
+`cache_ttl` is in seconds and is converted to the wire's milliseconds. When
+`cache_ttl` is `None` the server emits no hint, so its wire output is
+identical to a server that never set one; a `cache_scope` given without a
+`cache_ttl` is meaningless (the client gates caching on the presence of a
+TTL) and is rejected rather than silently ignored.
+
+Returns `None` when no hint is set, or a map applying the same hint to every
+SDK-cacheable method otherwise.
+
+**Raises:**
+- `ValueError`: If `cache_ttl` is not positive, or if `cache_scope` is set
+without `cache_ttl`.
+
diff --git a/docs/python-sdk/fastmcp-server-completions.mdx b/docs/python-sdk/fastmcp-server-completions.mdx
new file mode 100644
index 000000000..dcea2c00d
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-completions.mdx
@@ -0,0 +1,41 @@
+---
+title: completions
+sidebarTitle: completions
+---
+
+# `fastmcp.server.completions`
+
+
+Server-side argument completion for FastMCP.
+
+A completion request names a reference — a specific prompt or resource
+template — and the argument being completed, plus a context of the argument
+values already supplied. The server answers with candidate string values.
+
+FastMCP surfaces this as a single server-level handler registered with
+``@mcp.completion``, mirroring the MCP SDK's own ``completion/complete`` shape
+and FastMCP's client-side ``Client.complete()``. The handler receives the
+reference, the argument, and the optional context, and returns candidates for
+whichever reference/argument pair it recognizes.
+
+
+## Functions
+
+### `normalize_completion`
+
+```python
+normalize_completion(result: CompletionValues) -> mcp_types.Completion
+```
+
+
+Coerce a handler's return value into a wire ``Completion``.
+
+A returned ``str`` is rejected: it is almost always a mistake (the value
+would iterate into one-character candidates), so it raises rather than
+silently producing surprising output.
+
+The MCP contract caps a completion at 100 values, so a longer result is
+truncated to the first 100 with ``has_more`` set — a handler that returns
+thousands of matches emits a conforming response rather than an oversized
+one that strict clients reject.
+
diff --git a/docs/python-sdk/fastmcp-server-context.mdx b/docs/python-sdk/fastmcp-server-context.mdx
new file mode 100644
index 000000000..a9d766b6b
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-context.mdx
@@ -0,0 +1,711 @@
+---
+title: context
+sidebarTitle: context
+---
+
+# `fastmcp.server.context`
+
+## Functions
+
+### `set_transport`
+
+```python
+set_transport(transport: TransportType) -> Token[TransportType | None]
+```
+
+
+Set the current transport type. Returns token for reset.
+
+
+### `reset_transport`
+
+```python
+reset_transport(token: Token[TransportType | None]) -> None
+```
+
+
+Reset transport to previous value.
+
+
+### `set_context`
+
+```python
+set_context(context: Context) -> Generator[Context, None, None]
+```
+
+## Classes
+
+### `LogData`
+
+
+Data object for passing log arguments to client-side handlers.
+
+This provides an interface to match the Python standard library logging,
+for compatibility with structured logging.
+
+
+### `Context`
+
+
+Context object providing access to MCP capabilities.
+
+This provides a cleaner interface to MCP's RequestContext functionality.
+It gets injected into tool and resource functions that request it via type hints.
+
+To use context in a tool function, add a parameter with the Context type annotation:
+
+```python
+@server.tool
+async def my_tool(x: int, ctx: Context) -> str:
+ # Log messages to the client
+ await ctx.info(f"Processing {x}")
+ await ctx.debug("Debug info")
+ await ctx.warning("Warning message")
+ await ctx.error("Error message")
+
+ # Report progress
+ await ctx.report_progress(50, 100, "Processing")
+
+ # Access resources
+ data = await ctx.read_resource("resource://data")
+
+ # Get request info
+ request_id = ctx.request_id
+ client_id = ctx.client_id
+
+ # Manage state across the session (persists across requests)
+ await ctx.set_state("key", "value")
+ value = await ctx.get_state("key")
+
+ # Store non-serializable values for the current request only
+ await ctx.set_state("client", http_client, serializable=False)
+
+ return str(x)
+```
+
+State Management:
+Context provides session-scoped state that persists across requests within
+the same MCP session. State is automatically keyed by session, ensuring
+isolation between different clients.
+
+State set during `on_initialize` middleware will persist to subsequent tool
+calls when using the same session object (STDIO, SSE, single-server HTTP).
+For distributed/serverless HTTP deployments where different machines handle
+the init and tool calls, state is isolated by the mcp-session-id header.
+
+The context parameter name can be anything as long as it's annotated with Context.
+The context is optional - tools that don't need it can omit the parameter.
+
+
+**Methods:**
+
+#### `is_background_task`
+
+```python
+is_background_task(self) -> bool
+```
+
+True when this context is running in a background task (Docket worker).
+
+When True, certain operations like elicit() will use task-aware
+implementations that can pause the task and wait for client input.
+
+
+#### `task_id`
+
+```python
+task_id(self) -> str | None
+```
+
+Get the background task ID if running in a background task.
+
+Returns None if not running in a background task context.
+
+
+#### `origin_request_id`
+
+```python
+origin_request_id(self) -> str | None
+```
+
+Get the request ID that originated this execution, if available.
+
+In foreground request mode, this is the current request_id.
+In background task mode, this is the request_id captured when the task
+was submitted, if one was available.
+
+
+#### `fastmcp`
+
+```python
+fastmcp(self) -> FastMCP
+```
+
+Get the FastMCP instance.
+
+
+#### `request_context`
+
+```python
+request_context(self) -> FastMCPRequestContext | None
+```
+
+Access to the underlying request context.
+
+Returns None when the MCP session has not been established yet.
+Returns the FastMCPRequestContext wrapper once the MCP session is available.
+
+For HTTP request access in middleware, use `get_http_request()` from fastmcp.server.dependencies,
+which works whether or not the MCP session is available.
+
+Example in middleware:
+```python
+async def on_request(self, context, call_next):
+ ctx = context.fastmcp_context
+ if ctx.request_context:
+ # MCP session available - can access session_id, request_id, etc.
+ session_id = ctx.session_id
+ else:
+ # MCP session not available yet - use HTTP helpers
+ from fastmcp.server.dependencies import get_http_request
+ request = get_http_request()
+ return await call_next(context)
+```
+
+
+#### `client_extension_settings`
+
+```python
+client_extension_settings(self, identifier: str) -> dict[str, Any] | None
+```
+
+This request's per-request opt-in settings for an MCP extension.
+
+SEP-2133 extensions negotiate per request: the client repeats its
+extension capabilities in each request's ``_meta`` under
+``io.modelcontextprotocol/clientCapabilities`` → ``extensions`` →
+``identifier``. Returns the declared settings dict (possibly empty) when
+the extension was opted in for this request, or ``None`` when it was
+not (or there is no active request). This bridges an extension's
+``tools/call`` interceptor — which receives a FastMCP ``Context`` — to
+the request's declared client capabilities.
+
+
+#### `input_responses`
+
+```python
+input_responses(self) -> mcp_types.InputResponses | None
+```
+
+Client responses to a prior `InputRequiredResult.input_requests`.
+
+The multi-round-trip guard channel (SEP-2322). A guard tool inspects
+this to decide what to do on each round: `None` on the initial round
+(nothing has been asked yet, or the client retried without responses),
+so the tool returns an `InputRequiredResult` to ask; present on a later
+round, so the tool reads the answers and proceeds. It is a mapping whose
+keys match the `input_requests` map the tool minted; each value is the
+client's result for that request (an `ElicitResult`, `CreateMessageResult`,
+or `ListRootsResult`).
+
+In a background task there is no wire request, so this falls back to the
+responses the in-task guard loop delivered (see the tasks extension).
+
+
+#### `request_state`
+
+```python
+request_state(self) -> str | None
+```
+
+Opaque state echoed from a prior `InputRequiredResult.request_state`.
+
+The multi-round-trip guard channel (SEP-2322): whatever a tool put in
+`InputRequiredResult.request_state` on an earlier round is handed back
+here (as plaintext — the framework seals it on the wire and unseals it
+before the tool runs, so tampering is rejected before this is read).
+`None` on the initial round. Use it to carry a small amount of computed
+state across rounds without re-deriving it.
+
+In a background task there is no wire request, so this falls back to the
+state the in-task guard loop re-injected (see the tasks extension).
+
+
+#### `lifespan_context`
+
+```python
+lifespan_context(self) -> dict[str, Any]
+```
+
+Access the server's lifespan context.
+
+Returns the context dict yielded by *this* server's lifespan function.
+For a mounted child this is the child's own lifespan, not the parent's
+— the MCP session always belongs to the parent, so reading from the
+request context would return the parent's. We read directly from the
+server's cached lifespan result instead, which is set by the
+per-server ``_lifespan_manager`` regardless of mount position.
+
+Returns an empty dict if no lifespan was configured.
+
+Example:
+```python
+@server.tool
+def my_tool(ctx: Context) -> str:
+ db = ctx.lifespan_context.get("db")
+ if db:
+ return db.query("SELECT 1")
+ return "No database connection"
+```
+
+
+#### `report_progress`
+
+```python
+report_progress(self, progress: float, total: float | None = None, message: str | None = None) -> None
+```
+
+Report progress for the current operation.
+
+Works in both foreground (MCP progress notifications) and background
+(Docket task execution) contexts.
+
+**Args:**
+- `progress`: Current progress value e.g. 24
+- `total`: Optional total value e.g. 100
+- `message`: Optional status message describing current progress
+
+
+#### `list_resources`
+
+```python
+list_resources(self) -> list[SDKResource]
+```
+
+List all available resources from the server.
+
+**Returns:**
+- List of Resource objects available on the server
+
+
+#### `list_prompts`
+
+```python
+list_prompts(self) -> list[SDKPrompt]
+```
+
+List all available prompts from the server.
+
+**Returns:**
+- List of Prompt objects available on the server
+
+
+#### `get_prompt`
+
+```python
+get_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> GetPromptResult
+```
+
+Get a prompt by name with optional arguments.
+
+**Args:**
+- `name`: The name of the prompt to get
+- `arguments`: Optional arguments to pass to the prompt
+
+**Returns:**
+- The prompt result
+
+
+#### `read_resource`
+
+```python
+read_resource(self, uri: str | AnyUrl) -> ResourceResult
+```
+
+Read a resource by URI.
+
+**Args:**
+- `uri`: Resource URI to read
+
+**Returns:**
+- ResourceResult with contents
+
+
+#### `log`
+
+```python
+log(self, message: str, level: LoggingLevel | None = None, logger_name: str | None = None, extra: Mapping[str, Any] | None = None) -> None
+```
+
+Send a log message to the client.
+
+Messages sent to Clients are also logged to the `fastmcp.server.context.to_client` logger with a level of `DEBUG`.
+
+**Args:**
+- `message`: Log message
+- `level`: Optional log level. One of "debug", "info", "notice", "warning", "error", "critical",
+"alert", or "emergency". Default is "info".
+- `logger_name`: Optional logger name
+- `extra`: Optional mapping for additional arguments
+
+
+#### `transport`
+
+```python
+transport(self) -> TransportType | None
+```
+
+Get the current transport type.
+
+Returns the transport type used to run this server: "stdio", "sse",
+or "streamable-http". Returns None if called outside of a server context.
+
+
+#### `client_supports_extension`
+
+```python
+client_supports_extension(self, extension_id: str) -> bool
+```
+
+Check whether the connected client supports a given MCP extension.
+
+Inspects the ``extensions`` extra field on ``ClientCapabilities``
+sent by the client during initialization.
+
+Reads the client's advertised capabilities from the session, which is
+available in request mode and in background-task mode (where the
+snapshot session preserves the client's initialize params). Returns
+``False`` when no session is available (e.g., a distributed worker with
+no live session, or outside any context) or when the client did not
+advertise the extension.
+
+Example::
+
+ from fastmcp.apps.config import UI_EXTENSION_ID
+
+ @mcp.tool
+ async def my_tool(ctx: Context) -> str:
+ if ctx.client_supports_extension(UI_EXTENSION_ID):
+ return "UI-capable client"
+ return "text-only client"
+
+
+#### `client_id`
+
+```python
+client_id(self) -> str | None
+```
+
+Get the client ID if available.
+
+
+#### `request_id`
+
+```python
+request_id(self) -> str
+```
+
+Get the unique ID for this request.
+
+Raises RuntimeError if MCP request context is not available.
+
+
+#### `session_id`
+
+```python
+session_id(self) -> str
+```
+
+Get the MCP session ID for ALL transports.
+
+Returns the session ID that can be used as a key for session-based
+data storage (e.g., Redis) to share data between tool calls within
+the same client session.
+
+**Returns:**
+- The session ID for StreamableHTTP transports, or a generated ID
+- for other transports.
+
+
+#### `session`
+
+```python
+session(self) -> ServerSession
+```
+
+Access to the underlying session for advanced usage.
+
+In request mode: Returns the session from the active request context.
+In background task mode: Returns the session stored at Context creation.
+
+Raises RuntimeError if no session is available.
+
+
+#### `debug`
+
+```python
+debug(self, message: str, logger_name: str | None = None, extra: Mapping[str, Any] | None = None) -> None
+```
+
+Send a `DEBUG`-level message to the connected MCP Client.
+
+Messages sent to Clients are also logged to the `fastmcp.server.context.to_client` logger with a level of `DEBUG`.
+
+
+#### `info`
+
+```python
+info(self, message: str, logger_name: str | None = None, extra: Mapping[str, Any] | None = None) -> None
+```
+
+Send a `INFO`-level message to the connected MCP Client.
+
+Messages sent to Clients are also logged to the `fastmcp.server.context.to_client` logger with a level of `DEBUG`.
+
+
+#### `warning`
+
+```python
+warning(self, message: str, logger_name: str | None = None, extra: Mapping[str, Any] | None = None) -> None
+```
+
+Send a `WARNING`-level message to the connected MCP Client.
+
+Messages sent to Clients are also logged to the `fastmcp.server.context.to_client` logger with a level of `DEBUG`.
+
+
+#### `error`
+
+```python
+error(self, message: str, logger_name: str | None = None, extra: Mapping[str, Any] | None = None) -> None
+```
+
+Send a `ERROR`-level message to the connected MCP Client.
+
+Messages sent to Clients are also logged to the `fastmcp.server.context.to_client` logger with a level of `DEBUG`.
+
+
+#### `send_notification`
+
+```python
+send_notification(self, notification: mcp_types.ServerNotification) -> None
+```
+
+Send a notification to the client immediately.
+
+**Args:**
+- `notification`: An MCP notification instance (e.g., ToolListChangedNotification())
+
+
+#### `close_sse_stream`
+
+```python
+close_sse_stream(self) -> None
+```
+
+Close the current response stream to trigger client reconnection.
+
+When using StreamableHTTP transport with an EventStore configured, this
+method gracefully closes the HTTP connection for the current request.
+The client will automatically reconnect (after `retry_interval` milliseconds)
+and resume receiving events from where it left off via the EventStore.
+
+This is useful for long-running operations to avoid load balancer timeouts.
+Instead of holding a connection open for minutes, you can periodically close
+and let the client reconnect.
+
+
+#### `elicit`
+
+```python
+elicit(self, message: str, response_type: type[T]) -> AcceptedElicitation[T] | DeclinedElicitation | CancelledElicitation
+```
+
+The accepted elicitation will contain the response data
+
+
+#### `elicit`
+
+```python
+elicit(self, message: str, response_type: list[str]) -> AcceptedElicitation[str] | DeclinedElicitation | CancelledElicitation
+```
+
+When response_type is a list of strings, the accepted elicitation will
+contain the selected string response
+
+
+#### `elicit`
+
+```python
+elicit(self, message: str, response_type: dict[str, dict[str, str]]) -> AcceptedElicitation[str] | DeclinedElicitation | CancelledElicitation
+```
+
+When response_type is a dict mapping keys to title dicts, the accepted
+elicitation will contain the selected key
+
+
+#### `elicit`
+
+```python
+elicit(self, message: str, response_type: list[list[str]]) -> AcceptedElicitation[list[str]] | DeclinedElicitation | CancelledElicitation
+```
+
+When response_type is a list containing a list of strings (multi-select),
+the accepted elicitation will contain a list of selected strings
+
+
+#### `elicit`
+
+```python
+elicit(self, message: str, response_type: list[dict[str, dict[str, str]]]) -> AcceptedElicitation[list[str]] | DeclinedElicitation | CancelledElicitation
+```
+
+When response_type is a list containing a dict mapping keys to title dicts
+(multi-select with titles), the accepted elicitation will contain a list of
+selected keys
+
+
+#### `elicit`
+
+```python
+elicit(self, message: str, response_type: type[T] | list[str] | dict[str, dict[str, str]] | list[list[str]] | list[dict[str, dict[str, str]]]) -> AcceptedElicitation[T] | AcceptedElicitation[dict[str, Any]] | AcceptedElicitation[str] | AcceptedElicitation[list[str]] | DeclinedElicitation | CancelledElicitation
+```
+
+Send an elicitation request to the client and await the response.
+
+Call this method at any time to request additional information from
+the user through the client. The client must support elicitation,
+or the request will error.
+
+Note that the MCP protocol only supports simple object schemas with
+primitive types. You can provide a dataclass, TypedDict, or BaseModel to
+comply. If you provide a primitive type, an object schema with a single
+"value" field will be generated for the MCP interaction and
+automatically deconstructed into the primitive type upon response.
+
+``response_type`` is required. Pass ``bool`` when all you need is a
+confirmation; an empty schema leaves some clients rendering an empty,
+non-functional form.
+
+**Args:**
+- `message`: A human-readable message explaining what information is needed
+- `response_type`: The type of the response, which should be a primitive
+type or dataclass or BaseModel. If it is a primitive type, an
+object schema with a single "value" field will be generated.
+- `response_title`: Optional label to display for the wrapped ``value``
+field when ``response_type`` is a scalar, Literal, Enum, or one
+of the dict/list shorthand forms. Overrides the auto-generated
+"Value" label. Raises ``TypeError`` if passed with a BaseModel,
+dataclass, or ``None`` response type (use ``Field(title=...)``
+on the model instead).
+- `response_description`: Optional description to attach to the wrapped
+``value`` field. Same scope rules as ``response_title``.
+
+
+#### `set_state`
+
+```python
+set_state(self, key: str, value: Any) -> None
+```
+
+Set a value in the state store.
+
+By default, values are stored in the session-scoped state store and
+persist across requests within the same MCP session. Values must be
+JSON-serializable (dicts, lists, strings, numbers, etc.).
+
+For non-serializable values (e.g., HTTP clients, database connections),
+pass ``serializable=False``. These values are stored in a request-scoped
+dict and only live for the current MCP request (tool call, resource
+read, or prompt render). They will not be available in subsequent
+requests.
+
+The key is automatically prefixed with the session identifier.
+
+
+#### `get_state`
+
+```python
+get_state(self, key: str) -> Any
+```
+
+Get a value from the state store.
+
+Checks request-scoped state first (set with ``serializable=False``),
+then falls back to the session-scoped state store.
+
+Returns None if the key is not found.
+
+
+#### `delete_state`
+
+```python
+delete_state(self, key: str) -> None
+```
+
+Delete a value from the state store.
+
+Removes from both request-scoped and session-scoped stores.
+
+
+#### `enable_components`
+
+```python
+enable_components(self) -> None
+```
+
+Enable components matching criteria for this session only.
+
+Session rules override global transforms. Rules accumulate - each call
+adds a new rule to the session. Later marks override earlier ones
+(Visibility transform semantics).
+
+Sends notifications to this session only: ToolListChangedNotification,
+ResourceListChangedNotification, and PromptListChangedNotification.
+
+**Args:**
+- `names`: Component names or URIs to match.
+- `keys`: Component keys to match (e.g., {"tool\:my_tool@v1"}).
+- `version`: Component version spec to match.
+- `tags`: Tags to match (component must have at least one).
+- `components`: Component types to match (e.g., {"tool", "prompt"}).
+- `match_all`: If True, matches all components regardless of other criteria.
+
+
+#### `disable_components`
+
+```python
+disable_components(self) -> None
+```
+
+Disable components matching criteria for this session only.
+
+Session rules override global transforms. Rules accumulate - each call
+adds a new rule to the session. Later marks override earlier ones
+(Visibility transform semantics).
+
+Sends notifications to this session only: ToolListChangedNotification,
+ResourceListChangedNotification, and PromptListChangedNotification.
+
+**Args:**
+- `names`: Component names or URIs to match.
+- `keys`: Component keys to match (e.g., {"tool\:my_tool@v1"}).
+- `version`: Component version spec to match.
+- `tags`: Tags to match (component must have at least one).
+- `components`: Component types to match (e.g., {"tool", "prompt"}).
+- `match_all`: If True, matches all components regardless of other criteria.
+
+
+#### `reset_visibility`
+
+```python
+reset_visibility(self) -> None
+```
+
+Clear all session visibility rules.
+
+Use this to reset session visibility back to global defaults.
+
+Sends notifications to this session only: ToolListChangedNotification,
+ResourceListChangedNotification, and PromptListChangedNotification.
+
diff --git a/docs/python-sdk/fastmcp-server-dependencies.mdx b/docs/python-sdk/fastmcp-server-dependencies.mdx
new file mode 100644
index 000000000..1ab291fb1
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-dependencies.mdx
@@ -0,0 +1,614 @@
+---
+title: dependencies
+sidebarTitle: dependencies
+---
+
+# `fastmcp.server.dependencies`
+
+
+Dependency injection for FastMCP.
+
+DI features (Depends, CurrentContext, CurrentFastMCP) work without pydocket
+using the uncalled-for DI engine. The docket-specific dependencies
+(``CurrentDocket``, ``CurrentWorker``) and background task execution live in the
+``fastmcp-tasks`` package.
+
+
+## Functions
+
+### `bind_request_context`
+
+```python
+bind_request_context(ctx: ServerRequestContext) -> Generator[FastMCPRequestContext, None, None]
+```
+
+
+Bind a ``FastMCPRequestContext`` for the duration of a handler.
+
+Constructs the wrapper from the SDK's per-request context and sets/resets
+the ``fastmcp_request_ctx`` ContextVar. Every request adapter and the
+initialize middleware enters this so ``Context`` and dependency helpers can
+read the active request from the ContextVar.
+
+
+### `extract_version_spec`
+
+```python
+extract_version_spec(meta: dict[str, Any] | None) -> str | None
+```
+
+
+Extract the FastMCP component version from a lifted ``_meta`` block.
+
+
+### `set_background_context_factory`
+
+```python
+set_background_context_factory(factory: Callable[[], Awaitable[Context | None]] | None) -> None
+```
+
+
+Install (or clear) the background-task ``Context`` factory.
+
+The factory returns an already-entered ``Context`` (so ``_current_context``
+is set for cleanup) when called inside a worker, or ``None`` when there is
+no task context. Passing ``None`` restores core's no-worker-fallback
+behavior.
+
+
+### `set_worker_server_resolver`
+
+```python
+set_worker_server_resolver(resolver: Callable[[], FastMCP | None] | None) -> None
+```
+
+
+Install (or clear) the worker-server resolver used by ``get_server()``.
+
+
+### `is_docket_available`
+
+```python
+is_docket_available() -> bool
+```
+
+
+Check if a compatible pydocket (>= 0.19.0) is installed and importable.
+
+Three things have to be true for fastmcp's task features to work:
+ 1. pydocket distribution metadata is discoverable
+ 2. its version is at least ``_MIN_DOCKET_VERSION`` (older versions are
+ missing symbols like ``docket.dependencies.current_execution``,
+ which fastmcp imports on the request hot path)
+ 3. the package actually imports — guards against broken/partial
+ installs where metadata exists but ``import docket`` blows up
+
+Any of those failing means we treat docket as unavailable and fall back
+to the no-tasks code paths instead of crashing deep inside a request.
+
+
+### `transform_context_annotations`
+
+```python
+transform_context_annotations(fn: Callable[..., Any]) -> Callable[..., Any]
+```
+
+
+Transform injected-by-type params into Dependency-defaulted params.
+
+Transforms ALL params typed as Context (into ``= CurrentContext()``) and as
+UserSession (into ``= CurrentSession()``) to use Docket's DI system, unless
+they already have a Dependency-based default.
+
+This unifies the legacy type annotation DI with Docket's Depends() system,
+allowing both patterns to work through a single resolution path.
+
+Note: Only POSITIONAL_OR_KEYWORD parameters are reordered (params with defaults
+after those without). KEYWORD_ONLY parameters keep their position since Python
+allows them to have defaults in any order.
+
+**Args:**
+- `fn`: Function to transform
+
+**Returns:**
+- Function with modified signature (same function object, updated __signature__)
+
+
+### `get_context`
+
+```python
+get_context() -> Context
+```
+
+
+Get the current FastMCP Context instance directly.
+
+
+### `get_server`
+
+```python
+get_server() -> FastMCP
+```
+
+
+Get the current FastMCP server instance directly.
+
+In a background-task worker the tasks extension's resolver is consulted
+first, so a mounted-child task resolves to the child server rather than the
+root that started the worker (#3571).
+
+**Returns:**
+- The active FastMCP server
+
+**Raises:**
+- `RuntimeError`: If no server in context
+
+
+### `get_session`
+
+```python
+get_session(session_id: str) -> Session
+```
+
+
+Resolve and validate a `Session` for an explicit `session_id`.
+
+Pair with a `session_id: SessionId` tool argument (the agent obtains an id
+from `create_session` and passes it back). For a single per-user bucket with
+nothing for the agent to pass, inject `session: UserSession` instead.
+
+State is keyed by `(principal, session_id)`: the authenticated principal is
+the isolation wall and `session_id` organizes sessions within it. The id must
+have been minted by `create_session` under the current principal; an id that
+was never created, or created under a different principal, raises
+`InvalidSession` rather than resolving to a fresh empty bucket (the specific
+reason is logged at debug level, never returned to the caller).
+
+Like `get_server()`, this resolves through the task-aware server, so it needs
+no foreground context — it works from a `task=True` tool's Docket worker as
+well as a normal request.
+
+
+### `get_http_request`
+
+```python
+get_http_request() -> Request
+```
+
+
+Get the current HTTP request.
+
+Tries MCP SDK's request_ctx first, then falls back to FastMCP's HTTP context.
+
+
+### `get_http_headers`
+
+```python
+get_http_headers(include_all: bool = False, include: set[str] | None = None) -> dict[str, str]
+```
+
+
+Extract headers from the current HTTP request if available.
+
+Never raises an exception, even if there is no active HTTP request (in which case
+an empty dict is returned).
+
+By default, strips problematic headers like `content-length` and `authorization`
+that cause issues if forwarded to downstream services. If `include_all` is True,
+all headers are returned.
+
+The `include` parameter allows specific headers to be included even if they would
+normally be excluded. This is useful for proxy transports that need to forward
+authorization headers to upstream MCP servers.
+
+
+### `get_access_token`
+
+```python
+get_access_token() -> AccessToken | None
+```
+
+
+Get the FastMCP access token from the current context.
+
+This function first tries to get the token from the current HTTP request's scope,
+which is more reliable for long-lived connections where the SDK's auth_context_var
+may become stale after token refresh. Falls back to the SDK's context var if no
+request is available.
+
+**Returns:**
+- The access token if an authenticated user is available, None otherwise.
+
+
+### `without_injected_parameters`
+
+```python
+without_injected_parameters(fn: Callable[..., Any]) -> Callable[..., Any]
+```
+
+
+Create a wrapper function without injected parameters.
+
+Returns a wrapper that excludes Context and Docket dependency parameters,
+making it safe to use with Pydantic TypeAdapter for schema generation and
+validation. The wrapper internally handles all dependency resolution and
+Context injection when called.
+
+Handles:
+- Legacy Context injection (always works)
+- Depends() injection (always works - uses docket or vendored DI engine)
+
+**Args:**
+- `fn`: Original function with Context and/or dependencies
+- `run_in_thread`: For sync ``fn``, whether to dispatch the call to a worker
+thread after resolving dependencies. Defaults to True. Set to False
+to call ``fn`` inline on the event loop thread — required for
+thread-affinity libraries (e.g. Windows COM). Ignored for async fns.
+
+**Returns:**
+- Async wrapper function without injected parameters
+
+
+### `resolve_dependencies`
+
+```python
+resolve_dependencies(fn: Callable[..., Any], arguments: dict[str, Any]) -> AsyncGenerator[dict[str, Any], None]
+```
+
+
+Resolve dependencies for a FastMCP function.
+
+This function:
+1. Filters out any dependency parameter names from user arguments (security)
+2. Resolves Depends() parameters via the DI system
+
+The filtering prevents external callers from overriding injected parameters by
+providing values for dependency parameter names. This is a security feature.
+
+Note: Context injection is handled via transform_context_annotations() which
+converts `ctx: Context` to `ctx: Context = Depends(get_context)` at registration
+time, so all injection goes through the unified DI system.
+
+**Args:**
+- `fn`: The function to resolve dependencies for
+- `arguments`: User arguments (may contain keys that match dependency names,
+ which will be filtered out)
+
+
+### `CurrentContext`
+
+```python
+CurrentContext() -> Context
+```
+
+
+Get the current FastMCP Context instance.
+
+This dependency provides access to the active FastMCP Context for the
+current MCP operation (tool/resource/prompt call).
+
+**Returns:**
+- A dependency that resolves to the active Context instance
+
+**Raises:**
+- `RuntimeError`: If no active context found (during resolution)
+
+
+### `OptionalCurrentContext`
+
+```python
+OptionalCurrentContext() -> Context | None
+```
+
+
+Get the current FastMCP Context, or None when no context is active.
+
+
+### `CurrentFastMCP`
+
+```python
+CurrentFastMCP() -> FastMCP
+```
+
+
+Get the current FastMCP server instance.
+
+This dependency provides access to the active FastMCP server.
+
+**Returns:**
+- A dependency that resolves to the active FastMCP server
+
+**Raises:**
+- `RuntimeError`: If no server in context (during resolution)
+
+
+### `CurrentRequest`
+
+```python
+CurrentRequest() -> Request
+```
+
+
+Get the current HTTP request.
+
+This dependency provides access to the Starlette Request object for the
+current HTTP request. Only available when running over HTTP transports
+(SSE or Streamable HTTP).
+
+**Returns:**
+- A dependency that resolves to the active Starlette Request
+
+**Raises:**
+- `RuntimeError`: If no HTTP request in context (e.g., STDIO transport)
+
+
+### `CurrentHeaders`
+
+```python
+CurrentHeaders() -> dict[str, str]
+```
+
+
+Get the current HTTP request headers.
+
+This dependency provides access to the HTTP headers for the current request,
+including the authorization header. Returns an empty dictionary when no HTTP
+request is available, making it safe to use in code that might run over any
+transport.
+
+**Returns:**
+- A dependency that resolves to a dictionary of header name -> value
+
+
+### `CurrentAccessToken`
+
+```python
+CurrentAccessToken() -> AccessToken
+```
+
+
+Get the current access token for the authenticated user.
+
+This dependency provides access to the AccessToken for the current
+authenticated request. Raises an error if no authentication is present.
+
+**Returns:**
+- A dependency that resolves to the active AccessToken
+
+**Raises:**
+- `RuntimeError`: If no authenticated user (use get_access_token() for optional)
+
+
+### `TokenClaim`
+
+```python
+TokenClaim(name: str) -> str
+```
+
+
+Get a specific claim from the access token.
+
+This dependency extracts a single claim value from the current access token.
+It's useful for getting user identifiers, roles, or other token claims
+without needing the full token object.
+
+**Args:**
+- `name`: The name of the claim to extract (e.g., "oid", "sub", "email")
+
+**Returns:**
+- A dependency that resolves to the claim value as a string
+
+**Raises:**
+- `RuntimeError`: If no access token is available or claim is missing
+
+
+## Classes
+
+### `FastMCPRequestContext`
+
+
+FastMCP-owned wrapper around the SDK's per-request context.
+
+The SDK v2 runner hands each handler a fresh ``ServerRequestContext`` as an
+argument rather than exposing it through a ContextVar. FastMCP owns this
+ContextVar (``fastmcp_request_ctx``) and each request adapter binds a
+``FastMCPRequestContext`` at the top of the handler (and the initialize
+middleware binds it too).
+
+A wrapper rather than the raw context because the SDK's
+``ServerRequestContext.meta`` is a bare ``RequestParamsMeta`` TypedDict that
+only carries ``progress_token`` — it does not carry ``_meta.fastmcp`` or the
+distributed-trace parent. Those live in the raw params dict under ``_meta``,
+which this wrapper lifts once so downstream consumers have a stable surface.
+
+
+### `ProgressLike`
+
+
+Protocol for progress tracking interface.
+
+Defines the common interface between InMemoryProgress (server context)
+and Docket's Progress (worker context).
+
+
+**Methods:**
+
+#### `current`
+
+```python
+current(self) -> int | None
+```
+
+Current progress value.
+
+
+#### `total`
+
+```python
+total(self) -> int
+```
+
+Total/target progress value.
+
+
+#### `message`
+
+```python
+message(self) -> str | None
+```
+
+Current progress message.
+
+
+#### `set_total`
+
+```python
+set_total(self, total: int) -> None
+```
+
+Set the total/target value for progress tracking.
+
+
+#### `increment`
+
+```python
+increment(self, amount: int = 1) -> None
+```
+
+Atomically increment the current progress value.
+
+
+#### `set_message`
+
+```python
+set_message(self, message: str | None) -> None
+```
+
+Update the progress status message.
+
+
+### `InMemoryProgress`
+
+
+In-memory progress tracker for immediate tool execution.
+
+Provides the same interface as Docket's Progress but stores state in memory
+instead of Redis. Useful for testing and immediate execution where
+progress doesn't need to be observable across processes.
+
+
+**Methods:**
+
+#### `current`
+
+```python
+current(self) -> int | None
+```
+
+#### `total`
+
+```python
+total(self) -> int
+```
+
+#### `message`
+
+```python
+message(self) -> str | None
+```
+
+#### `set_total`
+
+```python
+set_total(self, total: int) -> None
+```
+
+Set the total/target value for progress tracking.
+
+
+#### `increment`
+
+```python
+increment(self, amount: int = 1) -> None
+```
+
+Atomically increment the current progress value.
+
+
+#### `set_message`
+
+```python
+set_message(self, message: str | None) -> None
+```
+
+Update the progress status message.
+
+
+### `Progress`
+
+
+Progress dependency that works in both server and worker contexts.
+
+In a Docket worker, delegates to the execution's Redis-backed progress
+(observable across processes). Otherwise, uses in-memory tracking.
+
+The shared default instance acts as a stateless factory — ``__aenter__``
+creates a fresh ``Progress`` per invocation so concurrent tasks never
+share mutable state.
+
+
+**Methods:**
+
+#### `current`
+
+```python
+current(self) -> int | None
+```
+
+Current progress value.
+
+
+#### `total`
+
+```python
+total(self) -> int
+```
+
+Total/target progress value.
+
+
+#### `message`
+
+```python
+message(self) -> str | None
+```
+
+Current progress message.
+
+
+#### `set_total`
+
+```python
+set_total(self, total: int) -> None
+```
+
+Set the total/target value for progress tracking.
+
+
+#### `increment`
+
+```python
+increment(self, amount: int = 1) -> None
+```
+
+Atomically increment the current progress value.
+
+
+#### `set_message`
+
+```python
+set_message(self, message: str | None) -> None
+```
+
+Update the progress status message.
+
diff --git a/docs/python-sdk/fastmcp-server-elicitation.mdx b/docs/python-sdk/fastmcp-server-elicitation.mdx
new file mode 100644
index 000000000..824ab59e9
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-elicitation.mdx
@@ -0,0 +1,152 @@
+---
+title: elicitation
+sidebarTitle: elicitation
+---
+
+# `fastmcp.server.elicitation`
+
+## Functions
+
+### `parse_elicit_response_type`
+
+```python
+parse_elicit_response_type(response_type: Any, response_title: str | None = None, response_description: str | None = None) -> ElicitConfig
+```
+
+
+Parse response_type into schema and handling configuration.
+
+A response type is required; ``None`` raises ``TypeError``. Supports
+multiple syntaxes:
+- dict: `{"low": {"title": "..."}}` -> single-select titled enum
+- list patterns:
+ - `[["a", "b"]]` -> multi-select untitled
+ - `[{"low": {...}}]` -> multi-select titled
+ - `["a", "b"]` -> single-select untitled
+- `list\[X]` type annotation: multi-select with type
+- Scalar types (bool, int, float, str, Literal, Enum): single value
+- Other types (dataclass, BaseModel): use directly
+
+The ``response_title`` and ``response_description`` arguments customize the
+label and description of the wrapped ``value`` property for the scalar/dict/list
+shorthand forms. They are only valid when FastMCP is wrapping the response
+type; passing them with a full BaseModel/dataclass raises ``TypeError``,
+because in those cases the user already controls field metadata via
+``Field(title=..., description=...)``.
+
+
+### `handle_elicit_accept`
+
+```python
+handle_elicit_accept(config: ElicitConfig, content: Any) -> AcceptedElicitation[Any]
+```
+
+
+Handle an accepted elicitation response.
+
+**Args:**
+- `config`: The elicitation configuration from parse_elicit_response_type
+- `content`: The response content from the client
+
+**Returns:**
+- AcceptedElicitation with the extracted/validated data
+
+
+### `get_elicitation_schema`
+
+```python
+get_elicitation_schema(response_type: type[T]) -> dict[str, Any]
+```
+
+
+Get the schema for an elicitation response.
+
+**Args:**
+- `response_type`: The type of the response
+
+
+### `validate_elicitation_json_schema`
+
+```python
+validate_elicitation_json_schema(schema: dict[str, Any]) -> None
+```
+
+
+Validate that a JSON schema follows MCP elicitation requirements.
+
+This ensures the schema is compatible with MCP elicitation requirements:
+- Must be an object schema
+- Must only contain primitive field types (string, number, integer, boolean)
+- Must be flat (no nested objects or arrays of objects)
+- Allows const fields (for Literal types) and enum fields (for Enum types)
+- Only primitive types and their nullable variants are allowed
+
+**Args:**
+- `schema`: The JSON schema to validate
+
+**Raises:**
+- `TypeError`: If the schema doesn't meet MCP elicitation requirements
+
+
+## Classes
+
+### `ElicitationJsonSchema`
+
+
+Custom JSON schema generator for MCP elicitation that always inlines enums.
+
+MCP elicitation requires inline enum schemas without $ref/$defs references.
+This generator ensures enums are always generated inline for compatibility.
+Optionally adds enumNames for better UI display when available.
+
+
+**Methods:**
+
+#### `generate_inner`
+
+```python
+generate_inner(self, schema: core_schema.CoreSchema) -> JsonSchemaValue
+```
+
+Override to prevent ref generation for enums and handle list schemas.
+
+
+#### `list_schema`
+
+```python
+list_schema(self, schema: core_schema.ListSchema) -> JsonSchemaValue
+```
+
+Generate schema for list types, detecting enum items for multi-select.
+
+
+#### `enum_schema`
+
+```python
+enum_schema(self, schema: core_schema.EnumSchema) -> JsonSchemaValue
+```
+
+Generate inline enum schema.
+
+Always generates enum pattern: `{"enum": [value, ...]}`
+Titled enums are handled separately via dict-based syntax in ctx.elicit().
+
+
+### `AcceptedElicitation`
+
+
+Result when user accepts the elicitation.
+
+
+### `ScalarElicitationType`
+
+### `ElicitConfig`
+
+
+Configuration for an elicitation request.
+
+**Attributes:**
+- `schema`: The JSON schema to send to the client
+- `response_type`: The type to validate responses with (None for raw schemas)
+- `is_raw`: True if schema was built directly (extract "value" from response)
+
diff --git a/docs/python-sdk/fastmcp-server-event_store.mdx b/docs/python-sdk/fastmcp-server-event_store.mdx
new file mode 100644
index 000000000..08d266ea5
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-event_store.mdx
@@ -0,0 +1,78 @@
+---
+title: event_store
+sidebarTitle: event_store
+---
+
+# `fastmcp.server.event_store`
+
+
+EventStore implementation backed by AsyncKeyValue.
+
+This module provides an EventStore implementation that enables SSE polling/resumability
+for Streamable HTTP transports. Events are stored using the key_value package's
+AsyncKeyValue protocol, allowing users to configure any compatible backend
+(in-memory, Redis, etc.) following the same pattern as ResponseCachingMiddleware.
+
+
+## Classes
+
+### `EventEntry`
+
+
+Stored event entry.
+
+
+### `StreamEventList`
+
+
+List of event IDs for a stream.
+
+
+### `EventStore`
+
+
+EventStore implementation backed by AsyncKeyValue.
+
+Enables SSE polling/resumability by storing events that can be replayed
+when clients reconnect. Works with any AsyncKeyValue backend (memory, Redis, etc.)
+following the same pattern as ResponseCachingMiddleware and OAuthProxy.
+
+**Args:**
+- `storage`: AsyncKeyValue backend. Defaults to MemoryStore.
+- `max_events_per_stream`: Maximum events to retain per stream. Default 100.
+- `ttl`: Event TTL in seconds. Default 3600 (1 hour). Set to None for no expiration.
+
+
+**Methods:**
+
+#### `store_event`
+
+```python
+store_event(self, stream_id: StreamId, message: JSONRPCMessage | None) -> EventId
+```
+
+Store an event and return its ID.
+
+**Args:**
+- `stream_id`: ID of the stream the event belongs to
+- `message`: The JSON-RPC message to store, or None for priming events
+
+**Returns:**
+- The generated event ID for the stored event
+
+
+#### `replay_events_after`
+
+```python
+replay_events_after(self, last_event_id: EventId, send_callback: EventCallback) -> StreamId | None
+```
+
+Replay events that occurred after the specified event ID.
+
+**Args:**
+- `last_event_id`: The ID of the last event the client received
+- `send_callback`: A callback function to send events to the client
+
+**Returns:**
+- The stream ID of the replayed events, or None if the event ID was not found
+
diff --git a/docs/python-sdk/fastmcp-server-extensions.mdx b/docs/python-sdk/fastmcp-server-extensions.mdx
new file mode 100644
index 000000000..3c8c2f62f
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-extensions.mdx
@@ -0,0 +1,194 @@
+---
+title: extensions
+sidebarTitle: extensions
+---
+
+# `fastmcp.server.extensions`
+
+
+FastMCP-native server extension API (SEP-2133).
+
+An MCP extension is an opt-in, capability-negotiated bundle of protocol
+behaviour identified by a reverse-DNS string (e.g. `io.modelcontextprotocol/tasks`).
+Unlike the SDK's `mcp.server.extension.Extension`, a FastMCP `ServerExtension`
+is bound to its `FastMCP` instance at registration, so its request handlers and
+its `tools/call` interceptor can reach the component registry, `Context`, and
+auth scope that the SDK's model withholds.
+
+An extension contributes any subset of four things:
+
+- **A negotiated capability.** `settings()` is spliced into
+ `ServerCapabilities.extensions[identifier]` (see `LowLevelServer.get_capabilities`).
+- **New request methods.** `methods()` returns `MethodBinding`s, each wired onto
+ the low-level server via `add_request_handler` when the extension is registered.
+- **A `tools/call` interceptor.** `intercept_tool_call()` is the last gate before
+ a tool body runs — it composes *after* the FastMCP middleware chain and *before*
+ component execution, so it can observe, short-circuit, or pass a call through.
+- **A lifespan.** `lifespan()` is entered with the server's lifespan and exited on
+ shutdown — the hook the SDK's `Extension` lacks, needed to start backends/workers.
+
+The base class follows the SDK's httpx-style shape: every contribution method has
+a default, so a subclass overrides only what it needs.
+
+
+## Functions
+
+### `read_client_extension_settings`
+
+```python
+read_client_extension_settings(ctx: ServerRequestContext[Any, Any], identifier: str) -> dict[str, Any] | None
+```
+
+
+Read a client's per-request extension opt-in from the request `_meta`.
+
+SEP-2133 extensions negotiate per request: the client repeats its extension
+capabilities in each request's `_meta` under
+`io.modelcontextprotocol/clientCapabilities` → `extensions` → `identifier`.
+Returns the declared settings dict (possibly empty) when the extension was
+opted in for this request, or `None` when it was not.
+
+
+### `build_method_handler`
+
+```python
+build_method_handler(binding: MethodBinding) -> ExtensionRequestHandler
+```
+
+
+Wrap a `MethodBinding` into a low-level request handler.
+
+The adapter enforces `protocol_versions` gating (rejecting other versions as
+`METHOD_NOT_FOUND`, since `add_request_handler` registers unconditionally)
+and binds the FastMCP request context so the handler can use `get_context()`,
+auth, and other request-scoped dependencies.
+
+
+### `wrap_tool_call_interceptor`
+
+```python
+wrap_tool_call_interceptor(extension: ServerExtension, call_next: Callable[[Any], Awaitable[Any]]) -> Callable[[Any], Awaitable[Any]]
+```
+
+
+Fold one extension's `intercept_tool_call` around a middleware `call_next`.
+
+The returned wrapper is a FastMCP `CallNext`: it hands the extension the
+validated `tools/call` params, the FastMCP `Context`, and a zero-arg
+continuation that runs the rest of the chain and, finally, the tool body.
+
+
+## Classes
+
+### `MethodBinding`
+
+
+A new request method an extension serves, e.g. `tasks/get`.
+
+`params_type` validates incoming params before `handler` runs; it should
+subclass `RequestParams` so `_meta` parses uniformly. `protocol_versions`,
+when set, restricts the method to those wire versions — a request at any
+other version is rejected as `METHOD_NOT_FOUND`, mirroring the spec's
+`(method, version)` boundary. `None` (the default) admits every version.
+
+Extension methods are additive: `method` must not name a spec-defined
+request method (`tools/call`, `completion/complete`, ...). Binding one would
+silently shadow the server's own handler. Both constraints are enforced at
+construction.
+
+
+### `ServerExtension`
+
+
+Base class for an opt-in FastMCP server extension (SEP-2133).
+
+Subclass, set `identifier`, and override the contribution methods that
+apply. Every method has a default, so a minimal extension overrides only
+`identifier` and one contribution. `identifier` is validated at
+subclass-definition time when set as a class attribute, and again at
+registration (which covers per-instance identifiers assigned in `__init__`).
+
+Register an instance with `FastMCP.add_extension(...)`, which binds the
+extension to the server so `self.server`, `intercept_tool_call`, and method
+handlers can reach FastMCP-level constructs.
+
+
+**Methods:**
+
+#### `server`
+
+```python
+server(self) -> FastMCP
+```
+
+The FastMCP server this extension is registered on.
+
+Handlers, interceptors, and lifespan code reach the component registry,
+`Context`, and auth scope through here. Raises if the extension has not
+been registered with `FastMCP.add_extension()`.
+
+
+#### `settings`
+
+```python
+settings(self) -> dict[str, Any]
+```
+
+Per-extension settings advertised at `capabilities.extensions[identifier]`.
+
+An empty dict (the default) advertises the extension with no settings.
+
+
+#### `methods`
+
+```python
+methods(self) -> Sequence[MethodBinding]
+```
+
+New request methods this extension serves (additive).
+
+
+#### `lifespan`
+
+```python
+lifespan(self) -> AbstractAsyncContextManager[None]
+```
+
+A context manager entered with the server's lifespan, exited on shutdown.
+
+Default: a no-op. Override to start and stop resources an extension owns
+(a task-queue backend and worker, say). Entered once per runtime tree, at
+the root — a mounted child defers to the root, as the shared Docket does.
+
+
+#### `intercept_tool_call`
+
+```python
+intercept_tool_call(self, params: CallToolRequestParams, context: Context, call_next: ToolCallContinuation) -> ToolCallOutcome
+```
+
+Wrap `tools/call`. Default: pass through unchanged.
+
+Runs after the FastMCP middleware chain and before the tool body, so it
+is the last gate before execution. Override to observe the call, to
+short-circuit (return a result without awaiting `call_next`), or to pass
+it through (`return await call_next()`). `params` is the validated
+`tools/call` params; `context` is the FastMCP `Context`, from which the
+tool being called (`context.fastmcp.get_tool(params.name)`), auth scope,
+and the server are reachable. Multiple extensions nest with the
+first-registered outermost.
+
+
+#### `client_settings`
+
+```python
+client_settings(self, ctx: ServerRequestContext[Any, Any]) -> dict[str, Any] | None
+```
+
+This extension's per-request opt-in settings declared by the client.
+
+Reads the request's `_meta` client-capabilities block. Returns the
+declared settings dict (possibly empty) when the client opted this
+extension in for the request, or `None` when it did not. Convenience for
+`read_client_extension_settings(ctx, self.identifier)`.
+
diff --git a/docs/python-sdk/fastmcp-server-http.mdx b/docs/python-sdk/fastmcp-server-http.mdx
new file mode 100644
index 000000000..46db6c15a
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-http.mdx
@@ -0,0 +1,144 @@
+---
+title: http
+sidebarTitle: http
+---
+
+# `fastmcp.server.http`
+
+## Functions
+
+### `set_http_request`
+
+```python
+set_http_request(request: Request) -> Generator[Request, None, None]
+```
+
+### `create_base_app`
+
+```python
+create_base_app(routes: list[BaseRoute], middleware: list[Middleware], debug: bool = False, lifespan: Callable | None = None) -> StarletteWithLifespan
+```
+
+
+Create a base Starlette app with common middleware and routes.
+
+**Args:**
+- `routes`: List of routes to include in the app
+- `middleware`: List of middleware to include in the app
+- `debug`: Whether to enable debug mode
+- `lifespan`: Optional lifespan manager for the app
+
+**Returns:**
+- A Starlette application
+
+
+### `create_sse_app`
+
+```python
+create_sse_app(server: FastMCP[LifespanResultT], message_path: str, sse_path: str, auth: AuthProvider | None = None, debug: bool = False, routes: list[BaseRoute] | None = None, middleware: list[Middleware] | None = None) -> StarletteWithLifespan
+```
+
+
+Return an instance of the SSE server app.
+
+**Args:**
+- `server`: The FastMCP server instance
+- `message_path`: Path for SSE messages
+- `sse_path`: Path for SSE connections
+- `auth`: Optional authentication provider (AuthProvider)
+- `debug`: Whether to enable debug mode
+- `routes`: Optional list of custom routes
+- `middleware`: Optional list of middleware
+
+Returns:
+ A Starlette application with RequestContextMiddleware
+
+
+### `create_streamable_http_app`
+
+```python
+create_streamable_http_app(server: FastMCP[LifespanResultT], streamable_http_path: str, event_store: EventStore | None = None, retry_interval: int | None = None, auth: AuthProvider | None = None, json_response: bool = False, stateless_http: bool = False, debug: bool = False, routes: list[BaseRoute] | None = None, middleware: list[Middleware] | None = None, host_origin_protection: HostOriginProtection = False, allowed_hosts: Sequence[str] | None = None, allowed_origins: Sequence[str] | None = None, session_idle_timeout: float | None = None) -> StarletteWithLifespan
+```
+
+
+Return an instance of the StreamableHTTP server app.
+
+**Args:**
+- `server`: The FastMCP server instance
+- `streamable_http_path`: Path for StreamableHTTP connections
+- `event_store`: Optional event store for SSE polling/resumability
+- `retry_interval`: Optional retry interval in milliseconds for SSE polling.
+Controls how quickly clients should reconnect after server-initiated
+disconnections. Requires event_store to be set. Defaults to SDK default.
+- `auth`: Optional authentication provider (AuthProvider)
+- `json_response`: Whether to use JSON response format
+- `stateless_http`: Whether to use stateless mode (new transport per request)
+- `debug`: Whether to enable debug mode
+- `routes`: Optional list of custom routes
+- `middleware`: Optional list of middleware
+- `host_origin_protection`: Whether to validate Host and Origin headers
+before requests reach the MCP endpoint. Defaults to False for
+compatibility. "auto" protects localhost-bound servers and explicit
+host/origin allowlists.
+- `allowed_hosts`: Additional hostnames that may appear in the Host header.
+- `allowed_origins`: Additional browser origins trusted by the request guard.
+Configure CORS separately when browser JavaScript must read
+cross-origin responses.
+- `session_idle_timeout`: Maximum time in seconds a session may remain idle
+before it is terminated. The deadline is pushed forward on every
+request. When None, sessions never expire from inactivity. Not
+supported in stateless mode.
+
+**Returns:**
+- A Starlette application with StreamableHTTP support
+
+
+## Classes
+
+### `FastMCPStreamableHTTPSessionManager`
+
+
+Session manager that scopes resumability storage per transport session.
+
+
+**Methods:**
+
+#### `event_store`
+
+```python
+event_store(self) -> EventStore | None
+```
+
+#### `event_store`
+
+```python
+event_store(self, event_store: EventStore | None) -> None
+```
+
+### `StreamableHTTPASGIApp`
+
+
+ASGI application wrapper for Streamable HTTP server transport.
+
+
+### `HostOriginGuardMiddleware`
+
+
+Validate Host and Origin headers before requests reach MCP sessions.
+
+
+### `StarletteWithLifespan`
+
+**Methods:**
+
+#### `lifespan`
+
+```python
+lifespan(self) -> Lifespan[Starlette]
+```
+
+### `RequestContextMiddleware`
+
+
+Middleware that stores each request in a ContextVar and sets transport type.
+
diff --git a/docs/python-sdk/fastmcp-server-lifespan.mdx b/docs/python-sdk/fastmcp-server-lifespan.mdx
new file mode 100644
index 000000000..091836304
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-lifespan.mdx
@@ -0,0 +1,101 @@
+---
+title: lifespan
+sidebarTitle: lifespan
+---
+
+# `fastmcp.server.lifespan`
+
+
+Composable lifespans for FastMCP servers.
+
+This module provides a `@lifespan` decorator for creating composable server lifespans
+that can be combined using the `|` operator.
+
+Example:
+ ```python
+ from fastmcp import FastMCP
+ from fastmcp.server.lifespan import lifespan
+
+ @lifespan
+ async def db_lifespan(server):
+ conn = await connect_db()
+ yield {"db": conn}
+ await conn.close()
+
+ @lifespan
+ async def cache_lifespan(server):
+ cache = await connect_cache()
+ yield {"cache": cache}
+ await cache.close()
+
+ mcp = FastMCP("server", lifespan=db_lifespan | cache_lifespan)
+ ```
+
+To compose with existing `@asynccontextmanager` lifespans, wrap them explicitly:
+
+ ```python
+ from contextlib import asynccontextmanager
+ from fastmcp.server.lifespan import lifespan, ContextManagerLifespan
+
+ @asynccontextmanager
+ async def legacy_lifespan(server):
+ yield {"legacy": True}
+
+ @lifespan
+ async def new_lifespan(server):
+ yield {"new": True}
+
+ # Wrap the legacy lifespan explicitly
+ combined = ContextManagerLifespan(legacy_lifespan) | new_lifespan
+ ```
+
+
+## Functions
+
+### `lifespan`
+
+```python
+lifespan(fn: LifespanFn) -> Lifespan
+```
+
+
+Decorator to create a composable lifespan.
+
+Use this decorator on an async generator function to make it composable
+with other lifespans using the `|` operator.
+
+**Args:**
+- `fn`: An async generator function that takes a FastMCP server and yields
+a dict for the lifespan context.
+
+**Returns:**
+- A composable Lifespan wrapper.
+
+
+## Classes
+
+### `Lifespan`
+
+
+Composable lifespan wrapper.
+
+Wraps an async generator function and enables composition via the `|` operator.
+The wrapped function should yield a dict that becomes part of the lifespan context.
+
+
+### `ContextManagerLifespan`
+
+
+Lifespan wrapper for already-wrapped context manager functions.
+
+Use this for functions already decorated with @asynccontextmanager.
+
+
+### `ComposedLifespan`
+
+
+Two lifespans composed together.
+
+Enters the left lifespan first, then the right. Exits in reverse order.
+Results are shallow-merged into a single dict.
+
diff --git a/docs/python-sdk/fastmcp-server-low_level.mdx b/docs/python-sdk/fastmcp-server-low_level.mdx
new file mode 100644
index 000000000..f515849e4
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-low_level.mdx
@@ -0,0 +1,106 @@
+---
+title: low_level
+sidebarTitle: low_level
+---
+
+# `fastmcp.server.low_level`
+
+## Functions
+
+### `client_supports_extension`
+
+```python
+client_supports_extension(session: ServerSession, extension_id: str) -> bool
+```
+
+
+Check whether the connected client supports a given MCP extension.
+
+Inspects the ``extensions`` capability on ``ClientCapabilities`` sent by the
+client during initialization. In v2 the client's initialize params are
+reachable via ``session.client_params``.
+
+SDK v2 declares ``extensions`` as a real field on ``ClientCapabilities``, so
+a client sending ``ClientCapabilities(extensions={...})`` populates the field
+directly. We read that field first and fall back to ``model_extra`` only for
+legacy-serialized clients that carried ``extensions`` as an extra key.
+
+
+## Classes
+
+### `FastMCPServerMiddleware`
+
+
+Root dispatch for the FastMCP middleware chain, in the SDK's middleware layer.
+
+v2 no longer lets FastMCP subclass ``ServerSession`` (the runner constructs
+it per request), so the old ``MiddlewareServerSession._received_request``
+override is replaced by a ``ServerMiddleware`` — an ordinary entry in the
+SDK's own middleware list. Sitting at the root of dispatch, this
+is the single entry point through which *every* inbound message flows —
+requests, notifications, cancellations, ``initialize``, and even malformed or
+unroutable messages the SDK can still hand us. It binds the FastMCP
+request-context ContextVar and re-applies the app-scoped ``SharedContext`` for
+the whole chain, then runs the FastMCP ``Middleware`` chain so
+``on_message`` / ``on_request`` / ``on_notification`` observe the message.
+
+Dispatch shapes:
+
+- Negotiation runs the *whole* FastMCP chain here: ``initialize`` dispatches
+ through ``on_initialize`` and ``server/discover`` through ``on_discover``.
+ Neither has an interior FastMCP handler adapter, and the SDK serializes both
+ results before returning through its middleware seam, so this root adapter
+ restores core results to typed models before FastMCP middleware observes them.
+- The component methods (``tools/call``, ``tools/list``, ``resources/read``,
+ ...) still run their FastMCP chain *interior*, in the handler adapter, where
+ ``on_call_tool`` receives the typed component result and a tool exception
+ propagates through ``on_message``/``on_request`` exactly where the built-in
+ error/logging/timing middleware expect it. The root dispatch does not re-run the
+ chain for these — it only steps in when such a request fails *before* the
+ interior runs (malformed params, routing), so ``on_message`` still observes
+ the failure.
+- Every other message — all notifications (including ``notifications/cancelled``
+ and ``notifications/initialized``), ``ping``, ``logging/setLevel``, and any
+ unroutable/non-component request — has no interior FastMCP dispatch, so the
+ root dispatch runs the ``"outer"`` pass (``on_message`` plus
+ ``on_request``/``on_notification``) here, wrapping the real SDK dispatch.
+ This closes the long-standing gap where these messages were invisible to
+ FastMCP middleware.
+
+
+### `LowLevelServer`
+
+**Methods:**
+
+#### `fastmcp`
+
+```python
+fastmcp(self) -> FastMCP
+```
+
+Get the FastMCP instance.
+
+
+#### `create_initialization_options`
+
+```python
+create_initialization_options(self, notification_options: NotificationOptions | None = None, experimental_capabilities: dict[str, dict[str, Any]] | None = None, extensions: dict[str, dict[str, Any]] | None = None) -> InitializationOptions
+```
+
+#### `get_capabilities`
+
+```python
+get_capabilities(self, notification_options: NotificationOptions | None = None, experimental_capabilities: dict[str, dict[str, Any]] | None = None, extensions: dict[str, dict[str, Any]] | None = None) -> mcp_types.ServerCapabilities
+```
+
+Override to advertise registered extensions and the MCP Apps UI extension.
+
+``ServerCapabilities.extensions`` is a real declared field in v2, so we
+update it directly. The
+`FastMCP(experimental_capabilities=...)` merge also lives here rather
+than in `create_initialization_options`: the modern `server/discover`
+handler calls this directly, without going through
+`create_initialization_options` at all, so merging there only reached
+the handshake-era `initialize` response and silently dropped
+constructor-configured experimental capabilities from `discover`.
+
diff --git a/docs/python-sdk/fastmcp-server-mixins.mdx b/docs/python-sdk/fastmcp-server-mixins.mdx
new file mode 100644
index 000000000..9734da93c
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-mixins.mdx
@@ -0,0 +1,9 @@
+---
+title: mixins
+sidebarTitle: mixins
+---
+
+# `fastmcp.server.mixins`
+
+
+Server mixins for FastMCP.
diff --git a/docs/python-sdk/fastmcp-server-providers.mdx b/docs/python-sdk/fastmcp-server-providers.mdx
new file mode 100644
index 000000000..c227ee1a0
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-providers.mdx
@@ -0,0 +1,34 @@
+---
+title: providers
+sidebarTitle: providers
+---
+
+# `fastmcp.server.providers`
+
+
+Providers for dynamic MCP components.
+
+This module provides the `Provider` abstraction for providing tools,
+resources, and prompts dynamically at runtime.
+
+Example:
+ ```python
+ from fastmcp import FastMCP
+ from fastmcp.server.providers import Provider
+ from fastmcp.tools import Tool
+
+ class DatabaseProvider(Provider):
+ def __init__(self, db_url: str):
+ self.db = Database(db_url)
+
+ async def _list_tools(self) -> list[Tool]:
+ rows = await self.db.fetch("SELECT * FROM tools")
+ return [self._make_tool(row) for row in rows]
+
+ async def _get_tool(self, name: str) -> Tool | None:
+ row = await self.db.fetchone("SELECT * FROM tools WHERE name = ?", name)
+ return self._make_tool(row) if row else None
+
+ mcp = FastMCP("Server", providers=[DatabaseProvider(db_url)])
+ ```
+
diff --git a/docs/python-sdk/fastmcp-server-server.mdx b/docs/python-sdk/fastmcp-server-server.mdx
new file mode 100644
index 000000000..12524e5b8
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-server.mdx
@@ -0,0 +1,891 @@
+---
+title: server
+sidebarTitle: server
+---
+
+# `fastmcp.server.server`
+
+
+FastMCP - A more ergonomic interface for MCP servers.
+
+## Functions
+
+### `default_lifespan`
+
+```python
+default_lifespan(server: FastMCP[LifespanResultT]) -> AsyncIterator[Any]
+```
+
+
+Default lifespan context manager that does nothing.
+
+**Args:**
+- `server`: The server instance this lifespan is managing
+
+**Returns:**
+- An empty dictionary as the lifespan result.
+
+
+### `create_proxy`
+
+```python
+create_proxy(target: Client[ClientTransportT] | ClientTransport | FastMCP[Any] | SDKServer | AnyUrl | Path | MCPConfig | dict[str, Any] | str, **settings: Any) -> FastMCPProxy
+```
+
+
+Create a FastMCP proxy server for the given target.
+
+This is the recommended way to create a proxy server. For lower-level control,
+use `FastMCPProxy` or `ProxyProvider` directly from `fastmcp.server.providers.proxy`.
+
+**Args:**
+- `target`: The backend to proxy to. Can be\:
+- A Client instance (connected or disconnected)
+- A ClientTransport
+- A FastMCP server instance
+- A URL string or AnyUrl
+- A Path to a server script
+- An MCPConfig or dict
+- `mode`: Protocol-era negotiation for auto-created proxy clients (a
+non-Client target). By default (``None``) the backend MIRRORS the
+front connection's negotiated era per request, so the whole chain
+speaks one era end-to-end\: a modern front reaches a modern backend
+(a guard tool's `InputRequiredResult` (SEP-2322) round-trips) and a
+handshake front reaches a handshake backend (server-initiated
+sampling / elicitation / roots push-forwarding works). Pass an
+explicit mode (e.g. ``"auto"`` or a version string) to pin the
+backend era regardless of the front; this overrides mirroring and is
+appropriate when the backend only speaks one era. Ignored when
+`target` is already a `Client` (which carries its own mode).
+- `**settings`: Additional settings passed to FastMCPProxy (name, etc.)
+
+**Returns:**
+- A FastMCPProxy server that proxies to the target.
+
+
+## Classes
+
+### `StateValue`
+
+
+Wrapper for stored context state values.
+
+
+### `FastMCP`
+
+**Methods:**
+
+#### `name`
+
+```python
+name(self) -> str
+```
+
+#### `instructions`
+
+```python
+instructions(self) -> str | None
+```
+
+#### `instructions`
+
+```python
+instructions(self, value: str | None) -> None
+```
+
+#### `version`
+
+```python
+version(self) -> str | None
+```
+
+#### `website_url`
+
+```python
+website_url(self) -> str | None
+```
+
+#### `icons`
+
+```python
+icons(self) -> list[mcp_types.Icon]
+```
+
+#### `local_provider`
+
+```python
+local_provider(self) -> LocalProvider
+```
+
+The server's local provider, which stores directly-registered components.
+
+Use this to remove components:
+
+ mcp.local_provider.remove_tool("my_tool")
+ mcp.local_provider.remove_resource("data://info")
+ mcp.local_provider.remove_prompt("my_prompt")
+
+
+#### `add_middleware`
+
+```python
+add_middleware(self, middleware: Middleware) -> None
+```
+
+#### `add_extension`
+
+```python
+add_extension(self, extension: ServerExtension) -> None
+```
+
+Register a server extension (SEP-2133).
+
+An extension contributes a negotiated capability, additive request
+methods, a `tools/call` interceptor, and an optional lifespan — each
+with access to FastMCP-level constructs (the component registry,
+`Context`, auth scope). Its capability is advertised only while it is
+registered.
+
+The extension is bound to this server (so its handlers and interceptor
+can reach it), its method bindings are wired onto the low-level server,
+and it is recorded for capability advertisement, interception, and
+lifespan entry. Registering two extensions with the same identifier is
+an error, as is registering after the server's lifespan has started —
+the extension's lifespan could no longer run, leaving it silently
+half-active.
+
+Extensions are served by the server they are registered on. A mounted
+child's extensions do not propagate to the root: the root serves the
+wire, so only root-registered extensions advertise capabilities and
+answer methods (matching the lifespan, which also defers to the root).
+Register extensions on the server you run.
+
+
+#### `add_provider`
+
+```python
+add_provider(self, provider: Provider) -> None
+```
+
+Add a provider for dynamic tools, resources, and prompts.
+
+Providers are queried in registration order. The first provider to return
+a non-None result wins. Static components (registered via decorators)
+always take precedence over providers.
+
+**Args:**
+- `provider`: A Provider instance that will provide components dynamically.
+- `namespace`: Optional namespace prefix. When set\:
+- Tools become "namespace_toolname"
+- Resources become "protocol\://namespace/path"
+- Prompts become "namespace_promptname"
+
+
+#### `get_tasks`
+
+```python
+get_tasks(self) -> Sequence[FastMCPComponent]
+```
+
+Get task-eligible components with all transforms applied.
+
+Overrides AggregateProvider.get_tasks() to apply server-level transforms
+after aggregation. AggregateProvider handles provider-level namespacing.
+
+
+#### `add_transform`
+
+```python
+add_transform(self, transform: Transform) -> None
+```
+
+Add a server-level transform.
+
+Server-level transforms are applied after all providers are aggregated.
+They transform tools, resources, and prompts from ALL providers.
+
+**Args:**
+- `transform`: The transform to add.
+
+
+#### `list_tools`
+
+```python
+list_tools(self) -> Sequence[Tool]
+```
+
+List all enabled tools from providers.
+
+Overrides Provider.list_tools() to add enabled filtering, auth filtering,
+and middleware execution. Returns all versions (no deduplication).
+Protocol handlers deduplicate for MCP wire format.
+
+
+#### `get_tool`
+
+```python
+get_tool(self, name: str, version: VersionSpec | None = None) -> Tool | None
+```
+
+Get a tool by name, filtering disabled tools.
+
+Overrides Provider.get_tool() to filter disabled tools after all
+transforms (including session-level) have been applied. This ensures
+session transforms can override provider-level disables.
+
+When the highest version is disabled and no explicit version was
+requested, falls back to the next-highest enabled version.
+
+**Args:**
+- `name`: The tool name.
+- `version`: Version filter (None returns highest version).
+
+**Returns:**
+- The tool if found and enabled, None otherwise.
+
+
+#### `list_resources`
+
+```python
+list_resources(self) -> Sequence[Resource]
+```
+
+List all enabled resources from providers.
+
+Overrides Provider.list_resources() to add visibility filtering, auth filtering,
+and middleware execution. Returns all versions (no deduplication).
+Protocol handlers deduplicate for MCP wire format.
+
+
+#### `get_resource`
+
+```python
+get_resource(self, uri: str, version: VersionSpec | None = None) -> Resource | None
+```
+
+Get a resource by URI, filtering disabled resources.
+
+Overrides Provider.get_resource() to add visibility filtering after all
+transforms (including session-level) have been applied.
+
+When the highest version is disabled and no explicit version was
+requested, falls back to the next-highest enabled version.
+
+**Args:**
+- `uri`: The resource URI.
+- `version`: Version filter (None returns highest version).
+
+**Returns:**
+- The resource if found and enabled, None otherwise.
+
+
+#### `list_resource_templates`
+
+```python
+list_resource_templates(self) -> Sequence[ResourceTemplate]
+```
+
+List all enabled resource templates from providers.
+
+Overrides Provider.list_resource_templates() to add visibility filtering,
+auth filtering, and middleware execution. Returns all versions (no deduplication).
+Protocol handlers deduplicate for MCP wire format.
+
+
+#### `get_resource_template`
+
+```python
+get_resource_template(self, uri: str, version: VersionSpec | None = None) -> ResourceTemplate | None
+```
+
+Get a resource template by URI, filtering disabled templates.
+
+Overrides Provider.get_resource_template() to add visibility filtering after
+all transforms (including session-level) have been applied.
+
+When the highest version is disabled and no explicit version was
+requested, falls back to the next-highest enabled version.
+
+**Args:**
+- `uri`: The template URI.
+- `version`: Version filter (None returns highest version).
+
+**Returns:**
+- The template if found and enabled, None otherwise.
+
+
+#### `list_prompts`
+
+```python
+list_prompts(self) -> Sequence[Prompt]
+```
+
+List all enabled prompts from providers.
+
+Overrides Provider.list_prompts() to add visibility filtering, auth filtering,
+and middleware execution. Returns all versions (no deduplication).
+Protocol handlers deduplicate for MCP wire format.
+
+
+#### `get_prompt`
+
+```python
+get_prompt(self, name: str, version: VersionSpec | None = None) -> Prompt | None
+```
+
+Get a prompt by name, filtering disabled prompts.
+
+Overrides Provider.get_prompt() to add visibility filtering after all
+transforms (including session-level) have been applied.
+
+When the highest version is disabled and no explicit version was
+requested, falls back to the next-highest enabled version.
+
+**Args:**
+- `name`: The prompt name.
+- `version`: Version filter (None returns highest version).
+
+**Returns:**
+- The prompt if found and enabled, None otherwise.
+
+
+#### `call_tool`
+
+```python
+call_tool(self, name: str, arguments: dict[str, Any] | None = None) -> ToolResult
+```
+
+Call a tool by name.
+
+This is the public API for executing tools. By default, middleware is applied.
+
+**Args:**
+- `name`: The tool name
+- `arguments`: Tool arguments (optional)
+- `version`: Specific version to call. If None, calls highest version.
+- `run_middleware`: If True (default), apply the middleware chain.
+Set to False when called from middleware to avoid re-applying.
+
+**Returns:**
+- ToolResult.
+
+A guard tool that requests client input (SEP-2322 multi-round-trip)
+returns an ``InputRequiredToolResult`` (a ``ToolResult`` subclass); it
+flows back through the middleware chain as an ordinary result and the
+wire handler unwraps it into an ``InputRequiredResult`` on the response.
+
+**Raises:**
+- `NotFoundError`: If tool not found or disabled
+- `ToolError`: If tool execution fails
+- `ValidationError`: If arguments fail validation
+
+
+#### `read_resource`
+
+```python
+read_resource(self, uri: str) -> ResourceResult
+```
+
+Read a resource by URI.
+
+This is the public API for reading resources. By default, middleware is applied.
+Checks concrete resources first, then templates.
+
+**Args:**
+- `uri`: The resource URI
+- `version`: Specific version to read. If None, reads highest version.
+- `run_middleware`: If True (default), apply the middleware chain.
+Set to False when called from middleware to avoid re-applying.
+
+**Returns:**
+- ResourceResult.
+
+**Raises:**
+- `NotFoundError`: If resource not found or disabled
+- `ResourceError`: If resource read fails
+
+
+#### `render_prompt`
+
+```python
+render_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> PromptResult
+```
+
+Render a prompt by name.
+
+This is the public API for rendering prompts. By default, middleware is applied.
+Use get_prompt() to retrieve the prompt definition without rendering.
+
+**Args:**
+- `name`: The prompt name
+- `arguments`: Prompt arguments (optional)
+- `version`: Specific version to render. If None, renders highest version.
+- `run_middleware`: If True (default), apply the middleware chain.
+Set to False when called from middleware to avoid re-applying.
+
+**Returns:**
+- PromptResult.
+
+**Raises:**
+- `NotFoundError`: If prompt not found or disabled
+- `PromptError`: If prompt rendering fails
+
+
+#### `add_tool`
+
+```python
+add_tool(self, tool: Tool | Callable[..., Any]) -> Tool
+```
+
+Add a tool to the server.
+
+The tool function can optionally request a Context object by adding a parameter
+with the Context type annotation. See the @tool decorator for examples.
+
+**Args:**
+- `tool`: The Tool instance or @tool-decorated function to register
+
+**Returns:**
+- The tool instance that was added to the server.
+
+
+#### `tool`
+
+```python
+tool(self, name_or_fn: F) -> F
+```
+
+#### `tool`
+
+```python
+tool(self, name_or_fn: str | None = None) -> Callable[[F], F]
+```
+
+#### `tool`
+
+```python
+tool(self, name_or_fn: str | AnyFunction | None = None) -> Callable[[AnyFunction], FunctionTool] | FunctionTool | partial[Callable[[AnyFunction], FunctionTool] | FunctionTool]
+```
+
+Decorator to register a tool.
+
+Tools can optionally request a Context object by adding a parameter with the
+Context type annotation. The context provides access to MCP capabilities like
+logging, progress reporting, and resource access.
+
+This decorator supports multiple calling patterns:
+- @server.tool (without parentheses)
+- @server.tool (with empty parentheses)
+- @server.tool("custom_name") (with name as first argument)
+- @server.tool(name="custom_name") (with name as keyword argument)
+- server.tool(function, name="custom_name") (direct function call)
+
+**Args:**
+- `name_or_fn`: Either a function (when used as @tool), a string name, or None
+- `name`: Optional name for the tool (keyword-only, alternative to name_or_fn)
+- `description`: Optional description of what the tool does
+- `tags`: Optional set of tags for categorizing the tool
+- `output_schema`: Optional JSON schema for the tool's output
+- `annotations`: Optional annotations about the tool's behavior
+- `meta`: Optional meta information about the tool
+
+**Examples:**
+
+Register a tool with a custom name:
+```python
+@server.tool
+def my_tool(x: int) -> str:
+ return str(x)
+
+# Register a tool with a custom name
+@server.tool
+def my_tool(x: int) -> str:
+ return str(x)
+
+@server.tool("custom_name")
+def my_tool(x: int) -> str:
+ return str(x)
+
+@server.tool(name="custom_name")
+def my_tool(x: int) -> str:
+ return str(x)
+
+# Direct function call
+server.tool(my_function, name="custom_name")
+```
+
+
+#### `add_resource`
+
+```python
+add_resource(self, resource: Resource | Callable[..., Any]) -> Resource | ResourceTemplate
+```
+
+Add a resource to the server.
+
+**Args:**
+- `resource`: A Resource instance or @resource-decorated function to add
+
+**Returns:**
+- The resource instance that was added to the server.
+
+
+#### `add_template`
+
+```python
+add_template(self, template: ResourceTemplate) -> ResourceTemplate
+```
+
+Add a resource template to the server.
+
+**Args:**
+- `template`: A ResourceTemplate instance to add
+
+**Returns:**
+- The template instance that was added to the server.
+
+
+#### `resource`
+
+```python
+resource(self, uri: str) -> Callable[[F], F]
+```
+
+Decorator to register a function as a resource.
+
+The function will be called when the resource is read to generate its content.
+The function can return:
+- str for text content
+- bytes for binary content
+- other types will be converted to JSON
+
+Resources can optionally request a Context object by adding a parameter with the
+Context type annotation. The context provides access to MCP capabilities like
+logging, progress reporting, and session information.
+
+If the URI contains parameters (e.g. "resource://{param}") or the function
+has parameters, it will be registered as a template resource.
+
+**Args:**
+- `uri`: URI for the resource (e.g. "resource\://my-resource" or "resource\://{param}")
+- `name`: Optional name for the resource
+- `description`: Optional description of the resource
+- `mime_type`: Optional MIME type for the resource
+- `tags`: Optional set of tags for categorizing the resource
+- `annotations`: Optional annotations about the resource's behavior
+- `meta`: Optional meta information about the resource
+
+**Examples:**
+
+Register a resource with a custom name:
+```python
+@server.resource("resource://my-resource")
+def get_data() -> str:
+ return "Hello, world!"
+
+@server.resource("resource://my-resource")
+async get_data() -> str:
+ data = await fetch_data()
+ return f"Hello, world! {data}"
+
+@server.resource("resource://{city}/weather")
+def get_weather(city: str) -> str:
+ return f"Weather for {city}"
+
+@server.resource("resource://{city}/weather")
+async def get_weather_with_context(city: str, ctx: Context) -> str:
+ await ctx.info(f"Fetching weather for {city}")
+ return f"Weather for {city}"
+
+@server.resource("resource://{city}/weather")
+async def get_weather(city: str) -> str:
+ data = await fetch_weather(city)
+ return f"Weather for {city}: {data}"
+```
+
+
+#### `add_prompt`
+
+```python
+add_prompt(self, prompt: Prompt | Callable[..., Any]) -> Prompt
+```
+
+Add a prompt to the server.
+
+**Args:**
+- `prompt`: A Prompt instance or @prompt-decorated function to add
+
+**Returns:**
+- The prompt instance that was added to the server.
+
+
+#### `prompt`
+
+```python
+prompt(self, name_or_fn: F) -> F
+```
+
+#### `prompt`
+
+```python
+prompt(self, name_or_fn: str | None = None) -> Callable[[F], F]
+```
+
+#### `prompt`
+
+```python
+prompt(self, name_or_fn: str | AnyFunction | None = None) -> Callable[[AnyFunction], FunctionPrompt] | FunctionPrompt | partial[Callable[[AnyFunction], FunctionPrompt] | FunctionPrompt]
+```
+
+Decorator to register a prompt.
+
+ Prompts can optionally request a Context object by adding a parameter with the
+ Context type annotation. The context provides access to MCP capabilities like
+ logging, progress reporting, and session information.
+
+ This decorator supports multiple calling patterns:
+ - @server.prompt (without parentheses)
+ - @server.prompt() (with empty parentheses)
+ - @server.prompt("custom_name") (with name as first argument)
+ - @server.prompt(name="custom_name") (with name as keyword argument)
+ - server.prompt(function, name="custom_name") (direct function call)
+
+ Args:
+ name_or_fn: Either a function (when used as @prompt), a string name, or None
+ name: Optional name for the prompt (keyword-only, alternative to name_or_fn)
+ description: Optional description of what the prompt does
+ tags: Optional set of tags for categorizing the prompt
+ meta: Optional meta information about the prompt
+
+ Examples:
+
+ ```python
+ @server.prompt
+ def analyze_table(table_name: str) -> list[Message]:
+ schema = read_table_schema(table_name)
+ return [
+ {
+ "role": "user",
+ "content": f"Analyze this schema:
+{schema}"
+ }
+ ]
+
+ @server.prompt()
+ async def analyze_with_context(table_name: str, ctx: Context) -> list[Message]:
+ await ctx.info(f"Analyzing table {table_name}")
+ schema = read_table_schema(table_name)
+ return [
+ {
+ "role": "user",
+ "content": f"Analyze this schema:
+{schema}"
+ }
+ ]
+
+ @server.prompt("custom_name")
+ async def analyze_file(path: str) -> list[Message]:
+ content = await read_file(path)
+ return [
+ {
+ "role": "user",
+ "content": {
+ "type": "resource",
+ "resource": {
+ "uri": f"file://{path}",
+ "text": content
+ }
+ }
+ }
+ ]
+
+ @server.prompt(name="custom_name")
+ def another_prompt(data: str) -> list[Message]:
+ return [{"role": "user", "content": data}]
+
+ # Direct function call
+ server.prompt(my_function, name="custom_name")
+ ```
+
+
+#### `add_completion_handler`
+
+```python
+add_completion_handler(self, handler: CompletionHandler) -> None
+```
+
+Register the server's argument-completion handler.
+
+A server has a single completion handler that answers every
+`completion/complete` request, switching on the reference (a prompt or
+resource template) and the argument being completed. Registering it also
+registers the low-level `completion/complete` handler, which is what
+makes the SDK declare the completions capability — so the capability is
+advertised exactly when the server can answer. Calling this again
+replaces the handler.
+
+**Args:**
+- `handler`: A callable taking the reference, the
+`CompletionArgument`, and the optional `CompletionContext`, and
+returning candidate values (a `Completion`, a list of strings,
+or None). May be sync or async.
+
+
+#### `completion`
+
+```python
+completion(self, handler: CompletionHandler) -> CompletionHandler
+```
+
+#### `completion`
+
+```python
+completion(self) -> Callable[[CompletionHandler], CompletionHandler]
+```
+
+#### `completion`
+
+```python
+completion(self, handler: CompletionHandler | None = None) -> CompletionHandler | Callable[[CompletionHandler], CompletionHandler]
+```
+
+Decorator to register the server's argument-completion handler.
+
+The handler answers `completion/complete` requests for prompt arguments
+and resource-template parameters. It receives the reference being
+completed, the argument (its name and the partial value typed so far),
+and the context of arguments already supplied, and returns candidate
+values. Return a list of strings, a `Completion` (to include pagination
+hints), or None when the reference/argument is not one it handles — an
+unhandled reference yields an empty completion, not an error.
+
+Registering a handler declares the completions capability; a server with
+none does not advertise it. This works identically on the handshake and
+modern protocol eras.
+
+Supports both `@mcp.completion` and `@mcp.completion()`.
+
+Example:
+
+ ```python
+ from fastmcp import FastMCP
+ from mcp_types import Completion, PromptReference
+
+ mcp = FastMCP("Completion Server")
+
+ @mcp.prompt
+ def poem(theme: str) -> str:
+ return f"Write a poem about {theme}"
+
+ @mcp.completion
+ def complete(ref, argument, context):
+ if isinstance(ref, PromptReference) and ref.name == "poem":
+ if argument.name == "theme":
+ options = ["nature", "love", "adventure"]
+ return [o for o in options if o.startswith(argument.value)]
+ return None
+ ```
+
+
+#### `mount`
+
+```python
+mount(self, server: FastMCP[LifespanResultT], namespace: str | None = None, tool_names: dict[str, str] | None = None) -> None
+```
+
+Mount another FastMCP server on this server with an optional namespace.
+
+Mounting establishes a dynamic connection between servers. When a client
+interacts with a mounted server's objects through the parent server, requests
+are forwarded to the mounted server in real-time. This means changes to the
+mounted server are immediately reflected when accessed through the parent.
+
+When a server is mounted with a namespace:
+- Tools from the mounted server are accessible with namespaced names.
+ Example: If server has a tool named "get_weather", it will be available as "namespace_get_weather".
+- Resources are accessible with namespaced URIs.
+ Example: If server has a resource with URI "weather://forecast", it will be available as
+ "weather://namespace/forecast".
+- Templates are accessible with namespaced URI templates.
+ Example: If server has a template with URI "weather://location/{id}", it will be available
+ as "weather://namespace/location/{id}".
+- Prompts are accessible with namespaced names.
+ Example: If server has a prompt named "weather_prompt", it will be available as
+ "namespace_weather_prompt".
+
+When a server is mounted without a namespace (namespace=None), its tools, resources, templates,
+and prompts are accessible with their original names. Multiple servers can be mounted
+without namespaces, and they will be tried in order until a match is found.
+
+The mounted server's lifespan is executed when the parent server starts, and its
+middleware chain is invoked for all operations (tool calls, resource reads, prompts).
+
+**Args:**
+- `server`: The FastMCP server to mount.
+- `namespace`: Optional namespace to use for the mounted server's objects. If None,
+the server's objects are accessible with their original names.
+- `tool_names`: Optional mapping of original tool names to custom names. Use this
+to override namespaced names. Keys are the original tool names from the
+mounted server.
+
+
+#### `from_openapi`
+
+```python
+from_openapi(cls, openapi_spec: dict[str, Any], client: httpx2.AsyncClient | None = None, name: str = 'OpenAPI Server', route_maps: list[RouteMap] | None = None, route_map_fn: OpenAPIRouteMapFn | None = None, mcp_component_fn: OpenAPIComponentFn | None = None, mcp_names: dict[str, str] | None = None, tags: set[str] | None = None, validate_output: bool = True, **settings: Any) -> Self
+```
+
+Create a FastMCP server from an OpenAPI specification.
+
+**Args:**
+- `openapi_spec`: OpenAPI schema as a dictionary
+- `client`: Optional httpx2 AsyncClient for making HTTP requests.
+If not provided, a default client is created using the first
+server URL from the OpenAPI spec with a 30-second timeout.
+Legacy httpx clients are temporarily accepted with a deprecation
+warning.
+- `name`: Name for the MCP server
+- `route_maps`: Optional list of RouteMap objects defining route mappings
+- `route_map_fn`: Optional callable for advanced route type mapping
+- `mcp_component_fn`: Optional callable for component customization
+- `mcp_names`: Optional dictionary mapping operationId to component names
+- `tags`: Optional set of tags to add to all components
+- `validate_output`: If True (default), tools use the output schema
+extracted from the OpenAPI spec for response validation. If
+False, a permissive schema is used instead, allowing any
+response structure while still returning structured JSON.
+- `**settings`: Additional settings passed to FastMCP
+
+**Returns:**
+- A FastMCP server with an OpenAPIProvider attached.
+
+
+#### `from_fastapi`
+
+```python
+from_fastapi(cls, app: Any, name: str | None = None, route_maps: list[RouteMap] | None = None, route_map_fn: OpenAPIRouteMapFn | None = None, mcp_component_fn: OpenAPIComponentFn | None = None, mcp_names: dict[str, str] | None = None, httpx_client_kwargs: dict[str, Any] | None = None, tags: set[str] | None = None, **settings: Any) -> Self
+```
+
+Create a FastMCP server from a FastAPI application.
+
+**Args:**
+- `app`: FastAPI application instance
+- `name`: Name for the MCP server (defaults to app.title)
+- `route_maps`: Optional list of RouteMap objects defining route mappings
+- `route_map_fn`: Optional callable for advanced route type mapping
+- `mcp_component_fn`: Optional callable for component customization
+- `mcp_names`: Optional dictionary mapping operationId to component names
+- `httpx_client_kwargs`: Optional kwargs passed to httpx2.AsyncClient.
+Use this to configure timeout and other client settings.
+- `tags`: Optional set of tags to add to all components
+- `**settings`: Additional settings passed to FastMCP
+
+**Returns:**
+- A FastMCP server with an OpenAPIProvider attached.
+
+
+#### `generate_name`
+
+```python
+generate_name(cls, name: str | None = None) -> str
+```
diff --git a/docs/python-sdk/fastmcp-server-session_scoped_event_store.mdx b/docs/python-sdk/fastmcp-server-session_scoped_event_store.mdx
new file mode 100644
index 000000000..b595a435b
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-session_scoped_event_store.mdx
@@ -0,0 +1,31 @@
+---
+title: session_scoped_event_store
+sidebarTitle: session_scoped_event_store
+---
+
+# `fastmcp.server.session_scoped_event_store`
+
+
+Lightweight session scoping for Streamable HTTP event stores.
+
+## Classes
+
+### `SessionScopedEventStore`
+
+
+EventStore adapter that isolates stream IDs to one transport session.
+
+
+**Methods:**
+
+#### `store_event`
+
+```python
+store_event(self, stream_id: StreamId, message: JSONRPCMessage | None) -> EventId
+```
+
+#### `replay_events_after`
+
+```python
+replay_events_after(self, last_event_id: EventId, send_callback: EventCallback) -> StreamId | None
+```
diff --git a/docs/python-sdk/fastmcp-server-sessions.mdx b/docs/python-sdk/fastmcp-server-sessions.mdx
new file mode 100644
index 000000000..0caea6b13
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-sessions.mdx
@@ -0,0 +1,319 @@
+---
+title: sessions
+sidebarTitle: sessions
+---
+
+# `fastmcp.server.sessions`
+
+
+Stateless session state: server-side per-user and per-session storage.
+
+Modern (2026-07-28) MCP connections are stateless by construction — every
+request builds a fresh connection whose in-memory state is discarded when the
+request returns. This module gives tools two explicit ways to keep state across
+calls, both backed by the server's existing state store and both isolated by the
+authenticated principal rather than by any client-declared identifier.
+
+- `Session`: async `get`/`set`/`delete`/`clear` over a single dict stored under
+ one key, scoped to a `(principal, session_id)` pair. This is the state-accessor
+ object a handler works with — the value the standalone `get_session(id)`
+ returns and the value injected for a `UserSession` parameter.
+- `session: UserSession` (injected): a per-user bucket, dependency-injected like
+ `ctx: Context` and keyed by the request's authenticated principal. Requires
+ auth. `UserSession` is the injection annotation; the injected value is a
+ `Session`. It is always available under auth — no `create_session`, no
+ provider, no validation.
+- `session_id: SessionId` (argument): a required string the agent supplies,
+ resolved with the standalone `await get_session(session_id)`. The id is
+ minted
+ by `create_session`; an id that was never created (or was created under a
+ different principal) is rejected. This validation is the whole guarantee — an
+ unminted id never resolves, so nothing enforces provider registration.
+- `SessionProvider`: a `Provider` contributing `create_session` / `end_session`
+ tools. Register it with `mcp.add_provider(SessionProvider())` so a tool that
+ takes `session_id` has a way to mint ids; without it, no id can be created, so
+ those tools simply cannot resolve a session.
+
+Isolation is the authenticated principal, not the session id. State keyed by
+`(principal, session_id)` means a request under principal B can never address
+principal A's keys, no matter what `session_id` it passes; the id only organizes
+sessions within a principal. Without auth there is no principal wall — a session
+id is a bearer capability and sessions are not a boundary between clients.
+
+
+## Functions
+
+### `current_principal`
+
+```python
+current_principal() -> str | None
+```
+
+
+The authenticated principal for the current request as a compact JSON string.
+
+Returns the `(client_id, issuer, subject)` triple encoded as compact JSON, or
+`None` on an unauthenticated request. Two users of one OAuth client are
+distinct principals whenever the token verifier supplies a subject.
+
+
+### `session_storage_key`
+
+```python
+session_storage_key(principal: str | None, session_id: str) -> str
+```
+
+
+The single storage key holding a session's state dict.
+
+Keyed by `(principal, session_id)`: the principal is the isolation wall, the
+id organizes sessions within it. A session's whole state lives under this one
+key as a dict, so one key means one store TTL per session and `end` is a
+single delete.
+
+
+### `session_id_parameter_names`
+
+```python
+session_id_parameter_names(fn: Callable[..., object]) -> tuple[str, ...]
+```
+
+
+Names of a function's parameters annotated with `SessionId`.
+
+Scans resolved type hints for `Annotated[str, _SessionIdMarker()]` metadata.
+Returns an empty tuple when the hints cannot be resolved (the function then
+simply carries no auto-populated session-id description).
+
+`functools.partial` is unwrapped first, since `get_type_hints` rejects a
+partial object — FastMCP supports registering a partial as a tool, and its
+schema is still built from the underlying function, so its `SessionId`
+parameters must be detected here too. Parameters the partial has already
+bound — positionally or by keyword — are dropped, matching the tool's actual
+argument surface (the partial's own signature already reflects this).
+
+
+### `CurrentSession`
+
+```python
+CurrentSession() -> Session
+```
+
+
+Inject the per-user `Session` for the current authenticated principal.
+
+Rarely written explicitly — a `session: UserSession` parameter is rewritten
+to this. Provided for parity with `CurrentContext()` when an explicit default
+is preferred.
+
+
+### `OptionalCurrentSession`
+
+```python
+OptionalCurrentSession() -> Session | None
+```
+
+
+Inject the per-user `Session`, or `None` when the request is unauthenticated.
+
+Rarely written explicitly — a `session: UserSession | None = None` parameter
+is rewritten to this. Provided for parity with `OptionalCurrentContext()`.
+
+
+### `create_session`
+
+```python
+create_session() -> str
+```
+
+
+Create a new session and return its identifier.
+
+Mints an unguessable `uuid4`, records an initial session owned by the current
+principal, and returns the id as a string. Store it and pass it back as a
+`session_id` argument on later calls to persist state across a session — only
+an id created this way resolves. State is keyed by the authenticated
+principal, so the id organizes sessions within a user; on an unauthenticated
+connection the id is the only thing standing between callers, which is why it
+is unguessable.
+
+
+### `end_session`
+
+```python
+end_session(session_id: SessionId) -> str
+```
+
+
+End a session and delete all of its state.
+
+Validates the id like any other resolution (an unknown or foreign id is
+rejected), then deletes the session's key so the id no longer resolves.
+
+
+## Classes
+
+### `SessionAuthError`
+
+
+An injected `session: UserSession` was requested with no authenticated principal.
+
+Per-user session injection keys off the request's authenticated principal, so
+it is only meaningful under auth. A tool that needs cross-call state without
+auth should take a `session_id: SessionId` argument instead.
+
+
+### `InvalidSession`
+
+
+A session id did not resolve to a session created under the current principal.
+
+Raised by `get_session(session_id)` when the id was never created, or was
+created under a different principal. The public message is deliberately
+generic — the specific reason (which id, which principal) is logged at debug
+level, not returned to the caller, so an attacker cannot distinguish "unknown
+id" from "belongs to someone else".
+
+
+### `Session`
+
+
+Async accessors over one `(principal, session_id)` bucket of state.
+
+A session's state is a single dict stored under one key. That dict holds user
+state in a `state` sub-dict and a small creation marker alongside it, so a
+created-but-empty session is still distinguishable from a missing one.
+`get`/`set`/`delete` read-modify-write the sub-dict; `clear` empties the
+sub-dict but keeps the session valid; `end` deletes the whole key. Writes
+never impose a TTL — retention is entirely the server store's (configure it on
+the store you pass to `FastMCP(session_state_store=...)`).
+
+Concurrent writes to one session race on the read-modify-write; session state
+is small and typically driven serially by one agent, so this is acceptable.
+
+
+**Methods:**
+
+#### `id`
+
+```python
+id(self) -> str | None
+```
+
+The session's identifier, or `None` for an injected per-user session.
+
+For a session resolved from a `session_id` argument (or minted by
+`create_session`) this is that id. An injected `UserSession` has no
+distinct id — its bucket is the authenticated user — so it is `None`; the
+internal principal-derived key is deliberately not exposed here.
+
+
+#### `get`
+
+```python
+get(self, key: str, default: Any = None) -> Any
+```
+
+Return the value for `key`, or `default` when it is not set.
+
+
+#### `set`
+
+```python
+set(self, key: str, value: Any) -> None
+```
+
+Store `value` under `key` in this session (read-modify-write).
+
+Preserves the creation marker: only the user-state sub-dict is touched.
+
+
+#### `delete`
+
+```python
+delete(self, key: str) -> None
+```
+
+Remove `key` from this session, if present (preserves the marker).
+
+
+#### `clear`
+
+```python
+clear(self) -> None
+```
+
+Empty the session's user state but keep the session valid.
+
+The user-state sub-dict is reset to empty while the creation marker stays
+in place, so a cleared session still resolves through `get_session`.
+To invalidate a session entirely, use `end` (what `end_session` calls).
+
+
+#### `end`
+
+```python
+end(self) -> None
+```
+
+Invalidate the session — delete its one key and all of its state.
+
+After this the id no longer resolves through `get_session`. This is
+what `end_session` calls; `clear` only empties state and keeps the session.
+
+
+### `UserSession`
+
+
+Annotation marker for the injected per-user session.
+
+A `session: UserSession` parameter is **dependency-injected** like
+`ctx: Context`: keyed by the request's authenticated principal, excluded from
+the input schema, and requiring auth (it raises `SessionAuthError` with no
+principal). It doubles as the injection *annotation* and the injected
+type — the value a handler receives is a `UserSession`, which subclasses
+`Session`, so `await session.get(...)`, `.set`, `.delete`, and `.clear` all
+work exactly as on any other `Session`.
+
+Unlike `session_id: SessionId`, the per-user bucket needs no `create_session`,
+no `SessionProvider`, and no validation — it is always available under auth,
+keyed directly by the caller's identity.
+
+```python
+from fastmcp.server.sessions import UserSession
+
+@mcp.tool
+async def remember(fact: str, session: UserSession) -> str:
+ await session.set("fact", fact)
+ return "noted"
+```
+
+Subclasses `Session` only so the framework's type-based injection detector can
+key off it; it adds no behavior of its own.
+
+
+### `SessionProvider`
+
+
+Provider contributing the session lifecycle tools.
+
+Register it whenever a tool declares a `session_id: SessionId` argument:
+
+```python
+from fastmcp.server.sessions import SessionProvider
+
+mcp.add_provider(SessionProvider())
+```
+
+It registers two tools:
+
+- `create_session()` mints an unguessable `uuid4`, records the session, and
+ returns the id.
+- `end_session(session_id)` invalidates that session and deletes its state.
+
+It owns no storage (session state lives in the server's configured
+`session_state_store`) and imposes no TTL (retention is the store's). It
+exists to mint and end owned session ids. Registration is not enforced: with
+no provider, no id can be created, so every `get_session(...)` rejects —
+a `session_id` tool without a provider simply cannot resolve a session.
+
diff --git a/docs/python-sdk/fastmcp-server-telemetry.mdx b/docs/python-sdk/fastmcp-server-telemetry.mdx
new file mode 100644
index 000000000..874fcf1e9
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-telemetry.mdx
@@ -0,0 +1,117 @@
+---
+title: telemetry
+sidebarTitle: telemetry
+---
+
+# `fastmcp.server.telemetry`
+
+
+Server-side telemetry helpers.
+
+## Functions
+
+### `get_auth_span_attributes`
+
+```python
+get_auth_span_attributes() -> dict[str, str]
+```
+
+
+Get auth attributes for the current request, if authenticated.
+
+
+### `get_session_span_attributes`
+
+```python
+get_session_span_attributes() -> dict[str, str]
+```
+
+
+Get session attributes for the current request.
+
+
+### `get_protocol_span_attributes`
+
+```python
+get_protocol_span_attributes() -> dict[str, str]
+```
+
+
+Get the negotiated MCP protocol version for the current request.
+
+Mirrors the `mcp.protocol.version` attribute the SDK's own
+`OpenTelemetryMiddleware` sets — FastMCP drops that middleware to avoid a
+duplicate SERVER span, so this restores the attribute on FastMCP's span.
+
+
+### `record_span_exception`
+
+```python
+record_span_exception(span: Span, e: Exception) -> None
+```
+
+
+Record an exception and error status on a span.
+
+
+### `seam_span`
+
+```python
+seam_span(method: str, server_name: str) -> Generator[Span, None, None]
+```
+
+
+Open the per-request SERVER span at the FastMCP middleware seam.
+
+The span is named after the method and carries the base MCP attributes
+(`mcp.method.name`, `fastmcp.server.name`, auth/session context) so
+seam-only methods (`logging/setLevel`, `tasks/*`, `ping`, `initialize`, ...)
+are fully attributed even though they never reach the high-level path. It is
+marked with `SEAM_SPAN_MARKER` so a later `server_span` call in the
+high-level path enriches this span with component attributes instead of
+opening a second one. Exceptions raised anywhere below the seam — including
+rejections *before* the high-level path (auth, not-found, middleware vetoes)
+that would otherwise produce no SERVER span at all — are recorded here.
+
+In `propagation_only` mode no span is opened at all — this is the one place
+that has to know the difference, because the seam is where the incoming
+`_meta` parent context is applied for the whole request.
+
+
+### `server_span`
+
+```python
+server_span(name: str, method: str, server_name: str, component_type: str, component_key: str, resource_uri: str | None = None, tool_name: str | None = None, prompt_name: str | None = None) -> Generator[Span, None, None]
+```
+
+
+Emit or enrich a SERVER span with standard MCP attributes and auth context.
+
+When the current active span is the request's seam span (opened by
+`FastMCPServerMiddleware` and marked with `SEAM_SPAN_MARKER`), this sets the
+component attributes on that span and yields it *without* starting a second
+span — so failures rejected before this point and the successful high-level
+call share one richly-attributed SERVER span. Otherwise (non-seam contexts,
+e.g. in-process `mcp.call_tool()` calls that bypass the dispatcher) it opens a
+new SERVER span as before.
+
+Automatically records any exception on the span and sets error status.
+
+In `propagation_only` mode no span is opened or enriched. The seam has
+normally already attached the incoming parent context for this request;
+doing it again here is a no-op, and covers the in-process callers that
+bypass the dispatcher and so never reach the seam at all.
+
+
+### `delegate_span`
+
+```python
+delegate_span(name: str, provider_type: str, component_key: str, method: str | None = None) -> Generator[Span, None, None]
+```
+
+
+Create an INTERNAL span for provider delegation.
+
+Used by FastMCPProvider when delegating to mounted servers.
+Automatically records any exception on the span and sets error status.
+
diff --git a/docs/python-sdk/fastmcp-server-transforms.mdx b/docs/python-sdk/fastmcp-server-transforms.mdx
new file mode 100644
index 000000000..7e6d19054
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-transforms.mdx
@@ -0,0 +1,193 @@
+---
+title: transforms
+sidebarTitle: transforms
+---
+
+# `fastmcp.server.transforms`
+
+
+Transform system for component transformations.
+
+Transforms modify components (tools, resources, prompts). List operations use a pure
+function pattern where transforms receive sequences and return transformed sequences.
+Get operations use a middleware pattern with `call_next` to chain lookups.
+
+Unlike middleware (which operates on requests), transforms are observable by the
+system for task registration, tag filtering, and component introspection.
+
+Example:
+ ```python
+ from fastmcp import FastMCP
+ from fastmcp.server.transforms import Namespace
+
+ server = FastMCP("Server")
+ mount = server.mount(other_server)
+ mount.add_transform(Namespace("api")) # Tools become api_toolname
+ ```
+
+
+## Classes
+
+### `GetToolNext`
+
+
+Protocol for get_tool call_next functions.
+
+
+### `GetResourceNext`
+
+
+Protocol for get_resource call_next functions.
+
+
+### `GetResourceTemplateNext`
+
+
+Protocol for get_resource_template call_next functions.
+
+
+### `GetPromptNext`
+
+
+Protocol for get_prompt call_next functions.
+
+
+### `Transform`
+
+
+Base class for component transformations.
+
+List operations use a pure function pattern: transforms receive sequences
+and return transformed sequences. Get operations use a middleware pattern
+with `call_next` to chain lookups.
+
+
+**Methods:**
+
+#### `list_tools`
+
+```python
+list_tools(self, tools: Sequence[Tool]) -> Sequence[Tool]
+```
+
+List tools with transformation applied.
+
+**Args:**
+- `tools`: Sequence of tools to transform.
+
+**Returns:**
+- Transformed sequence of tools.
+
+
+#### `get_tool`
+
+```python
+get_tool(self, name: str, call_next: GetToolNext) -> Tool | None
+```
+
+Get a tool by name.
+
+**Args:**
+- `name`: The requested tool name (may be transformed).
+- `call_next`: Callable to get tool from downstream.
+- `version`: Optional version filter to apply.
+
+**Returns:**
+- The tool if found, None otherwise.
+
+
+#### `list_resources`
+
+```python
+list_resources(self, resources: Sequence[Resource]) -> Sequence[Resource]
+```
+
+List resources with transformation applied.
+
+**Args:**
+- `resources`: Sequence of resources to transform.
+
+**Returns:**
+- Transformed sequence of resources.
+
+
+#### `get_resource`
+
+```python
+get_resource(self, uri: str, call_next: GetResourceNext) -> Resource | None
+```
+
+Get a resource by URI.
+
+**Args:**
+- `uri`: The requested resource URI (may be transformed).
+- `call_next`: Callable to get resource from downstream.
+- `version`: Optional version filter to apply.
+
+**Returns:**
+- The resource if found, None otherwise.
+
+
+#### `list_resource_templates`
+
+```python
+list_resource_templates(self, templates: Sequence[ResourceTemplate]) -> Sequence[ResourceTemplate]
+```
+
+List resource templates with transformation applied.
+
+**Args:**
+- `templates`: Sequence of resource templates to transform.
+
+**Returns:**
+- Transformed sequence of resource templates.
+
+
+#### `get_resource_template`
+
+```python
+get_resource_template(self, uri: str, call_next: GetResourceTemplateNext) -> ResourceTemplate | None
+```
+
+Get a resource template by URI.
+
+**Args:**
+- `uri`: The requested template URI (may be transformed).
+- `call_next`: Callable to get template from downstream.
+- `version`: Optional version filter to apply.
+
+**Returns:**
+- The resource template if found, None otherwise.
+
+
+#### `list_prompts`
+
+```python
+list_prompts(self, prompts: Sequence[Prompt]) -> Sequence[Prompt]
+```
+
+List prompts with transformation applied.
+
+**Args:**
+- `prompts`: Sequence of prompts to transform.
+
+**Returns:**
+- Transformed sequence of prompts.
+
+
+#### `get_prompt`
+
+```python
+get_prompt(self, name: str, call_next: GetPromptNext) -> Prompt | None
+```
+
+Get a prompt by name.
+
+**Args:**
+- `name`: The requested prompt name (may be transformed).
+- `call_next`: Callable to get prompt from downstream.
+- `version`: Optional version filter to apply.
+
+**Returns:**
+- The prompt if found, None otherwise.
+
diff --git a/docs/python-sdk/fastmcp-settings.mdx b/docs/python-sdk/fastmcp-settings.mdx
index b6f401939..a0d999d27 100644
--- a/docs/python-sdk/fastmcp-settings.mdx
+++ b/docs/python-sdk/fastmcp-settings.mdx
@@ -7,7 +7,7 @@ sidebarTitle: settings
## Classes
-### `Settings`
+### `Settings`
FastMCP settings.
@@ -15,7 +15,7 @@ FastMCP settings.
**Methods:**
-#### `get_setting`
+#### `get_setting`
```python
get_setting(self, attr: str) -> Any
@@ -25,7 +25,7 @@ Get a setting. If the setting contains one or more `__`, it will be
treated as a nested setting.
-#### `set_setting`
+#### `set_setting`
```python
set_setting(self, attr: str, value: Any) -> None
@@ -35,7 +35,7 @@ Set a setting. If the setting contains one or more `__`, it will be
treated as a nested setting.
-#### `normalize_log_level`
+#### `normalize_log_level`
```python
normalize_log_level(cls, v)
diff --git a/docs/python-sdk/fastmcp-telemetry.mdx b/docs/python-sdk/fastmcp-telemetry.mdx
index 8e034ff6e..3cb06ca12 100644
--- a/docs/python-sdk/fastmcp-telemetry.mdx
+++ b/docs/python-sdk/fastmcp-telemetry.mdx
@@ -31,7 +31,52 @@ Example usage with SDK:
## Functions
-### `get_tracer`
+### `telemetry_mode`
+
+```python
+telemetry_mode() -> 'TelemetryMode'
+```
+
+
+Resolve the effective telemetry mode for the current context.
+
+This is `fastmcp.settings.telemetry_mode`, except that an active
+`suppress_fastmcp_telemetry()` block downgrades `native` to
+`propagation_only`. Suppression never upgrades or overrides `off`: `off`
+means FastMCP touches nothing, and a narrower request to skip FastMCP's
+spans cannot re-enable the context propagation `off` deliberately omits.
+
+
+### `native_spans_enabled`
+
+```python
+native_spans_enabled() -> bool
+```
+
+
+Whether FastMCP should create its own spans right now.
+
+
+### `suppress_fastmcp_telemetry`
+
+```python
+suppress_fastmcp_telemetry() -> Iterator[None]
+```
+
+
+Suppress FastMCP's own spans without disabling trace propagation.
+
+Scoped equivalent of `telemetry_mode="propagation_only"`, for callers that
+embed FastMCP inside their own instrumented stack and want to own the MCP
+span hierarchy for a specific block. Narrower than OpenTelemetry's global
+instrumentation suppression: only FastMCP's spans are skipped, so nested
+instrumentation (HTTP clients, databases) keeps emitting, and trace context
+still flows through `_meta` so those spans are parented correctly.
+
+Has no effect when `telemetry_mode` is already `off`.
+
+
+### `get_tracer`
```python
get_tracer(version: str | None = None) -> Tracer
@@ -42,21 +87,22 @@ Get the FastMCP tracer for creating spans.
Instrumentation is on by default. FastMCP uses only the OpenTelemetry API,
so span creation is a no-op with negligible overhead unless an OpenTelemetry
-SDK and exporter are configured. Set `fastmcp.settings.enable_telemetry` to
-False (env `FASTMCP_ENABLE_TELEMETRY=false`) to turn instrumentation off
-entirely, in which case this returns a pass-through tracer that leaves the
-current OTel context untouched even when an SDK is configured.
+SDK and exporter are configured. When `fastmcp.settings.telemetry_mode` is
+`propagation_only` or `off` — or the caller is inside a
+`suppress_fastmcp_telemetry()` block — this returns a pass-through tracer
+that creates no spans and leaves the current OTel context untouched even
+when an SDK is configured.
**Args:**
- `version`: Optional version string for the instrumentation
**Returns:**
-- A tracer instance. Returns a non-attaching pass-through tracer if
-- telemetry is disabled; span creation is otherwise a no-op unless an SDK
-- is configured.
+- A tracer instance. Returns a non-attaching pass-through tracer when
+- FastMCP's own spans are disabled; span creation is otherwise a no-op
+- unless an SDK is configured.
-### `inject_trace_context`
+### `inject_trace_context`
```python
inject_trace_context(meta: dict[str, Any] | None = None) -> dict[str, Any] | None
@@ -73,7 +119,7 @@ Inject current trace context into a meta dict for MCP request propagation.
- or None if no trace context to inject and meta was None
-### `record_span_error`
+### `record_span_error`
```python
record_span_error(span: Span, exception: BaseException) -> None
@@ -83,7 +129,7 @@ record_span_error(span: Span, exception: BaseException) -> None
Record an exception on a span and set error status.
-### `restore_dropped_attributes`
+### `restore_dropped_attributes`
```python
restore_dropped_attributes(span: Span, attrs: Mapping[str, otel_types.AttributeValue]) -> None
@@ -133,7 +179,7 @@ kept at call sites so it reads alongside the sibling `is_recording()`
guards already in those functions.
-### `extract_trace_context`
+### `extract_trace_context`
```python
extract_trace_context(meta: dict[str, Any] | None) -> Context
diff --git a/docs/python-sdk/fastmcp-utilities-docstring_parsing.mdx b/docs/python-sdk/fastmcp-utilities-docstring_parsing.mdx
index b8cacc823..bceb0256e 100644
--- a/docs/python-sdk/fastmcp-utilities-docstring_parsing.mdx
+++ b/docs/python-sdk/fastmcp-utilities-docstring_parsing.mdx
@@ -16,7 +16,7 @@ callers.
## Functions
-### `parse_docstring`
+### `parse_docstring`
```python
parse_docstring(fn: Callable[..., Any]) -> ParsedDocstring
@@ -32,7 +32,7 @@ docstring as the description with no parameter descriptions.
## Classes
-### `ParsedDocstring`
+### `ParsedDocstring`
The extracted description and per-parameter descriptions from a docstring.
diff --git a/docs/python-sdk/fastmcp-utilities-exceptions.mdx b/docs/python-sdk/fastmcp-utilities-exceptions.mdx
index 169e66d65..129ad5a67 100644
--- a/docs/python-sdk/fastmcp-utilities-exceptions.mdx
+++ b/docs/python-sdk/fastmcp-utilities-exceptions.mdx
@@ -7,13 +7,53 @@ sidebarTitle: exceptions
## Functions
-### `iter_exc`
+### `is_http_status_error`
+
+```python
+is_http_status_error(exc: BaseException) -> bool
+```
+
+
+Return whether an exception is an httpx2 or legacy-httpx status error.
+
+
+### `get_http_status_code`
+
+```python
+get_http_status_code(exc: BaseException) -> int | None
+```
+
+
+Return the response status code from a recognized HTTP status error.
+
+
+### `is_timeout_error`
+
+```python
+is_timeout_error(exc: BaseException) -> bool
+```
+
+
+Return whether an exception is an httpx2 or legacy-httpx timeout.
+
+
+### `is_request_error`
+
+```python
+is_request_error(exc: BaseException) -> bool
+```
+
+
+Return whether an exception is an httpx2 or legacy-httpx request error.
+
+
+### `iter_exc`
```python
iter_exc(group: BaseExceptionGroup)
```
-### `get_catch_handlers`
+### `get_catch_handlers`
```python
get_catch_handlers() -> Mapping[type[BaseException] | Iterable[type[BaseException]], Callable[[BaseExceptionGroup[Any]], Any]]
diff --git a/docs/python-sdk/fastmcp-utilities-inspect.mdx b/docs/python-sdk/fastmcp-utilities-inspect.mdx
index fca4da868..d2aca51d1 100644
--- a/docs/python-sdk/fastmcp-utilities-inspect.mdx
+++ b/docs/python-sdk/fastmcp-utilities-inspect.mdx
@@ -42,7 +42,7 @@ Extract information from a FastMCP v1.x instance using a Client.
- FastMCPInfo dataclass containing the extracted information
-### `inspect_fastmcp`
+### `inspect_fastmcp`
```python
inspect_fastmcp(mcp: FastMCP[Any] | SDKServer) -> FastMCPInfo
@@ -61,7 +61,7 @@ and uses the appropriate extraction method.
- FastMCPInfo dataclass containing the extracted information
-### `format_fastmcp_info`
+### `format_fastmcp_info`
```python
format_fastmcp_info(info: FastMCPInfo) -> bytes
@@ -73,7 +73,7 @@ Format FastMCPInfo as FastMCP-specific JSON.
This includes FastMCP-specific fields like tags, enabled, annotations, etc.
-### `format_mcp_info`
+### `format_mcp_info`
```python
format_mcp_info(mcp: FastMCP[Any] | SDKServer) -> bytes
@@ -86,7 +86,7 @@ Uses Client to get the standard MCP protocol format with camelCase fields.
Includes version metadata at the top level.
-### `format_info`
+### `format_info`
```python
format_info(mcp: FastMCP[Any] | SDKServer, format: InspectFormat | Literal['fastmcp', 'mcp'], info: FastMCPInfo | None = None) -> bytes
@@ -136,7 +136,7 @@ Information about a resource template.
Information extracted from a FastMCP instance.
-### `InspectFormat`
+### `InspectFormat`
Output format for inspect command.
diff --git a/docs/python-sdk/fastmcp-utilities-json_schema.mdx b/docs/python-sdk/fastmcp-utilities-json_schema.mdx
index 8f8e580bf..654108a63 100644
--- a/docs/python-sdk/fastmcp-utilities-json_schema.mdx
+++ b/docs/python-sdk/fastmcp-utilities-json_schema.mdx
@@ -7,7 +7,17 @@ sidebarTitle: json_schema
## Functions
-### `require_discriminator_property`
+### `replace_refs`
+
+```python
+replace_refs(*args: Any, **kwargs: Any) -> Any
+```
+
+
+Call jsonref lazily while preserving the module's patchable boundary.
+
+
+### `require_discriminator_property`
```python
require_discriminator_property(schema: dict[str, Any]) -> dict[str, Any]
@@ -24,7 +34,7 @@ model with ``union_tag_not_found``. No-op if there is no string
``propertyName``.
-### `dereference_refs`
+### `dereference_refs`
```python
dereference_refs(schema: dict[str, Any]) -> dict[str, Any]
@@ -57,7 +67,7 @@ schemas from untrusted servers.
- when no longer needed
-### `resolve_root_ref`
+### `resolve_root_ref`
```python
resolve_root_ref(schema: dict[str, Any]) -> dict[str, Any]
@@ -79,7 +89,7 @@ the referenced definition while preserving $defs for nested references.
- if no resolution is needed
-### `compress_schema`
+### `compress_schema`
```python
compress_schema(schema: dict[str, Any], prune_params: list[str] | None = None, prune_additional_properties: bool = False, prune_titles: bool = False, dereference: bool = False) -> dict[str, Any]
diff --git a/docs/python-sdk/fastmcp-utilities-logging.mdx b/docs/python-sdk/fastmcp-utilities-logging.mdx
index f3b58bf7e..4dde3d509 100644
--- a/docs/python-sdk/fastmcp-utilities-logging.mdx
+++ b/docs/python-sdk/fastmcp-utilities-logging.mdx
@@ -10,7 +10,7 @@ Logging utilities for FastMCP.
## Functions
-### `get_logger`
+### `get_logger`
```python
get_logger(name: str) -> logging.Logger
@@ -26,7 +26,7 @@ Get a logger nested under FastMCP namespace.
- a configured logger instance
-### `configure_logging`
+### `configure_logging`
```python
configure_logging(level: Literal['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'] | int = 'INFO', logger: logging.Logger | None = None, enable_rich_tracebacks: bool | None = None, **rich_kwargs: Any) -> None
@@ -41,7 +41,7 @@ Configure logging for FastMCP.
- `rich_kwargs`: the parameters to use for creating RichHandler
-### `temporary_log_level`
+### `temporary_log_level`
```python
temporary_log_level(level: str | None, logger: logging.Logger | None = None, enable_rich_tracebacks: bool | None = None, **rich_kwargs: Any)
diff --git a/docs/python-sdk/fastmcp-utilities-prefab.mdx b/docs/python-sdk/fastmcp-utilities-prefab.mdx
new file mode 100644
index 000000000..b03d7b185
--- /dev/null
+++ b/docs/python-sdk/fastmcp-utilities-prefab.mdx
@@ -0,0 +1,61 @@
+---
+title: prefab
+sidebarTitle: prefab
+---
+
+# `fastmcp.utilities.prefab`
+
+
+Lazy helpers for FastMCP's optional Prefab UI integration.
+
+## Functions
+
+### `prefab_available`
+
+```python
+prefab_available() -> bool
+```
+
+
+Return whether Prefab UI is installed without importing it.
+
+
+### `is_prefab_type`
+
+```python
+is_prefab_type(candidate: Any) -> bool
+```
+
+
+Return whether a type is a Prefab app or component type.
+
+
+### `is_prefab_app`
+
+```python
+is_prefab_app(value: Any) -> bool
+```
+
+
+Return whether a value is a Prefab app.
+
+
+### `is_prefab_component`
+
+```python
+is_prefab_component(value: Any) -> bool
+```
+
+
+Return whether a value is a Prefab component.
+
+
+### `prefab_app_from_component`
+
+```python
+prefab_app_from_component(component: Any) -> Any
+```
+
+
+Wrap a Prefab component in a Prefab app.
+