diff --git a/docs/python-sdk-pages.json b/docs/python-sdk-pages.json
index e55c709df..86cfabc6b 100644
--- a/docs/python-sdk-pages.json
+++ b/docs/python-sdk-pages.json
@@ -196,6 +196,7 @@
"python-sdk/fastmcp-server-auth-providers-in_memory",
"python-sdk/fastmcp-server-auth-providers-introspection",
"python-sdk/fastmcp-server-auth-providers-jwt",
+ "python-sdk/fastmcp-server-auth-providers-keycloak",
"python-sdk/fastmcp-server-auth-providers-oci",
"python-sdk/fastmcp-server-auth-providers-propelauth",
"python-sdk/fastmcp-server-auth-providers-scalekit",
@@ -315,6 +316,7 @@
"python-sdk/fastmcp-server-tasks-__init__",
"python-sdk/fastmcp-server-tasks-capabilities",
"python-sdk/fastmcp-server-tasks-config",
+ "python-sdk/fastmcp-server-tasks-context",
"python-sdk/fastmcp-server-tasks-elicitation",
"python-sdk/fastmcp-server-tasks-handlers",
"python-sdk/fastmcp-server-tasks-keys",
diff --git a/docs/python-sdk/fastmcp-client-client.mdx b/docs/python-sdk/fastmcp-client-client.mdx
index efbf56f08..f4285ebe9 100644
--- a/docs/python-sdk/fastmcp-client-client.mdx
+++ b/docs/python-sdk/fastmcp-client-client.mdx
@@ -7,7 +7,7 @@ sidebarTitle: client
## Classes
-### `ClientSessionState`
+### `ClientSessionState`
Holds all session-related state for a Client instance.
@@ -16,13 +16,13 @@ This allows clean separation of configuration (which is copied) from
session state (which should be fresh for each new client instance).
-### `CallToolResult`
+### `CallToolResult`
Parsed result from a tool call.
-### `Client`
+### `Client`
MCP client that delegates connection management to a Transport instance.
@@ -85,7 +85,7 @@ async with client:
**Methods:**
-#### `session`
+#### `session`
```python
session(self) -> ClientSession
@@ -94,7 +94,7 @@ session(self) -> ClientSession
Get the current active session. Raises RuntimeError if not connected.
-#### `initialize_result`
+#### `initialize_result`
```python
initialize_result(self) -> mcp.types.InitializeResult | None
@@ -103,7 +103,7 @@ initialize_result(self) -> mcp.types.InitializeResult | None
Get the result of the initialization request.
-#### `set_roots`
+#### `set_roots`
```python
set_roots(self, roots: RootsList | RootsHandler) -> None
@@ -112,7 +112,7 @@ set_roots(self, roots: RootsList | RootsHandler) -> None
Set the roots for the client. This does not automatically call `send_roots_list_changed`.
-#### `set_sampling_callback`
+#### `set_sampling_callback`
```python
set_sampling_callback(self, sampling_callback: SamplingHandler, sampling_capabilities: mcp.types.SamplingCapability | None = None) -> None
@@ -121,7 +121,7 @@ set_sampling_callback(self, sampling_callback: SamplingHandler, sampling_capabil
Set the sampling callback for the client.
-#### `set_elicitation_callback`
+#### `set_elicitation_callback`
```python
set_elicitation_callback(self, elicitation_callback: ElicitationHandler) -> None
@@ -130,7 +130,7 @@ set_elicitation_callback(self, elicitation_callback: ElicitationHandler) -> None
Set the elicitation callback for the client.
-#### `is_connected`
+#### `is_connected`
```python
is_connected(self) -> bool
@@ -139,7 +139,7 @@ is_connected(self) -> bool
Check if the client is currently connected.
-#### `new`
+#### `new`
```python
new(self) -> Client[ClientTransportT]
@@ -155,7 +155,7 @@ share state with the original client.
- A new Client instance with the same configuration but disconnected state.
-#### `initialize`
+#### `initialize`
```python
initialize(self, timeout: datetime.timedelta | float | int | None = None) -> mcp.types.InitializeResult
@@ -183,13 +183,13 @@ capabilities, protocol version, and optional instructions.
- `RuntimeError`: If the client is not connected or initialization times out.
-#### `close`
+#### `close`
```python
close(self)
```
-#### `ping`
+#### `ping`
```python
ping(self) -> bool
@@ -198,7 +198,7 @@ ping(self) -> bool
Send a ping request.
-#### `cancel`
+#### `cancel`
```python
cancel(self, request_id: str | int, reason: str | None = None) -> None
@@ -207,7 +207,7 @@ cancel(self, request_id: str | int, reason: str | None = None) -> None
Send a cancellation notification for an in-progress request.
-#### `progress`
+#### `progress`
```python
progress(self, progress_token: str | int, progress: float, total: float | None = None, message: str | None = None) -> None
@@ -216,7 +216,7 @@ progress(self, progress_token: str | int, progress: float, total: float | None =
Send a progress notification.
-#### `set_logging_level`
+#### `set_logging_level`
```python
set_logging_level(self, level: mcp.types.LoggingLevel) -> None
@@ -225,7 +225,7 @@ set_logging_level(self, level: mcp.types.LoggingLevel) -> None
Send a logging/setLevel request.
-#### `send_roots_list_changed`
+#### `send_roots_list_changed`
```python
send_roots_list_changed(self) -> None
@@ -234,7 +234,7 @@ send_roots_list_changed(self) -> None
Send a roots/list_changed notification.
-#### `complete_mcp`
+#### `complete_mcp`
```python
complete_mcp(self, ref: mcp.types.ResourceTemplateReference | mcp.types.PromptReference, argument: dict[str, str], context_arguments: dict[str, Any] | None = None) -> mcp.types.CompleteResult
@@ -257,7 +257,7 @@ containing the completion and any additional metadata.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `complete`
+#### `complete`
```python
complete(self, ref: mcp.types.ResourceTemplateReference | mcp.types.PromptReference, argument: dict[str, str], context_arguments: dict[str, Any] | None = None) -> mcp.types.Completion
@@ -279,7 +279,7 @@ include with the completion request. Defaults to None.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `generate_name`
+#### `generate_name`
```python
generate_name(cls, name: str | None = None) -> str
diff --git a/docs/python-sdk/fastmcp-client-tasks.mdx b/docs/python-sdk/fastmcp-client-tasks.mdx
index 547d9bc92..874089b71 100644
--- a/docs/python-sdk/fastmcp-client-tasks.mdx
+++ b/docs/python-sdk/fastmcp-client-tasks.mdx
@@ -114,8 +114,8 @@ with fallback to polling (reliable). Optimally wakes up immediately
on status changes when server sends notifications/tasks/status.
**Args:**
-- `state`: Desired state ('submitted', 'working', 'completed', 'failed').
- If None, waits for any terminal state (completed/failed)
+- `state`: Desired state ('working', 'input_required', 'completed', 'failed', 'cancelled').
+ If None, waits until the task exits the 'working' state (completed, failed, cancelled, input_required, etc.)
- `timeout`: Maximum time to wait in seconds
**Returns:**
@@ -125,7 +125,7 @@ on status changes when server sends notifications/tasks/status.
- `TimeoutError`: If desired state not reached within timeout
-#### `cancel`
+#### `cancel`
```python
cancel(self) -> None
@@ -140,7 +140,7 @@ Note: If server executed immediately (graceful degradation), this is a no-op
as there's no server-side task to cancel.
-### `ToolTask`
+### `ToolTask`
Represents a tool call that may execute in background or immediately.
@@ -151,7 +151,7 @@ or executes synchronously (graceful degradation per SEP-1686).
**Methods:**
-#### `result`
+#### `result`
```python
result(self) -> CallToolResult
@@ -166,7 +166,7 @@ Otherwise waits for background task to complete and retrieves result.
- The parsed tool result (same as call_tool returns)
-### `PromptTask`
+### `PromptTask`
Represents a prompt call that may execute in background or immediately.
@@ -177,7 +177,7 @@ or executes synchronously (graceful degradation per SEP-1686).
**Methods:**
-#### `result`
+#### `result`
```python
result(self) -> mcp.types.GetPromptResult
@@ -192,7 +192,7 @@ Otherwise waits for background task to complete and retrieves result.
- The prompt result with messages and description
-### `ResourceTask`
+### `ResourceTask`
Represents a resource read that may execute in background or immediately.
@@ -203,7 +203,7 @@ or executes synchronously (graceful degradation per SEP-1686).
**Methods:**
-#### `result`
+#### `result`
```python
result(self) -> list[mcp.types.TextResourceContents | mcp.types.BlobResourceContents]
diff --git a/docs/python-sdk/fastmcp-resources-base.mdx b/docs/python-sdk/fastmcp-resources-base.mdx
index aab4a1dd7..d9f76a057 100644
--- a/docs/python-sdk/fastmcp-resources-base.mdx
+++ b/docs/python-sdk/fastmcp-resources-base.mdx
@@ -10,7 +10,7 @@ Base classes and interfaces for FastMCP resources.
## Classes
-### `ResourceContent`
+### `ResourceContent`
Wrapper for resource content with optional MIME type and metadata.
@@ -21,7 +21,7 @@ other types (dict, list, BaseModel, etc.) are automatically JSON-serialized.
**Methods:**
-#### `to_mcp_resource_contents`
+#### `to_mcp_resource_contents`
```python
to_mcp_resource_contents(self, uri: AnyUrl | str) -> mcp.types.TextResourceContents | mcp.types.BlobResourceContents
@@ -36,7 +36,7 @@ Convert to MCP resource contents type.
- TextResourceContents for str content, BlobResourceContents for bytes
-### `ResourceResult`
+### `ResourceResult`
Canonical result type for resource reads.
@@ -47,7 +47,7 @@ per-item MIME types, and metadata at both the item and result level.
**Methods:**
-#### `to_mcp_result`
+#### `to_mcp_result`
```python
to_mcp_result(self, uri: AnyUrl | str) -> mcp.types.ReadResourceResult
@@ -62,7 +62,7 @@ Convert to MCP ReadResourceResult.
- MCP ReadResourceResult with converted contents
-### `Resource`
+### `Resource`
Base class for all resources.
@@ -70,13 +70,13 @@ Base class for all resources.
**Methods:**
-#### `from_function`
+#### `from_function`
```python
from_function(cls, fn: Callable[..., Any], uri: str | AnyUrl) -> FunctionResource
```
-#### `set_default_mime_type`
+#### `set_default_mime_type`
```python
set_default_mime_type(cls, mime_type: str | None) -> str
@@ -85,7 +85,7 @@ set_default_mime_type(cls, mime_type: str | None) -> str
Set default MIME type if not provided.
-#### `set_default_name`
+#### `set_default_name`
```python
set_default_name(self) -> Self
@@ -94,7 +94,7 @@ set_default_name(self) -> Self
Set default name from URI if not provided.
-#### `read`
+#### `read`
```python
read(self) -> str | bytes | ResourceResult
@@ -108,7 +108,7 @@ Subclasses implement this to return resource data. Supported return types:
- ResourceResult: Full control over contents and result-level meta
-#### `convert_result`
+#### `convert_result`
```python
convert_result(self, raw_value: Any) -> ResourceResult
@@ -131,7 +131,7 @@ MCP Apps CSP/permissions) is propagated to each content item so
that hosts can read it from the ``resources/read`` response.
-#### `to_mcp_resource`
+#### `to_mcp_resource`
```python
to_mcp_resource(self, **overrides: Any) -> SDKResource
@@ -140,7 +140,7 @@ to_mcp_resource(self, **overrides: Any) -> SDKResource
Convert the resource to an SDKResource.
-#### `key`
+#### `key`
```python
key(self) -> str
@@ -149,7 +149,7 @@ key(self) -> str
The globally unique lookup key for this resource.
-#### `register_with_docket`
+#### `register_with_docket`
```python
register_with_docket(self, docket: Docket) -> None
@@ -158,7 +158,7 @@ register_with_docket(self, docket: Docket) -> None
Register this resource with docket for background execution.
-#### `add_to_docket`
+#### `add_to_docket`
```python
add_to_docket(self, docket: Docket, **kwargs: Any) -> Execution
@@ -173,7 +173,7 @@ Schedule this resource for background execution via docket.
- `**kwargs`: Additional kwargs passed to docket.add()
-#### `get_span_attributes`
+#### `get_span_attributes`
```python
get_span_attributes(self) -> dict[str, Any]
diff --git a/docs/python-sdk/fastmcp-resources-template.mdx b/docs/python-sdk/fastmcp-resources-template.mdx
index 540866c5a..7fc0cf305 100644
--- a/docs/python-sdk/fastmcp-resources-template.mdx
+++ b/docs/python-sdk/fastmcp-resources-template.mdx
@@ -52,9 +52,23 @@ Supports RFC 6570 URI templates:
- Query params: `{?var1,var2}`
+### `expand_uri_template`
+
+```python
+expand_uri_template(uri_template: str, params: dict[str, Any]) -> str
+```
+
+
+Expand a URI template with parameters — inverse of `match_uri_template`.
+
+Supports the same RFC 6570 subset:
+- Path params: `{var}`, `{var*}`
+- Query params: `{?var1,var2}`
+
+
## Classes
-### `ResourceTemplate`
+### `ResourceTemplate`
A template for dynamically creating resources.
@@ -62,13 +76,13 @@ A template for dynamically creating resources.
**Methods:**
-#### `from_function`
+#### `from_function`
```python
from_function(fn: Callable[..., Any], uri_template: str, name: str | None = None, version: str | int | None = None, title: str | None = None, description: str | None = None, icons: list[Icon] | None = None, mime_type: str | None = None, tags: set[str] | None = None, annotations: Annotations | None = None, meta: dict[str, Any] | None = None, task: bool | TaskConfig | None = None, auth: AuthCheck | list[AuthCheck] | None = None) -> FunctionResourceTemplate
```
-#### `set_default_mime_type`
+#### `set_default_mime_type`
```python
set_default_mime_type(cls, mime_type: str | None) -> str
@@ -77,7 +91,7 @@ set_default_mime_type(cls, mime_type: str | None) -> str
Set default MIME type if not provided.
-#### `matches`
+#### `matches`
```python
matches(self, uri: str) -> dict[str, Any] | None
@@ -86,7 +100,7 @@ matches(self, uri: str) -> dict[str, Any] | None
Check if URI matches template and extract parameters.
-#### `read`
+#### `read`
```python
read(self, arguments: dict[str, Any]) -> str | bytes | ResourceResult
@@ -95,7 +109,7 @@ read(self, arguments: dict[str, Any]) -> str | bytes | ResourceResult
Read the resource content.
-#### `convert_result`
+#### `convert_result`
```python
convert_result(self, raw_value: Any) -> ResourceResult
@@ -111,7 +125,7 @@ Handles ResourceResult passthrough and converts raw values using
ResourceResult's normalization.
-#### `create_resource`
+#### `create_resource`
```python
create_resource(self, uri: str, params: dict[str, Any]) -> Resource
@@ -123,7 +137,7 @@ The base implementation does not support background tasks.
Use FunctionResourceTemplate for task support.
-#### `to_mcp_template`
+#### `to_mcp_template`
```python
to_mcp_template(self, **overrides: Any) -> SDKResourceTemplate
@@ -132,7 +146,7 @@ to_mcp_template(self, **overrides: Any) -> SDKResourceTemplate
Convert the resource template to an SDKResourceTemplate.
-#### `from_mcp_template`
+#### `from_mcp_template`
```python
from_mcp_template(cls, mcp_template: SDKResourceTemplate) -> ResourceTemplate
@@ -141,7 +155,7 @@ from_mcp_template(cls, mcp_template: SDKResourceTemplate) -> ResourceTemplate
Creates a FastMCP ResourceTemplate from a raw MCP ResourceTemplate object.
-#### `key`
+#### `key`
```python
key(self) -> str
@@ -150,7 +164,7 @@ key(self) -> str
The globally unique lookup key for this template.
-#### `register_with_docket`
+#### `register_with_docket`
```python
register_with_docket(self, docket: Docket) -> None
@@ -159,7 +173,7 @@ register_with_docket(self, docket: Docket) -> None
Register this template with docket for background execution.
-#### `add_to_docket`
+#### `add_to_docket`
```python
add_to_docket(self, docket: Docket, params: dict[str, Any], **kwargs: Any) -> Execution
@@ -175,13 +189,13 @@ Schedule this template for background execution via docket.
- `**kwargs`: Additional kwargs passed to docket.add()
-#### `get_span_attributes`
+#### `get_span_attributes`
```python
get_span_attributes(self) -> dict[str, Any]
```
-### `FunctionResourceTemplate`
+### `FunctionResourceTemplate`
A template for dynamically creating resources.
@@ -189,7 +203,7 @@ A template for dynamically creating resources.
**Methods:**
-#### `create_resource`
+#### `create_resource`
```python
create_resource(self, uri: str, params: dict[str, Any]) -> Resource
@@ -198,7 +212,7 @@ create_resource(self, uri: str, params: dict[str, Any]) -> Resource
Create a resource from the template with the given parameters.
-#### `read`
+#### `read`
```python
read(self, arguments: dict[str, Any]) -> str | bytes | ResourceResult
@@ -207,7 +221,7 @@ read(self, arguments: dict[str, Any]) -> str | bytes | ResourceResult
Read the resource content.
-#### `register_with_docket`
+#### `register_with_docket`
```python
register_with_docket(self, docket: Docket) -> None
@@ -216,7 +230,7 @@ register_with_docket(self, docket: Docket) -> None
Register this template with docket for background execution.
-#### `add_to_docket`
+#### `add_to_docket`
```python
add_to_docket(self, docket: Docket, params: dict[str, Any], **kwargs: Any) -> Execution
@@ -234,7 +248,7 @@ FunctionResourceTemplate splats the params dict since .fn expects **kwargs.
- `**kwargs`: Additional kwargs passed to docket.add()
-#### `from_function`
+#### `from_function`
```python
from_function(cls, fn: Callable[..., Any], uri_template: str, name: str | None = None, version: str | int | None = None, title: str | None = None, description: str | None = None, icons: list[Icon] | None = None, mime_type: str | None = None, tags: set[str] | None = None, annotations: Annotations | None = None, meta: dict[str, Any] | None = None, task: bool | TaskConfig | None = None, auth: AuthCheck | list[AuthCheck] | None = None) -> FunctionResourceTemplate
diff --git a/docs/python-sdk/fastmcp-server-auth-auth.mdx b/docs/python-sdk/fastmcp-server-auth-auth.mdx
index def0830fd..69f63aeb7 100644
--- a/docs/python-sdk/fastmcp-server-auth-auth.mdx
+++ b/docs/python-sdk/fastmcp-server-auth-auth.mdx
@@ -85,7 +85,7 @@ custom authentication routes.
**Methods:**
-#### `verify_token`
+#### `verify_token`
```python
verify_token(self, token: str) -> AccessToken | None
@@ -102,7 +102,7 @@ All auth providers must implement token verification.
- AccessToken object if valid, None if invalid or expired
-#### `set_mcp_path`
+#### `set_mcp_path`
```python
set_mcp_path(self, mcp_path: str | None) -> None
@@ -119,7 +119,7 @@ MCP endpoint path.
- `mcp_path`: The path where the MCP endpoint is mounted (e.g., "/mcp")
-#### `get_routes`
+#### `get_routes`
```python
get_routes(self, mcp_path: str | None = None) -> list[Route]
@@ -143,7 +143,7 @@ provider does not create the actual MCP endpoint route.
- List of all routes for this provider (excluding the MCP endpoint itself)
-#### `get_well_known_routes`
+#### `get_well_known_routes`
```python
get_well_known_routes(self, mcp_path: str | None = None) -> list[Route]
@@ -171,7 +171,7 @@ This is used to construct path-scoped well-known URLs.
- List of well-known discovery routes (typically mounted at root level)
-#### `get_middleware`
+#### `get_middleware`
```python
get_middleware(self) -> list
@@ -183,7 +183,7 @@ Get HTTP application-level middleware for this auth provider.
- List of Starlette Middleware instances to apply to the HTTP app
-### `TokenVerifier`
+### `TokenVerifier`
Base class for token verifiers (Resource Servers).
@@ -194,7 +194,7 @@ Token verifiers typically don't provide authentication routes by default.
**Methods:**
-#### `scopes_supported`
+#### `scopes_supported`
```python
scopes_supported(self) -> list[str]
@@ -208,7 +208,7 @@ where tokens contain short-form scopes but clients request full URI
scopes).
-#### `verify_token`
+#### `verify_token`
```python
verify_token(self, token: str) -> AccessToken | None
@@ -217,7 +217,7 @@ verify_token(self, token: str) -> AccessToken | None
Verify a bearer token and return access info if valid.
-### `RemoteAuthProvider`
+### `RemoteAuthProvider`
Authentication provider for resource servers that verify tokens from known authorization servers.
@@ -234,7 +234,7 @@ the authorization servers that issue valid tokens.
**Methods:**
-#### `verify_token`
+#### `verify_token`
```python
verify_token(self, token: str) -> AccessToken | None
@@ -243,7 +243,7 @@ verify_token(self, token: str) -> AccessToken | None
Verify token using the configured token verifier.
-#### `get_routes`
+#### `get_routes`
```python
get_routes(self, mcp_path: str | None = None) -> list[Route]
@@ -254,7 +254,7 @@ Get routes for this provider.
Creates protected resource metadata routes (RFC 9728).
-### `MultiAuth`
+### `MultiAuth`
Composes an optional auth server with additional token verifiers.
@@ -270,7 +270,7 @@ come from the server; verifiers contribute only token verification.
**Methods:**
-#### `verify_token`
+#### `verify_token`
```python
verify_token(self, token: str) -> AccessToken | None
@@ -283,7 +283,7 @@ it is logged and treated as a non-match so that remaining sources
still get a chance to verify the token.
-#### `set_mcp_path`
+#### `set_mcp_path`
```python
set_mcp_path(self, mcp_path: str | None) -> None
@@ -292,7 +292,7 @@ set_mcp_path(self, mcp_path: str | None) -> None
Propagate MCP path to the server and all verifiers.
-#### `get_routes`
+#### `get_routes`
```python
get_routes(self, mcp_path: str | None = None) -> list[Route]
@@ -301,7 +301,7 @@ get_routes(self, mcp_path: str | None = None) -> list[Route]
Delegate route creation to the server.
-#### `get_well_known_routes`
+#### `get_well_known_routes`
```python
get_well_known_routes(self, mcp_path: str | None = None) -> list[Route]
@@ -313,7 +313,7 @@ This ensures that server-specific well-known route logic (e.g.,
OAuthProvider's RFC 8414 path-aware discovery) is preserved.
-### `OAuthProvider`
+### `OAuthProvider`
OAuth Authorization Server provider.
@@ -324,7 +324,7 @@ authorization flows, token issuance, and token verification.
**Methods:**
-#### `verify_token`
+#### `verify_token`
```python
verify_token(self, token: str) -> AccessToken | None
@@ -342,7 +342,7 @@ to our existing load_access_token method.
- AccessToken object if valid, None if invalid or expired
-#### `get_routes`
+#### `get_routes`
```python
get_routes(self, mcp_path: str | None = None) -> list[Route]
@@ -358,7 +358,7 @@ This method creates the full set of OAuth routes including:
- List of OAuth routes
-#### `get_well_known_routes`
+#### `get_well_known_routes`
```python
get_well_known_routes(self, mcp_path: str | None = None) -> list[Route]
diff --git a/docs/python-sdk/fastmcp-server-auth-oauth_proxy-proxy.mdx b/docs/python-sdk/fastmcp-server-auth-oauth_proxy-proxy.mdx
index 866c26570..bb5e3a314 100644
--- a/docs/python-sdk/fastmcp-server-auth-oauth_proxy-proxy.mdx
+++ b/docs/python-sdk/fastmcp-server-auth-oauth_proxy-proxy.mdx
@@ -140,7 +140,7 @@ Handles provider-specific requirements:
**Methods:**
-#### `set_mcp_path`
+#### `set_mcp_path`
```python
set_mcp_path(self, mcp_path: str | None) -> None
@@ -157,7 +157,7 @@ this specific MCP endpoint.
- `mcp_path`: The path where the MCP endpoint is mounted (e.g., "/mcp")
-#### `jwt_issuer`
+#### `jwt_issuer`
```python
jwt_issuer(self) -> JWTIssuer
@@ -169,7 +169,7 @@ The JWT issuer is created when set_mcp_path() is called (via get_routes()).
This property ensures a clear error if used before initialization.
-#### `get_client`
+#### `get_client`
```python
get_client(self, client_id: str) -> OAuthClientInformationFull | None
@@ -182,7 +182,7 @@ For unregistered clients, returns None (which will raise an error in the SDK).
CIMD clients (URL-based client IDs) are looked up and cached automatically.
-#### `register_client`
+#### `register_client`
```python
register_client(self, client_info: OAuthClientInformationFull) -> None
@@ -196,7 +196,7 @@ redirect URI will likely be localhost or unknown to the proxied IDP. The
proxied IDP only knows about this server's fixed redirect URI.
-#### `authorize`
+#### `authorize`
```python
authorize(self, client: OAuthClientInformationFull, params: AuthorizationParams) -> str
@@ -214,7 +214,7 @@ If consent is disabled (require_authorization_consent=False), skip the consent s
and redirect directly to the upstream IdP.
-#### `load_authorization_code`
+#### `load_authorization_code`
```python
load_authorization_code(self, client: OAuthClientInformationFull, authorization_code: str) -> AuthorizationCode | None
@@ -226,7 +226,7 @@ Look up our client code and return authorization code object
with PKCE challenge for validation.
-#### `exchange_authorization_code`
+#### `exchange_authorization_code`
```python
exchange_authorization_code(self, client: OAuthClientInformationFull, authorization_code: AuthorizationCode) -> OAuthToken
@@ -244,7 +244,7 @@ Implements the token factory pattern:
PKCE validation is handled by the MCP framework before this method is called.
-#### `load_refresh_token`
+#### `load_refresh_token`
```python
load_refresh_token(self, client: OAuthClientInformationFull, refresh_token: str) -> RefreshToken | None
@@ -256,7 +256,7 @@ Looks up by token hash and reconstructs the RefreshToken object.
Validates that the token belongs to the requesting client.
-#### `exchange_refresh_token`
+#### `exchange_refresh_token`
```python
exchange_refresh_token(self, client: OAuthClientInformationFull, refresh_token: RefreshToken, scopes: list[str]) -> OAuthToken
@@ -273,7 +273,7 @@ Implements two-tier refresh:
6. Keep same FastMCP refresh token (unless upstream rotates)
-#### `load_access_token`
+#### `load_access_token`
```python
load_access_token(self, token: str) -> AccessToken | None
@@ -293,7 +293,7 @@ The FastMCP JWT is a reference token - all authorization data comes
from validating the upstream token via the TokenVerifier.
-#### `revoke_token`
+#### `revoke_token`
```python
revoke_token(self, token: AccessToken | RefreshToken) -> None
@@ -306,7 +306,7 @@ For all tokens, attempts upstream revocation if endpoint is configured.
Access token JTI mappings expire via TTL.
-#### `get_routes`
+#### `get_routes`
```python
get_routes(self, mcp_path: str | None = None) -> list[Route]
diff --git a/docs/python-sdk/fastmcp-server-auth-oidc_proxy.mdx b/docs/python-sdk/fastmcp-server-auth-oidc_proxy.mdx
index 904968111..da088e129 100644
--- a/docs/python-sdk/fastmcp-server-auth-oidc_proxy.mdx
+++ b/docs/python-sdk/fastmcp-server-auth-oidc_proxy.mdx
@@ -52,7 +52,7 @@ that is OIDC compliant.
**Methods:**
-#### `get_oidc_configuration`
+#### `get_oidc_configuration`
```python
get_oidc_configuration(self, config_url: AnyHttpUrl, strict: bool | None, timeout_seconds: int | None) -> OIDCConfiguration
@@ -66,7 +66,7 @@ Gets the OIDC configuration for the specified configuration URL.
- `timeout_seconds`: HTTP request timeout in seconds
-#### `get_token_verifier`
+#### `get_token_verifier`
```python
get_token_verifier(self) -> TokenVerifier
diff --git a/docs/python-sdk/fastmcp-server-auth-providers-aws.mdx b/docs/python-sdk/fastmcp-server-auth-providers-aws.mdx
index 3b834c67b..e0f46689c 100644
--- a/docs/python-sdk/fastmcp-server-auth-providers-aws.mdx
+++ b/docs/python-sdk/fastmcp-server-auth-providers-aws.mdx
@@ -71,7 +71,7 @@ Features:
**Methods:**
-#### `get_token_verifier`
+#### `get_token_verifier`
```python
get_token_verifier(self) -> AWSCognitoTokenVerifier
diff --git a/docs/python-sdk/fastmcp-server-auth-providers-azure.mdx b/docs/python-sdk/fastmcp-server-auth-providers-azure.mdx
index ea22062f4..e65cc6119 100644
--- a/docs/python-sdk/fastmcp-server-auth-providers-azure.mdx
+++ b/docs/python-sdk/fastmcp-server-auth-providers-azure.mdx
@@ -14,7 +14,7 @@ using the OAuth Proxy pattern for non-DCR OAuth flows.
## Functions
-### `EntraOBOToken`
+### `EntraOBOToken`
```python
EntraOBOToken(scopes: list[str]) -> str
@@ -43,7 +43,7 @@ or OBO exchange fails
## Classes
-### `AzureProvider`
+### `AzureProvider`
Azure (Microsoft Entra) OAuth provider for FastMCP.
@@ -78,7 +78,7 @@ Setup:
**Methods:**
-#### `authorize`
+#### `authorize`
```python
authorize(self, client: OAuthClientInformationFull, params: AuthorizationParams) -> str
@@ -98,7 +98,7 @@ scopes to determine the resource/audience instead of a separate parameter.
- Authorization URL to redirect the user to Azure AD
-#### `get_obo_credential`
+#### `get_obo_credential`
```python
get_obo_credential(self, user_assertion: str) -> OnBehalfOfCredential
@@ -120,7 +120,7 @@ calls multiple tools with the same scopes.
- `ImportError`: If azure-identity is not installed (requires fastmcp[azure]).
-#### `close_obo_credentials`
+#### `close_obo_credentials`
```python
close_obo_credentials(self) -> None
@@ -129,7 +129,7 @@ close_obo_credentials(self) -> None
Close all cached OBO credentials.
-### `AzureJWTVerifier`
+### `AzureJWTVerifier`
JWT verifier pre-configured for Azure AD / Microsoft Entra ID.
@@ -166,7 +166,7 @@ Example::
**Methods:**
-#### `scopes_supported`
+#### `scopes_supported`
```python
scopes_supported(self) -> list[str]
diff --git a/docs/python-sdk/fastmcp-server-auth-providers-in_memory.mdx b/docs/python-sdk/fastmcp-server-auth-providers-in_memory.mdx
index c4ee4cc14..0e1e0d94e 100644
--- a/docs/python-sdk/fastmcp-server-auth-providers-in_memory.mdx
+++ b/docs/python-sdk/fastmcp-server-auth-providers-in_memory.mdx
@@ -16,19 +16,19 @@ It simulates the OAuth 2.1 flow locally without external calls.
**Methods:**
-#### `get_client`
+#### `get_client`
```python
get_client(self, client_id: str) -> OAuthClientInformationFull | None
```
-#### `register_client`
+#### `register_client`
```python
register_client(self, client_info: OAuthClientInformationFull) -> None
```
-#### `authorize`
+#### `authorize`
```python
authorize(self, client: OAuthClientInformationFull, params: AuthorizationParams) -> str
@@ -38,37 +38,37 @@ Simulates user authorization and generates an authorization code.
Returns a redirect URI with the code and state.
-#### `load_authorization_code`
+#### `load_authorization_code`
```python
load_authorization_code(self, client: OAuthClientInformationFull, authorization_code: str) -> AuthorizationCode | None
```
-#### `exchange_authorization_code`
+#### `exchange_authorization_code`
```python
exchange_authorization_code(self, client: OAuthClientInformationFull, authorization_code: AuthorizationCode) -> OAuthToken
```
-#### `load_refresh_token`
+#### `load_refresh_token`
```python
load_refresh_token(self, client: OAuthClientInformationFull, refresh_token: str) -> RefreshToken | None
```
-#### `exchange_refresh_token`
+#### `exchange_refresh_token`
```python
exchange_refresh_token(self, client: OAuthClientInformationFull, refresh_token: RefreshToken, scopes: list[str]) -> OAuthToken
```
-#### `load_access_token`
+#### `load_access_token`
```python
load_access_token(self, token: str) -> AccessToken | None
```
-#### `verify_token`
+#### `verify_token`
```python
verify_token(self, token: str) -> AccessToken | None
@@ -86,7 +86,7 @@ to our existing load_access_token method.
- AccessToken object if valid, None if invalid or expired
-#### `revoke_token`
+#### `revoke_token`
```python
revoke_token(self, token: AccessToken | RefreshToken) -> None
diff --git a/docs/python-sdk/fastmcp-server-auth-providers-keycloak.mdx b/docs/python-sdk/fastmcp-server-auth-providers-keycloak.mdx
new file mode 100644
index 000000000..e3cde2e60
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-auth-providers-keycloak.mdx
@@ -0,0 +1,20 @@
+---
+title: keycloak
+sidebarTitle: keycloak
+---
+
+# `fastmcp.server.auth.providers.keycloak`
+
+
+Keycloak authentication provider for FastMCP.
+
+## Classes
+
+### `KeycloakAuthProvider`
+
+
+Keycloak authentication provider using Dynamic Client Registration (DCR).
+
+Requires Keycloak 26.6.0 or later, which includes the fix for DCR compatibility
+with MCP clients (https://github.com/keycloak/keycloak/pull/45309).
+
diff --git a/docs/python-sdk/fastmcp-server-auth-providers-workos.mdx b/docs/python-sdk/fastmcp-server-auth-providers-workos.mdx
index 86cd88f59..8d8c80061 100644
--- a/docs/python-sdk/fastmcp-server-auth-providers-workos.mdx
+++ b/docs/python-sdk/fastmcp-server-auth-providers-workos.mdx
@@ -59,7 +59,7 @@ Setup Requirements:
4. Note your Client ID and Client Secret
-### `AuthKitProvider`
+### `AuthKitProvider`
AuthKit metadata provider for DCR (Dynamic Client Registration).
@@ -85,7 +85,7 @@ https://workos.com/docs/authkit/mcp/integrating/token-verification
**Methods:**
-#### `get_routes`
+#### `get_routes`
```python
get_routes(self, mcp_path: str | None = None) -> list[Route]
diff --git a/docs/python-sdk/fastmcp-server-dependencies.mdx b/docs/python-sdk/fastmcp-server-dependencies.mdx
index 64186a6cd..927434df2 100644
--- a/docs/python-sdk/fastmcp-server-dependencies.mdx
+++ b/docs/python-sdk/fastmcp-server-dependencies.mdx
@@ -15,74 +15,7 @@ CurrentWorker) and background task execution require fastmcp[tasks].
## Functions
-### `get_task_context`
-
-```python
-get_task_context() -> TaskContextInfo | None
-```
-
-
-Get the current task context if running inside a background task worker.
-
-This function extracts task information from the Docket execution context.
-Returns None if not running in a task context (e.g., foreground execution).
-
-**Returns:**
-- TaskContextInfo with task_id and session_id, or None if not in a task.
-
-
-### `register_task_session`
-
-```python
-register_task_session(session_id: str, session: ServerSession) -> None
-```
-
-
-Register a session for Context access in background tasks.
-
-Called automatically when a task is submitted to Docket. The session is
-stored as a weakref so it doesn't prevent garbage collection when the
-client disconnects.
-
-**Args:**
-- `session_id`: The session identifier
-- `session`: The ServerSession instance
-
-
-### `get_task_session`
-
-```python
-get_task_session(session_id: str) -> ServerSession | None
-```
-
-
-Get a registered session by ID if still alive.
-
-**Args:**
-- `session_id`: The session identifier
-
-**Returns:**
-- The ServerSession if found and alive, None otherwise
-
-
-### `register_task_server`
-
-```python
-register_task_server(task_id: str, server: FastMCP) -> None
-```
-
-
-Register the server for a background task.
-
-Called at task-submission time (inside the child server's call_tool
-context) so that background workers can resolve CurrentFastMCP() and
-ctx.fastmcp to the child server for mounted tasks.
-
-The map is bounded to avoid unbounded growth in long-lived servers.
-Evicted entries fall back to the ContextVar (parent server).
-
-
-### `is_docket_available`
+### `is_docket_available`
```python
is_docket_available() -> bool
@@ -103,7 +36,7 @@ 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.
-### `require_docket`
+### `require_docket`
```python
require_docket(feature: str) -> None
@@ -117,7 +50,7 @@ Raise ImportError with install instructions if docket not available.
"CurrentDocket()"). Will be included in the error message.
-### `transform_context_annotations`
+### `transform_context_annotations`
```python
transform_context_annotations(fn: Callable[..., Any]) -> Callable[..., Any]
@@ -143,7 +76,7 @@ allows them to have defaults in any order.
- Function with modified signature (same function object, updated __signature__)
-### `get_context`
+### `get_context`
```python
get_context() -> Context
@@ -153,7 +86,7 @@ get_context() -> Context
Get the current FastMCP Context instance directly.
-### `get_server`
+### `get_server`
```python
get_server() -> FastMCP
@@ -173,7 +106,7 @@ started the worker).
- `RuntimeError`: If no server in context
-### `get_http_request`
+### `get_http_request`
```python
get_http_request() -> Request
@@ -187,7 +120,7 @@ In background tasks, returns a synthetic request populated with the
snapshotted headers from the originating HTTP request.
-### `get_http_headers`
+### `get_http_headers`
```python
get_http_headers(include_all: bool = False, include: set[str] | None = None) -> dict[str, str]
@@ -208,7 +141,7 @@ normally be excluded. This is useful for proxy transports that need to forward
authorization headers to upstream MCP servers.
-### `get_access_token`
+### `get_access_token`
```python
get_access_token() -> AccessToken | None
@@ -227,7 +160,7 @@ token snapshot stored in Redis at task submission time.
- The access token if an authenticated user is available, None otherwise.
-### `without_injected_parameters`
+### `without_injected_parameters`
```python
without_injected_parameters(fn: Callable[..., Any]) -> Callable[..., Any]
@@ -252,7 +185,7 @@ Handles:
- Async wrapper function without injected parameters
-### `resolve_dependencies`
+### `resolve_dependencies`
```python
resolve_dependencies(fn: Callable[..., Any], arguments: dict[str, Any]) -> AsyncGenerator[dict[str, Any], None]
@@ -278,7 +211,7 @@ time, so all injection goes through the unified DI system.
which will be filtered out)
-### `CurrentContext`
+### `CurrentContext`
```python
CurrentContext() -> Context
@@ -297,7 +230,7 @@ current MCP operation (tool/resource/prompt call).
- `RuntimeError`: If no active context found (during resolution)
-### `OptionalCurrentContext`
+### `OptionalCurrentContext`
```python
OptionalCurrentContext() -> Context | None
@@ -307,7 +240,7 @@ OptionalCurrentContext() -> Context | None
Get the current FastMCP Context, or None when no context is active.
-### `CurrentDocket`
+### `CurrentDocket`
```python
CurrentDocket() -> Docket
@@ -327,7 +260,7 @@ automatically creates for background task scheduling.
- `ImportError`: If fastmcp[tasks] not installed
-### `CurrentWorker`
+### `CurrentWorker`
```python
CurrentWorker() -> Worker
@@ -347,7 +280,7 @@ automatically creates for background task processing.
- `ImportError`: If fastmcp[tasks] not installed
-### `CurrentFastMCP`
+### `CurrentFastMCP`
```python
CurrentFastMCP() -> FastMCP
@@ -365,7 +298,7 @@ This dependency provides access to the active FastMCP server.
- `RuntimeError`: If no server in context (during resolution)
-### `CurrentRequest`
+### `CurrentRequest`
```python
CurrentRequest() -> Request
@@ -385,7 +318,7 @@ current HTTP request. Only available when running over HTTP transports
- `RuntimeError`: If no HTTP request in context (e.g., STDIO transport)
-### `CurrentHeaders`
+### `CurrentHeaders`
```python
CurrentHeaders() -> dict[str, str]
@@ -403,7 +336,7 @@ transport.
- A dependency that resolves to a dictionary of header name -> value
-### `CurrentAccessToken`
+### `CurrentAccessToken`
```python
CurrentAccessToken() -> AccessToken
@@ -422,7 +355,7 @@ authenticated request. Raises an error if no authentication is present.
- `RuntimeError`: If no authenticated user (use get_access_token() for optional)
-### `TokenClaim`
+### `TokenClaim`
```python
TokenClaim(name: str) -> str
@@ -447,62 +380,7 @@ without needing the full token object.
## Classes
-### `TaskContextInfo`
-
-
-Information about the current background task context.
-
-Returned by ``get_task_context()`` when running inside a Docket worker.
-Contains identifiers needed to communicate with the MCP session.
-
-
-### `TaskContextSnapshot`
-
-
-All context data snapshotted at task-submission time.
-
-Stored as a single Redis key per task, restored once in the worker.
-
-
-**Methods:**
-
-#### `capture`
-
-```python
-capture(cls) -> TaskContextSnapshot
-```
-
-Capture current context for background task execution.
-
-
-#### `from_json`
-
-```python
-from_json(cls, raw: str | bytes) -> TaskContextSnapshot
-```
-
-Deserialize from JSON stored in Redis.
-
-
-#### `to_json`
-
-```python
-to_json(self) -> str
-```
-
-Serialize to JSON for Redis storage.
-
-
-#### `save`
-
-```python
-save(self, docket: Docket, session_id: str, task_id: str, ttl_seconds: int) -> None
-```
-
-Store this snapshot as a single Redis key.
-
-
-### `ProgressLike`
+### `ProgressLike`
Protocol for progress tracking interface.
@@ -513,7 +391,7 @@ and Docket's Progress (worker context).
**Methods:**
-#### `current`
+#### `current`
```python
current(self) -> int | None
@@ -522,7 +400,7 @@ current(self) -> int | None
Current progress value.
-#### `total`
+#### `total`
```python
total(self) -> int
@@ -531,7 +409,7 @@ total(self) -> int
Total/target progress value.
-#### `message`
+#### `message`
```python
message(self) -> str | None
@@ -540,7 +418,7 @@ message(self) -> str | None
Current progress message.
-#### `set_total`
+#### `set_total`
```python
set_total(self, total: int) -> None
@@ -549,7 +427,7 @@ set_total(self, total: int) -> None
Set the total/target value for progress tracking.
-#### `increment`
+#### `increment`
```python
increment(self, amount: int = 1) -> None
@@ -558,7 +436,7 @@ increment(self, amount: int = 1) -> None
Atomically increment the current progress value.
-#### `set_message`
+#### `set_message`
```python
set_message(self, message: str | None) -> None
@@ -567,7 +445,7 @@ set_message(self, message: str | None) -> None
Update the progress status message.
-### `InMemoryProgress`
+### `InMemoryProgress`
In-memory progress tracker for immediate tool execution.
@@ -579,25 +457,25 @@ progress doesn't need to be observable across processes.
**Methods:**
-#### `current`
+#### `current`
```python
current(self) -> int | None
```
-#### `total`
+#### `total`
```python
total(self) -> int
```
-#### `message`
+#### `message`
```python
message(self) -> str | None
```
-#### `set_total`
+#### `set_total`
```python
set_total(self, total: int) -> None
@@ -606,7 +484,7 @@ set_total(self, total: int) -> None
Set the total/target value for progress tracking.
-#### `increment`
+#### `increment`
```python
increment(self, amount: int = 1) -> None
@@ -615,7 +493,7 @@ increment(self, amount: int = 1) -> None
Atomically increment the current progress value.
-#### `set_message`
+#### `set_message`
```python
set_message(self, message: str | None) -> None
@@ -624,7 +502,7 @@ set_message(self, message: str | None) -> None
Update the progress status message.
-### `Progress`
+### `Progress`
Progress dependency that works in both server and worker contexts.
@@ -639,7 +517,7 @@ share mutable state.
**Methods:**
-#### `current`
+#### `current`
```python
current(self) -> int | None
@@ -648,7 +526,7 @@ current(self) -> int | None
Current progress value.
-#### `total`
+#### `total`
```python
total(self) -> int
@@ -657,7 +535,7 @@ total(self) -> int
Total/target progress value.
-#### `message`
+#### `message`
```python
message(self) -> str | None
@@ -666,7 +544,7 @@ message(self) -> str | None
Current progress message.
-#### `set_total`
+#### `set_total`
```python
set_total(self, total: int) -> None
@@ -675,7 +553,7 @@ set_total(self, total: int) -> None
Set the total/target value for progress tracking.
-#### `increment`
+#### `increment`
```python
increment(self, amount: int = 1) -> None
@@ -684,7 +562,7 @@ increment(self, amount: int = 1) -> None
Atomically increment the current progress value.
-#### `set_message`
+#### `set_message`
```python
set_message(self, message: str | None) -> None
diff --git a/docs/python-sdk/fastmcp-server-providers-fastmcp_provider.mdx b/docs/python-sdk/fastmcp-server-providers-fastmcp_provider.mdx
index 0602510ce..585c9b376 100644
--- a/docs/python-sdk/fastmcp-server-providers-fastmcp_provider.mdx
+++ b/docs/python-sdk/fastmcp-server-providers-fastmcp_provider.mdx
@@ -18,7 +18,7 @@ executed.
## Classes
-### `FastMCPProviderTool`
+### `FastMCPProviderTool`
Tool that delegates execution to a wrapped server's middleware.
@@ -30,7 +30,7 @@ chain is executed.
**Methods:**
-#### `wrap`
+#### `wrap`
```python
wrap(cls, server: Any, tool: Tool) -> FastMCPProviderTool
@@ -39,7 +39,7 @@ wrap(cls, server: Any, tool: Tool) -> FastMCPProviderTool
Wrap a Tool to delegate execution to the server's middleware.
-#### `run`
+#### `run`
```python
run(self, arguments: dict[str, Any]) -> ToolResult
@@ -51,13 +51,13 @@ This is called when the tool is used within a TransformedTool
forwarding function or other contexts where task_meta is not available.
-#### `get_span_attributes`
+#### `get_span_attributes`
```python
get_span_attributes(self) -> dict[str, Any]
```
-### `FastMCPProviderResource`
+### `FastMCPProviderResource`
Resource that delegates reading to a wrapped server's read_resource().
@@ -68,7 +68,7 @@ When `read()` is called, this resource invokes the wrapped server's
**Methods:**
-#### `wrap`
+#### `wrap`
```python
wrap(cls, server: Any, resource: Resource) -> FastMCPProviderResource
@@ -77,13 +77,13 @@ wrap(cls, server: Any, resource: Resource) -> FastMCPProviderResource
Wrap a Resource to delegate reading to the server's middleware.
-#### `get_span_attributes`
+#### `get_span_attributes`
```python
get_span_attributes(self) -> dict[str, Any]
```
-### `FastMCPProviderPrompt`
+### `FastMCPProviderPrompt`
Prompt that delegates rendering to a wrapped server's render_prompt().
@@ -94,7 +94,7 @@ When `render()` is called, this prompt invokes the wrapped server's
**Methods:**
-#### `wrap`
+#### `wrap`
```python
wrap(cls, server: Any, prompt: Prompt) -> FastMCPProviderPrompt
@@ -103,7 +103,7 @@ wrap(cls, server: Any, prompt: Prompt) -> FastMCPProviderPrompt
Wrap a Prompt to delegate rendering to the server's middleware.
-#### `render`
+#### `render`
```python
render(self, arguments: dict[str, Any] | None = None) -> PromptResult
@@ -115,13 +115,13 @@ This is called when the prompt is used within a transformed context
or other contexts where task_meta is not available.
-#### `get_span_attributes`
+#### `get_span_attributes`
```python
get_span_attributes(self) -> dict[str, Any]
```
-### `FastMCPProviderResourceTemplate`
+### `FastMCPProviderResourceTemplate`
Resource template that creates FastMCPProviderResources.
@@ -133,7 +133,7 @@ when read.
**Methods:**
-#### `wrap`
+#### `wrap`
```python
wrap(cls, server: Any, template: ResourceTemplate) -> FastMCPProviderResourceTemplate
@@ -142,7 +142,7 @@ wrap(cls, server: Any, template: ResourceTemplate) -> FastMCPProviderResourceTem
Wrap a ResourceTemplate to create FastMCPProviderResources.
-#### `create_resource`
+#### `create_resource`
```python
create_resource(self, uri: str, params: dict[str, Any]) -> Resource
@@ -155,7 +155,7 @@ We use `_original_uri_template` with `params` to construct the internal
URI that the nested server understands.
-#### `read`
+#### `read`
```python
read(self, arguments: dict[str, Any]) -> str | bytes | ResourceResult
@@ -167,7 +167,7 @@ Reads the resource via the wrapped server and returns the ResourceResult.
This method is called by Docket during background task execution.
-#### `register_with_docket`
+#### `register_with_docket`
```python
register_with_docket(self, docket: Docket) -> None
@@ -176,7 +176,7 @@ register_with_docket(self, docket: Docket) -> None
No-op: the child's actual template is registered via get_tasks().
-#### `add_to_docket`
+#### `add_to_docket`
```python
add_to_docket(self, docket: Docket, params: dict[str, Any], **kwargs: Any) -> Execution
@@ -188,13 +188,13 @@ The child's FunctionResourceTemplate.fn is registered (via get_tasks),
and it expects splatted **kwargs, so we splat params here.
-#### `get_span_attributes`
+#### `get_span_attributes`
```python
get_span_attributes(self) -> dict[str, Any]
```
-### `FastMCPProvider`
+### `FastMCPProvider`
Provider that wraps a FastMCP server.
@@ -210,7 +210,7 @@ This ensures middleware runs when components are executed.
**Methods:**
-#### `get_app_tool`
+#### `get_app_tool`
```python
get_app_tool(self, app_name: str, tool_name: str) -> Tool | None
@@ -219,7 +219,7 @@ get_app_tool(self, app_name: str, tool_name: str) -> Tool | None
Delegate to nested server's get_app_tool, wrapping for middleware.
-#### `get_tool_by_hash`
+#### `get_tool_by_hash`
```python
get_tool_by_hash(self, tool_hash: str, tool_name: str) -> Tool | None
@@ -228,7 +228,7 @@ get_tool_by_hash(self, tool_hash: str, tool_name: str) -> Tool | None
Delegate to nested server's get_tool_by_hash, wrapping for middleware.
-#### `get_tasks`
+#### `get_tasks`
```python
get_tasks(self) -> Sequence[FastMCPComponent]
@@ -242,7 +242,7 @@ server's transforms applied, then applies this provider's transforms
for correct registration keys.
-#### `lifespan`
+#### `lifespan`
```python
lifespan(self) -> AsyncIterator[None]
diff --git a/docs/python-sdk/fastmcp-server-tasks-context.mdx b/docs/python-sdk/fastmcp-server-tasks-context.mdx
new file mode 100644
index 000000000..945180ca7
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-tasks-context.mdx
@@ -0,0 +1,175 @@
+---
+title: context
+sidebarTitle: context
+---
+
+# `fastmcp.server.tasks.context`
+
+
+Task context and scoping for background task execution.
+
+Determines authorization scope (``get_task_scope``), manages the context
+snapshot that is captured at task submission and restored in workers
+(``TaskContextSnapshot``), and maintains in-process registries for live
+sessions and servers.
+
+
+## Functions
+
+### `get_task_scope`
+
+```python
+get_task_scope() -> str | None
+```
+
+
+Get the authorization scope for task isolation.
+
+Returns the raw scope identifier for the current access token, or
+``None`` when no auth context is present (anonymous tasks).
+
+The scope is composed as ``client_id|sub`` when the token carries a
+``sub`` claim — necessary for fixed-OAuth servers where ``client_id`` is
+shared across all users — and falls back to ``client_id`` alone for
+DCR/CIMD flows where the client identity is already per-user.
+
+Encoding for Redis/Docket keys happens at the boundary in ``keys.py``;
+this function returns the raw value.
+
+
+### `get_task_context`
+
+```python
+get_task_context() -> TaskContextInfo | None
+```
+
+
+Get the current task context if running inside a background task worker.
+
+This function extracts task information from the Docket execution context.
+Returns None if not running in a task context (e.g., foreground execution).
+
+**Returns:**
+- TaskContextInfo with task_id and task_scope, or None if not in a task.
+
+
+### `get_task_session_id`
+
+```python
+get_task_session_id() -> str | None
+```
+
+
+Get the session_id for the current background task, if available.
+
+Loads the task snapshot (from cache or Redis) and returns the session_id
+that was captured at task submission time. Returns None if not in a task
+context or if the snapshot isn't available.
+
+
+### `register_task_session`
+
+```python
+register_task_session(session_id: str, session: ServerSession) -> None
+```
+
+
+Register a session for in-process background task access.
+
+Called automatically when a task is submitted to Docket. The session is
+stored as a weakref so it doesn't prevent garbage collection when the
+client disconnects.
+
+
+### `get_task_session`
+
+```python
+get_task_session(session_id: str) -> ServerSession | None
+```
+
+
+Get a registered session by ID if still alive.
+
+Returns None in distributed workers where the session lives in another
+process — callers must handle this gracefully.
+
+
+### `register_task_server`
+
+```python
+register_task_server(task_id: str, server: FastMCP) -> None
+```
+
+
+Register the server for a background task.
+
+Called at task-submission time so that background workers can resolve
+the correct (child) server for mounted tasks.
+
+
+### `get_task_server`
+
+```python
+get_task_server(task_id: str) -> FastMCP | None
+```
+
+
+Get the registered server for a background task, if still alive.
+
+
+## Classes
+
+### `TaskContextInfo`
+
+
+Information about the current background task context.
+
+Returned by ``get_task_context()`` when running inside a Docket worker.
+Contains identifiers needed to communicate with the MCP session.
+
+
+### `TaskContextSnapshot`
+
+
+All context data snapshotted at task-submission time.
+
+Stored as a single Redis key per task, restored once in the worker.
+
+
+**Methods:**
+
+#### `capture`
+
+```python
+capture(cls) -> TaskContextSnapshot
+```
+
+Capture current context for background task execution.
+
+
+#### `from_json`
+
+```python
+from_json(cls, raw: str | bytes) -> TaskContextSnapshot
+```
+
+Deserialize from JSON stored in Redis.
+
+
+#### `to_json`
+
+```python
+to_json(self) -> str
+```
+
+Serialize to JSON for Redis storage.
+
+
+#### `save`
+
+```python
+save(self, docket: Docket, task_scope: str | None, task_id: str, ttl_seconds: int) -> None
+```
+
+Store this snapshot as a single Redis key.
+
diff --git a/docs/python-sdk/fastmcp-server-tasks-elicitation.mdx b/docs/python-sdk/fastmcp-server-tasks-elicitation.mdx
index cc6f3dea2..3914d207c 100644
--- a/docs/python-sdk/fastmcp-server-tasks-elicitation.mdx
+++ b/docs/python-sdk/fastmcp-server-tasks-elicitation.mdx
@@ -23,7 +23,7 @@ internal APIs for background task coordination.
## Functions
-### `elicit_for_task`
+### `elicit_for_task`
```python
elicit_for_task(task_id: str, session: ServerSession | None, message: str, schema: dict[str, Any], fastmcp: FastMCP) -> mcp.types.ElicitResult
@@ -50,10 +50,10 @@ in a Docket worker context where there's no active MCP request.
- `McpError`: If the elicitation request fails
-### `relay_elicitation`
+### `relay_elicitation`
```python
-relay_elicitation(session: ServerSession, session_id: str, task_id: str, elicitation: dict[str, Any], fastmcp: FastMCP) -> None
+relay_elicitation(session: ServerSession, task_scope: str | None, task_id: str, elicitation: dict[str, Any], fastmcp: FastMCP) -> None
```
@@ -66,16 +66,16 @@ response to Redis so the blocked worker can resume.
**Args:**
- `session`: MCP ServerSession
-- `session_id`: Session identifier
+- `task_scope`: Authorization scope for Redis key construction
- `task_id`: Background task ID
- `elicitation`: Elicitation metadata (message, requestedSchema)
- `fastmcp`: FastMCP server instance
-### `handle_task_input`
+### `handle_task_input`
```python
-handle_task_input(task_id: str, session_id: str, action: str, content: dict[str, Any] | None, fastmcp: FastMCP) -> bool
+handle_task_input(task_id: str, task_scope: str | None, action: str, content: dict[str, Any] | None, fastmcp: FastMCP) -> bool
```
@@ -86,7 +86,7 @@ request from a background task.
**Args:**
- `task_id`: The background task ID
-- `session_id`: The MCP session ID
+- `task_scope`: Authorization scope for Redis key construction
- `action`: The elicitation action ("accept", "decline", "cancel")
- `content`: The response content (for "accept" action)
- `fastmcp`: The FastMCP server instance
diff --git a/docs/python-sdk/fastmcp-server-tasks-handlers.mdx b/docs/python-sdk/fastmcp-server-tasks-handlers.mdx
index 3493b752e..fd3659421 100644
--- a/docs/python-sdk/fastmcp-server-tasks-handlers.mdx
+++ b/docs/python-sdk/fastmcp-server-tasks-handlers.mdx
@@ -13,7 +13,7 @@ Handles queuing tool/prompt/resource executions to Docket as background tasks.
## Functions
-### `submit_to_docket`
+### `submit_to_docket`
```python
submit_to_docket(task_type: Literal['tool', 'resource', 'template', 'prompt'], key: str, component: Tool | Resource | ResourceTemplate | Prompt, arguments: dict[str, Any] | None = None, task_meta: TaskMeta | None = None) -> mcp.types.CreateTaskResult
diff --git a/docs/python-sdk/fastmcp-server-tasks-keys.mdx b/docs/python-sdk/fastmcp-server-tasks-keys.mdx
index a274d3c1d..a852fadd9 100644
--- a/docs/python-sdk/fastmcp-server-tasks-keys.mdx
+++ b/docs/python-sdk/fastmcp-server-tasks-keys.mdx
@@ -6,34 +6,40 @@ sidebarTitle: keys
# `fastmcp.server.tasks.keys`
-Task key management for SEP-1686 background tasks.
+Docket and Redis key encoding for background tasks.
-Task keys encode security scoping and metadata in the Docket key format:
- `{session_id}:{client_task_id}:{task_type}:{component_identifier}`
+The compound Docket task key embeds the auth boundary so that the parser can
+reject cross-scope access without consulting Redis. Authenticated and
+anonymous tasks live in disjoint keyspaces:
-This format provides:
-- Session-based security scoping (prevents cross-session access)
-- Task type identification (tool/prompt/resource)
-- Component identification (name or URI for result conversion)
+ auth:{enc_scope}:{client_task_id}:{task_type}:{enc_identifier}
+ anon:{client_task_id}:{task_type}:{enc_identifier}
+
+The same `auth/anon` partition is used for the per-task Redis prefix
+(``fastmcp:task:auth:{enc_scope}`` vs ``fastmcp:task:anon``) — see
+``task_redis_prefix``.
+
+``task_scope`` is the raw scope identifier (typically derived from
+``client_id`` or ``client_id|sub``); encoding happens once, at the boundary,
+in this module.
## Functions
-### `build_task_key`
+### `build_task_key`
```python
-build_task_key(session_id: str, client_task_id: str, task_type: str, component_identifier: str) -> str
+build_task_key(task_scope: str | None, client_task_id: str, task_type: str, component_identifier: str) -> str
```
Build Docket task key with embedded metadata.
-Format: `{session_id}:{client_task_id}:{task_type}:{component_identifier}`
-
-The component_identifier is URI-encoded to handle special characters (colons, slashes, etc.).
+When ``task_scope`` is ``None`` the task is anonymous and lives in the
+``anon`` keyspace. Otherwise it lives under ``auth:{enc_scope}``.
**Args:**
-- `session_id`: Session ID for security scoping
+- `task_scope`: Raw authorization scope, or ``None`` for anonymous tasks
- `client_task_id`: Client-provided task ID
- `task_type`: Type of task ("tool", "prompt", "resource")
- `component_identifier`: Tool name, prompt name, or resource URI
@@ -43,16 +49,18 @@ The component_identifier is URI-encoded to handle special characters (colons, sl
**Examples:**
->>> build_task_key("session123", "task456", "tool", "my_tool")
-'session123:task456:tool:my_tool'
->>> build_task_key("session123", "task456", "resource", "file://data.txt")
-'session123:task456:resource:file%3A%2F%2Fdata.txt'
+>>> build_task_key("client-a", "task456", "tool", "my_tool")
+'auth:client-a:task456:tool:my_tool'
+>>> build_task_key(None, "task456", "tool", "my_tool")
+'anon:task456:tool:my_tool'
+>>> build_task_key("client-a", "task456", "resource", "file://data.txt")
+'auth:client-a:task456:resource:file%3A%2F%2Fdata.txt'
-### `parse_task_key`
+### `parse_task_key`
```python
-parse_task_key(task_key: str) -> dict[str, str]
+parse_task_key(task_key: str) -> TaskKeyParts
```
@@ -62,17 +70,21 @@ Parse Docket task key to extract metadata.
- `task_key`: Encoded task key from Docket
**Returns:**
-- Dict with keys: session_id, client_task_id, task_type, component_identifier
+- Dict with keys: ``task_scope`` (``str | None``), ``client_task_id``,
+- ``task_type``, ``component_identifier``.
+
+**Raises:**
+- `ValueError`: If the key has an unrecognized tag or wrong segment count.
**Examples:**
->>> parse_task_key("session123:task456:tool:my_tool")
-`{'session_id': 'session123', 'client_task_id': 'task456', 'task_type': 'tool', 'component_identifier': 'my_tool'}`
->>> parse_task_key("session123:task456:resource:file%3A%2F%2Fdata.txt")
-`{'session_id': 'session123', 'client_task_id': 'task456', 'task_type': 'resource', 'component_identifier': 'file://data.txt'}`
+>>> parse_task_key("auth:client-a:task456:tool:my_tool")
+`{'task_scope': 'client-a', 'client_task_id': 'task456', 'task_type': 'tool', 'component_identifier': 'my_tool'}`
+>>> parse_task_key("anon:task456:tool:my_tool")
+`{'task_scope': None, 'client_task_id': 'task456', 'task_type': 'tool', 'component_identifier': 'my_tool'}`
-### `get_client_task_id_from_key`
+### `get_client_task_id_from_key`
```python
get_client_task_id_from_key(task_key: str) -> str
@@ -85,5 +97,37 @@ Extract just the client task ID from a task key.
- `task_key`: Full encoded task key
**Returns:**
-- Client-provided task ID (second segment)
+- Client-provided task ID
+
+**Examples:**
+
+>>> get_client_task_id_from_key("auth:client-a:task456:tool:my_tool")
+'task456'
+>>> get_client_task_id_from_key("anon:task456:tool:my_tool")
+'task456'
+
+
+### `task_redis_prefix`
+
+```python
+task_redis_prefix(task_scope: str | None) -> str
+```
+
+
+Return the Redis key prefix that owns a given scope.
+
+Authenticated tasks live under ``fastmcp:task:auth:{enc_scope}``;
+anonymous tasks live under ``fastmcp:task:anon``. Callers append
+``f":{task_id}:..."`` to compose the final key.
+
+
+## Classes
+
+### `TaskKeyParts`
+
+
+Decoded segments of a Docket task key.
+
+``task_scope`` is ``None`` for anonymous tasks, the raw scope string
+otherwise.
diff --git a/docs/python-sdk/fastmcp-server-tasks-notifications.mdx b/docs/python-sdk/fastmcp-server-tasks-notifications.mdx
index 217b4b6ac..441760f34 100644
--- a/docs/python-sdk/fastmcp-server-tasks-notifications.mdx
+++ b/docs/python-sdk/fastmcp-server-tasks-notifications.mdx
@@ -67,7 +67,7 @@ This loop:
- `fastmcp`: FastMCP server instance (for elicitation relay)
-### `ensure_subscriber_running`
+### `ensure_subscriber_running`
```python
ensure_subscriber_running(session_id: str, session: ServerSession, docket: Docket, fastmcp: FastMCP) -> None
@@ -86,7 +86,7 @@ Safe to call multiple times for the same session.
- `fastmcp`: FastMCP server instance (for elicitation relay)
-### `stop_subscriber`
+### `stop_subscriber`
```python
stop_subscriber(session_id: str) -> None
@@ -102,7 +102,7 @@ for delivery if client reconnects (with TTL expiration).
- `session_id`: Session identifier
-### `get_subscriber_count`
+### `get_subscriber_count`
```python
get_subscriber_count() -> int
diff --git a/docs/python-sdk/fastmcp-server-tasks-requests.mdx b/docs/python-sdk/fastmcp-server-tasks-requests.mdx
index a8b31a13d..64ac4a263 100644
--- a/docs/python-sdk/fastmcp-server-tasks-requests.mdx
+++ b/docs/python-sdk/fastmcp-server-tasks-requests.mdx
@@ -16,7 +16,7 @@ This module requires fastmcp[tasks] (pydocket). It is only imported when docket
## Functions
-### `tasks_get_handler`
+### `tasks_get_handler`
```python
tasks_get_handler(server: FastMCP, params: dict[str, Any]) -> GetTaskResult
@@ -33,7 +33,7 @@ Handle MCP 'tasks/get' request (SEP-1686).
- Task status response with spec-compliant fields
-### `tasks_result_handler`
+### `tasks_result_handler`
```python
tasks_result_handler(server: FastMCP, params: dict[str, Any]) -> Any
@@ -52,7 +52,7 @@ Converts raw task return values to MCP types based on task type.
- MCP result (CallToolResult, GetPromptResult, or ReadResourceResult)
-### `tasks_list_handler`
+### `tasks_list_handler`
```python
tasks_list_handler(server: FastMCP, params: dict[str, Any]) -> ListTasksResult
@@ -71,7 +71,7 @@ Note: With client-side tracking, this returns minimal info.
- Response with tasks list and pagination
-### `tasks_cancel_handler`
+### `tasks_cancel_handler`
```python
tasks_cancel_handler(server: FastMCP, params: dict[str, Any]) -> CancelTaskResult