From fe197557c8036712b93f13134aa6c282bae739e6 Mon Sep 17 00:00:00 2001
From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
Date: Fri, 16 Jan 2026 21:16:06 -0500
Subject: [PATCH 1/5] Rename _fastmcp metadata namespace to fastmcp and make
non-optional
- Rename meta namespace from `_fastmcp` to `fastmcp`
- Always include fastmcp metadata (remove `include_fastmcp_meta` setting)
- Add component version to metadata when available
---
docs/clients/prompts.mdx | 8 +-
docs/clients/resources.mdx | 10 +-
docs/clients/tools.mdx | 8 +-
docs/development/upgrade-guide.mdx | 62 +++++++++
docs/integrations/openapi.mdx | 6 +-
docs/servers/server.mdx | 9 --
src/fastmcp/prompts/prompt.py | 4 +-
src/fastmcp/resources/resource.py | 4 +-
src/fastmcp/resources/template.py | 4 +-
src/fastmcp/server/providers/proxy.py | 10 +-
src/fastmcp/server/server.py | 11 --
src/fastmcp/settings.py | 14 --
src/fastmcp/tools/function_tool.py | 6 +-
src/fastmcp/tools/tool.py | 4 +-
src/fastmcp/utilities/components.py | 29 ++--
.../server/middleware/test_tool_injection.py | 10 +-
.../providers/proxy/test_proxy_client.py | 2 +-
.../providers/proxy/test_proxy_server.py | 8 +-
tests/server/test_server.py | 124 ++----------------
tests/utilities/test_components.py | 60 ++++++---
20 files changed, 163 insertions(+), 230 deletions(-)
diff --git a/docs/clients/prompts.mdx b/docs/clients/prompts.mdx
index 1c05b75b3f..c4ae2f4d4d 100644
--- a/docs/clients/prompts.mdx
+++ b/docs/clients/prompts.mdx
@@ -27,7 +27,7 @@ async with client:
print(f"Arguments: {[arg.name for arg in prompt.arguments]}")
# Access tags and other metadata
if prompt.meta:
- fastmcp_meta = prompt.meta.get('_fastmcp', {})
+ fastmcp_meta = prompt.meta.get('fastmcp', {})
print(f"Tags: {fastmcp_meta.get('tags', [])}")
```
@@ -45,15 +45,15 @@ async with client:
analysis_prompts = [
prompt for prompt in prompts
if prompt.meta and
- prompt.meta.get('_fastmcp', {}) and
- 'analysis' in prompt.meta.get('_fastmcp', {}).get('tags', [])
+ prompt.meta.get('fastmcp', {}) and
+ 'analysis' in prompt.meta.get('fastmcp', {}).get('tags', [])
]
print(f"Found {len(analysis_prompts)} analysis prompts")
```
-The `meta` field is part of the standard MCP specification. FastMCP servers include tags and other metadata within a `_fastmcp` namespace (e.g., `meta._fastmcp.tags`) to avoid conflicts with user-defined metadata. This behavior can be controlled with the server's `include_fastmcp_meta` setting - when disabled, the `_fastmcp` namespace won't be included. Other MCP server implementations may not provide this metadata structure.
+The `meta` field is part of the standard MCP specification. FastMCP servers always include tags and other metadata within a `fastmcp` namespace (e.g., `meta.fastmcp.tags`) to avoid conflicts with user-defined metadata. Component versions are also included in the metadata when available (e.g., `meta.fastmcp.version`). Other MCP server implementations may not provide this metadata structure.
## Using Prompts
diff --git a/docs/clients/resources.mdx b/docs/clients/resources.mdx
index 22ebafab81..cef312267a 100644
--- a/docs/clients/resources.mdx
+++ b/docs/clients/resources.mdx
@@ -36,7 +36,7 @@ async with client:
print(f"MIME Type: {resource.mimeType}")
# Access tags and other metadata
if resource.meta:
- fastmcp_meta = resource.meta.get('_fastmcp', {})
+ fastmcp_meta = resource.meta.get('fastmcp', {})
print(f"Tags: {fastmcp_meta.get('tags', [])}")
```
@@ -55,7 +55,7 @@ async with client:
print(f"Description: {template.description}")
# Access tags and other metadata
if template.meta:
- fastmcp_meta = template.meta.get('_fastmcp', {})
+ fastmcp_meta = template.meta.get('fastmcp', {})
print(f"Tags: {fastmcp_meta.get('tags', [])}")
```
@@ -73,15 +73,15 @@ async with client:
config_resources = [
resource for resource in resources
if resource.meta and
- resource.meta.get('_fastmcp', {}) and
- 'config' in resource.meta.get('_fastmcp', {}).get('tags', [])
+ resource.meta.get('fastmcp', {}) and
+ 'config' in resource.meta.get('fastmcp', {}).get('tags', [])
]
print(f"Found {len(config_resources)} config resources")
```
-The `meta` field is part of the standard MCP specification. FastMCP servers include tags and other metadata within a `_fastmcp` namespace (e.g., `meta._fastmcp.tags`) to avoid conflicts with user-defined metadata. This behavior can be controlled with the server's `include_fastmcp_meta` setting - when disabled, the `_fastmcp` namespace won't be included. Other MCP server implementations may not provide this metadata structure.
+The `meta` field is part of the standard MCP specification. FastMCP servers always include tags and other metadata within a `fastmcp` namespace (e.g., `meta.fastmcp.tags`) to avoid conflicts with user-defined metadata. Component versions are also included in the metadata when available (e.g., `meta.fastmcp.version`). Other MCP server implementations may not provide this metadata structure.
## Reading Resources
diff --git a/docs/clients/tools.mdx b/docs/clients/tools.mdx
index 4d7ebabc4e..17bc9f6924 100644
--- a/docs/clients/tools.mdx
+++ b/docs/clients/tools.mdx
@@ -27,7 +27,7 @@ async with client:
print(f"Parameters: {tool.inputSchema}")
# Access tags and other metadata
if tool.meta:
- fastmcp_meta = tool.meta.get('_fastmcp', {})
+ fastmcp_meta = tool.meta.get('fastmcp', {})
print(f"Tags: {fastmcp_meta.get('tags', [])}")
```
@@ -45,15 +45,15 @@ async with client:
analysis_tools = [
tool for tool in tools
if tool.meta and
- tool.meta.get('_fastmcp', {}) and
- 'analysis' in tool.meta.get('_fastmcp', {}).get('tags', [])
+ tool.meta.get('fastmcp', {}) and
+ 'analysis' in tool.meta.get('fastmcp', {}).get('tags', [])
]
print(f"Found {len(analysis_tools)} analysis tools")
```
-The `meta` field is part of the standard MCP specification. FastMCP servers include tags and other metadata within a `_fastmcp` namespace (e.g., `meta._fastmcp.tags`) to avoid conflicts with user-defined metadata. This behavior can be controlled with the server's `include_fastmcp_meta` setting - when disabled, the `_fastmcp` namespace won't be included. Other MCP server implementations may not provide this metadata structure.
+The `meta` field is part of the standard MCP specification. FastMCP servers always include tags and other metadata within a `fastmcp` namespace (e.g., `meta.fastmcp.tags`) to avoid conflicts with user-defined metadata. Component versions are also included in the metadata when available (e.g., `meta.fastmcp.version`). Other MCP server implementations may not provide this metadata structure.
## Executing Tools
diff --git a/docs/development/upgrade-guide.mdx b/docs/development/upgrade-guide.mdx
index c5465f1b3c..cb59818a93 100644
--- a/docs/development/upgrade-guide.mdx
+++ b/docs/development/upgrade-guide.mdx
@@ -8,6 +8,68 @@ tag: NEW
This guide provides migration instructions for breaking changes and major updates when upgrading between FastMCP versions.
+## FastMCP Metadata Namespace Change
+
+### Metadata Namespace Renamed
+
+The FastMCP metadata namespace has been renamed from `_fastmcp` to `fastmcp` (underscore prefix removed). All metadata is now always included in component responses.
+
+**What changed:**
+- Metadata namespace: `meta._fastmcp` → `meta.fastmcp`
+- The `include_fastmcp_meta` setting and parameter have been removed
+- Component version is now included in metadata when available (`meta.fastmcp.version`)
+
+**Migration steps:**
+
+1. **Update metadata access patterns:**
+
+ ```python Before
+ tags = tool.meta.get("_fastmcp", {}).get("tags", [])
+ ```
+
+ ```python After
+ tags = tool.meta.get("fastmcp", {}).get("tags", [])
+ ```
+
+
+2. **Remove `include_fastmcp_meta` parameter:**
+
+ ```python Before
+ mcp = FastMCP(include_fastmcp_meta=False)
+ ```
+
+ ```python After
+ # Parameter removed - metadata is always included
+ mcp = FastMCP()
+ ```
+
+
+3. **Remove `include_fastmcp_meta` from component serialization:**
+
+ ```python Before
+ mcp_tool = tool.to_mcp_tool(include_fastmcp_meta=True)
+ ```
+
+ ```python After
+ mcp_tool = tool.to_mcp_tool()
+ ```
+
+
+4. **Access component version from metadata:**
+
+ ```python Before
+ # Version was not available in metadata
+ ```
+
+ ```python After
+ version = tool.meta.get("fastmcp", {}).get("version")
+ if version:
+ print(f"Tool version: {version}")
+ ```
+
+
+**Why this changed:** The underscore prefix was removed to make the namespace more discoverable and consistent with standard naming conventions. Making metadata always included simplifies the API and ensures consistent behavior across all FastMCP servers.
+
## v3.0.0
### WSTransport Removed
diff --git a/docs/integrations/openapi.mdx b/docs/integrations/openapi.mdx
index 7eceea4077..88dc19b142 100644
--- a/docs/integrations/openapi.mdx
+++ b/docs/integrations/openapi.mdx
@@ -324,7 +324,7 @@ mcp = FastMCP.from_openapi(
#### OpenAPI Tags in Client Meta
-FastMCP automatically includes OpenAPI tags from your specification in the component's metadata. These tags are available to MCP clients through the `meta._fastmcp.tags` field, allowing clients to filter and organize components based on the original OpenAPI tagging:
+FastMCP automatically includes OpenAPI tags from your specification in the component's metadata. These tags are available to MCP clients through the `meta.fastmcp.tags` field, allowing clients to filter and organize components based on the original OpenAPI tagging:
```json {5} OpenAPI spec with tags
@@ -345,8 +345,8 @@ async with client:
tools = await client.list_tools()
for tool in tools:
if tool.meta:
- # OpenAPI tags are now available in _fastmcp namespace!
- fastmcp_meta = tool.meta.get('_fastmcp', {})
+ # OpenAPI tags are now available in fastmcp namespace!
+ fastmcp_meta = tool.meta.get('fastmcp', {})
openapi_tags = fastmcp_meta.get('tags', [])
if 'users' in openapi_tags:
print(f"Found user-related tool: {tool.name}")
diff --git a/docs/servers/server.mdx b/docs/servers/server.mdx
index 90cbcd7e9e..777c7adf16 100644
--- a/docs/servers/server.mdx
+++ b/docs/servers/server.mdx
@@ -95,11 +95,6 @@ The `FastMCP` constructor accepts several arguments:
Controls how tool input parameters are validated. When `False` (default), FastMCP uses Pydantic's flexible validation that coerces compatible inputs (e.g., `"10"` → `10` for int parameters). When `True`, uses the MCP SDK's JSON Schema validation to validate inputs against the exact schema before passing them to your function, rejecting any type mismatches. The default mode improves compatibility with LLM clients while maintaining type safety. See [Input Validation Modes](/servers/tools#input-validation-modes) for details
-
-
-
- Whether to include FastMCP metadata in component responses. When `True`, component tags and other FastMCP-specific metadata are included in the `_fastmcp` namespace within each component's `meta` field. When `False`, this metadata is omitted, resulting in cleaner integration with external systems. Can be overridden globally via `FASTMCP_INCLUDE_FASTMCP_META` environment variable
-
## Components
@@ -344,7 +339,6 @@ mcp = FastMCP(
on_duplicate_tools="error", # Handle duplicate registrations
on_duplicate_resources="warn",
on_duplicate_prompts="replace",
- include_fastmcp_meta=False, # Disable FastMCP metadata for cleaner integration
)
```
@@ -359,14 +353,12 @@ import fastmcp
print(fastmcp.settings.log_level) # Default: "INFO"
print(fastmcp.settings.mask_error_details) # Default: False
print(fastmcp.settings.strict_input_validation) # Default: False
-print(fastmcp.settings.include_fastmcp_meta) # Default: True
```
Common global settings include:
- **`log_level`**: Logging level ("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"), set with `FASTMCP_LOG_LEVEL`
- **`mask_error_details`**: Whether to hide detailed error information from clients, set with `FASTMCP_MASK_ERROR_DETAILS`
- **`strict_input_validation`**: Controls tool input validation mode (default: False for flexible coercion), set with `FASTMCP_STRICT_INPUT_VALIDATION`. See [Input Validation Modes](/servers/tools#input-validation-modes)
-- **`include_fastmcp_meta`**: Whether to include FastMCP metadata in component responses (default: True), set with `FASTMCP_INCLUDE_FASTMCP_META`
- **`env_file`**: Path to the environment file to load settings from (default: ".env"), set with `FASTMCP_ENV_FILE`. Useful when your project uses a `.env` file with syntax incompatible with python-dotenv
### Transport-Specific Configuration
@@ -399,6 +391,5 @@ Global FastMCP settings can be configured via environment variables (prefixed wi
export FASTMCP_LOG_LEVEL=DEBUG
export FASTMCP_MASK_ERROR_DETAILS=True
export FASTMCP_STRICT_INPUT_VALIDATION=False
-export FASTMCP_INCLUDE_FASTMCP_META=False
```
diff --git a/src/fastmcp/prompts/prompt.py b/src/fastmcp/prompts/prompt.py
index fde2c9e4f0..57bbecd56a 100644
--- a/src/fastmcp/prompts/prompt.py
+++ b/src/fastmcp/prompts/prompt.py
@@ -200,8 +200,6 @@ class Prompt(FastMCPComponent):
def to_mcp_prompt(
self,
- *,
- include_fastmcp_meta: bool | None = None,
**overrides: Any,
) -> SDKPrompt:
"""Convert the prompt to an MCP prompt."""
@@ -221,7 +219,7 @@ def to_mcp_prompt(
title=overrides.get("title", self.title),
icons=overrides.get("icons", self.icons),
_meta=overrides.get( # type: ignore[call-arg] # _meta is Pydantic alias for meta field
- "_meta", self.get_meta(include_fastmcp_meta=include_fastmcp_meta)
+ "_meta", self.get_meta()
),
)
diff --git a/src/fastmcp/resources/resource.py b/src/fastmcp/resources/resource.py
index 5dd907348c..6b23468e4d 100644
--- a/src/fastmcp/resources/resource.py
+++ b/src/fastmcp/resources/resource.py
@@ -357,8 +357,6 @@ async def _read(
def to_mcp_resource(
self,
- *,
- include_fastmcp_meta: bool | None = None,
**overrides: Any,
) -> SDKResource:
"""Convert the resource to an SDKResource."""
@@ -372,7 +370,7 @@ def to_mcp_resource(
icons=overrides.get("icons", self.icons),
annotations=overrides.get("annotations", self.annotations),
_meta=overrides.get( # type: ignore[call-arg] # _meta is Pydantic alias for meta field
- "_meta", self.get_meta(include_fastmcp_meta=include_fastmcp_meta)
+ "_meta", self.get_meta()
),
)
diff --git a/src/fastmcp/resources/template.py b/src/fastmcp/resources/template.py
index 63c77e2c3b..343c124240 100644
--- a/src/fastmcp/resources/template.py
+++ b/src/fastmcp/resources/template.py
@@ -251,8 +251,6 @@ async def create_resource(self, uri: str, params: dict[str, Any]) -> Resource:
def to_mcp_template(
self,
- *,
- include_fastmcp_meta: bool | None = None,
**overrides: Any,
) -> SDKResourceTemplate:
"""Convert the resource template to an SDKResourceTemplate."""
@@ -266,7 +264,7 @@ def to_mcp_template(
icons=overrides.get("icons", self.icons),
annotations=overrides.get("annotations", self.annotations),
_meta=overrides.get( # type: ignore[call-arg] # _meta is Pydantic alias for meta field
- "_meta", self.get_meta(include_fastmcp_meta=include_fastmcp_meta)
+ "_meta", self.get_meta()
),
)
diff --git a/src/fastmcp/server/providers/proxy.py b/src/fastmcp/server/providers/proxy.py
index 699b18308a..a21faa27e3 100644
--- a/src/fastmcp/server/providers/proxy.py
+++ b/src/fastmcp/server/providers/proxy.py
@@ -104,7 +104,7 @@ def from_mcp_tool(
output_schema=mcp_tool.outputSchema,
icons=mcp_tool.icons,
meta=mcp_tool.meta,
- tags=(mcp_tool.meta or {}).get("_fastmcp", {}).get("tags", []),
+ tags=(mcp_tool.meta or {}).get("fastmcp", {}).get("tags", []),
)
async def run(
@@ -211,7 +211,7 @@ def from_mcp_resource(
mime_type=mcp_resource.mimeType or "text/plain",
icons=mcp_resource.icons,
meta=mcp_resource.meta,
- tags=(mcp_resource.meta or {}).get("_fastmcp", {}).get("tags", []),
+ tags=(mcp_resource.meta or {}).get("fastmcp", {}).get("tags", []),
task_config=TaskConfig(mode="forbidden"),
)
@@ -309,7 +309,7 @@ def from_mcp_template( # type: ignore[override]
icons=mcp_template.icons,
parameters={}, # Remote templates don't have local parameters
meta=mcp_template.meta,
- tags=(mcp_template.meta or {}).get("_fastmcp", {}).get("tags", []),
+ tags=(mcp_template.meta or {}).get("fastmcp", {}).get("tags", []),
task_config=TaskConfig(mode="forbidden"),
)
@@ -371,7 +371,7 @@ async def create_resource(
].mimeType, # Use first item's mimeType for backward compatibility
icons=self.icons,
meta=self.meta,
- tags=(self.meta or {}).get("_fastmcp", {}).get("tags", []),
+ tags=(self.meta or {}).get("fastmcp", {}).get("tags", []),
_cached_content=cached_content,
)
@@ -429,7 +429,7 @@ def from_mcp_prompt(
arguments=arguments,
icons=mcp_prompt.icons,
meta=mcp_prompt.meta,
- tags=(mcp_prompt.meta or {}).get("_fastmcp", {}).get("tags", []),
+ tags=(mcp_prompt.meta or {}).get("fastmcp", {}).get("tags", []),
task_config=TaskConfig(mode="forbidden"),
)
diff --git a/src/fastmcp/server/server.py b/src/fastmcp/server/server.py
index f83e8224b1..3ca76f4591 100644
--- a/src/fastmcp/server/server.py
+++ b/src/fastmcp/server/server.py
@@ -248,7 +248,6 @@ def __init__(
tool_serializer: ToolResultSerializerType | None = None,
include_tags: Collection[str] | None = None,
exclude_tags: Collection[str] | None = None,
- include_fastmcp_meta: bool | None = None,
on_duplicate: DuplicateBehavior | None = None,
strict_input_validation: bool | None = None,
tasks: bool | None = None,
@@ -406,12 +405,6 @@ def __init__(
sampling_handler_behavior or "fallback"
)
- self.include_fastmcp_meta: bool = (
- include_fastmcp_meta
- if include_fastmcp_meta is not None
- else fastmcp.settings.include_fastmcp_meta
- )
-
self._handle_deprecated_settings(
log_level=log_level,
debug=debug,
@@ -1939,7 +1932,6 @@ async def _list_tools_mcp(self) -> list[SDKTool]:
return [
tool.to_mcp_tool(
name=tool.name,
- include_fastmcp_meta=self.include_fastmcp_meta,
)
for tool in tools
]
@@ -1956,7 +1948,6 @@ async def _list_resources_mcp(self) -> list[SDKResource]:
return [
resource.to_mcp_resource(
uri=str(resource.uri),
- include_fastmcp_meta=self.include_fastmcp_meta,
)
for resource in resources
]
@@ -1973,7 +1964,6 @@ async def _list_resource_templates_mcp(self) -> list[SDKResourceTemplate]:
return [
template.to_mcp_template(
uriTemplate=template.uri_template,
- include_fastmcp_meta=self.include_fastmcp_meta,
)
for template in templates
]
@@ -1990,7 +1980,6 @@ async def _list_prompts_mcp(self) -> list[SDKPrompt]:
return [
prompt.to_mcp_prompt(
name=prompt.name,
- include_fastmcp_meta=self.include_fastmcp_meta,
)
for prompt in prompts
]
diff --git a/src/fastmcp/settings.py b/src/fastmcp/settings.py
index 5a8ca57936..0257e8d3bd 100644
--- a/src/fastmcp/settings.py
+++ b/src/fastmcp/settings.py
@@ -305,20 +305,6 @@ def normalize_log_level(cls, v):
False # If True, uses true stateless mode (new transport per request)
)
- include_fastmcp_meta: Annotated[
- bool,
- Field(
- description=inspect.cleandoc(
- """
- Whether to include FastMCP meta in the server's MCP responses.
- If True, a `_fastmcp` key will be added to the `meta` field of
- all MCP component responses. This key will contain a dict of
- various FastMCP-specific metadata, such as tags.
- """
- ),
- ),
- ] = True
-
mounted_components_raise_on_load_error: Annotated[
bool,
Field(
diff --git a/src/fastmcp/tools/function_tool.py b/src/fastmcp/tools/function_tool.py
index 890841ce80..be5e16f7ab 100644
--- a/src/fastmcp/tools/function_tool.py
+++ b/src/fastmcp/tools/function_tool.py
@@ -84,8 +84,6 @@ class FunctionTool(Tool):
def to_mcp_tool(
self,
- *,
- include_fastmcp_meta: bool | None = None,
**overrides: Any,
) -> mcp.types.Tool:
"""Convert the FastMCP tool to an MCP tool.
@@ -93,9 +91,7 @@ def to_mcp_tool(
Extends the base implementation to add task execution mode if enabled.
"""
# Get base MCP tool from parent
- mcp_tool = super().to_mcp_tool(
- include_fastmcp_meta=include_fastmcp_meta, **overrides
- )
+ mcp_tool = super().to_mcp_tool(**overrides)
# Add task execution mode per SEP-1686
# Only set execution if not overridden and task execution is supported
diff --git a/src/fastmcp/tools/tool.py b/src/fastmcp/tools/tool.py
index f4b83247ce..36b4913433 100644
--- a/src/fastmcp/tools/tool.py
+++ b/src/fastmcp/tools/tool.py
@@ -164,8 +164,6 @@ def _validate_tool_name(self) -> Tool:
def to_mcp_tool(
self,
- *,
- include_fastmcp_meta: bool | None = None,
**overrides: Any,
) -> MCPTool:
"""Convert the FastMCP tool to an MCP tool."""
@@ -186,7 +184,7 @@ def to_mcp_tool(
annotations=overrides.get("annotations", self.annotations),
execution=overrides.get("execution", self.execution),
_meta=overrides.get( # type: ignore[call-arg] # _meta is Pydantic alias for meta field
- "_meta", self.get_meta(include_fastmcp_meta=include_fastmcp_meta)
+ "_meta", self.get_meta()
),
)
diff --git a/src/fastmcp/utilities/components.py b/src/fastmcp/utilities/components.py
index b9a7f2eab9..067aafe10e 100644
--- a/src/fastmcp/utilities/components.py
+++ b/src/fastmcp/utilities/components.py
@@ -7,7 +7,6 @@
from pydantic import BeforeValidator, Field
from typing_extensions import Self, TypeVar
-import fastmcp
from fastmcp.server.tasks.config import TaskConfig
from fastmcp.utilities.types import FastMCPBaseModel
@@ -20,6 +19,7 @@
class FastMCPMeta(TypedDict, total=False):
tags: list[str]
+ version: str
def _convert_set_default_none(maybe_set: set[T] | Sequence[T] | None) -> set[T]:
@@ -126,27 +126,24 @@ def key(self) -> str:
base_key = self.make_key(self.name)
return f"{base_key}@{self.version or ''}"
- def get_meta(
- self, include_fastmcp_meta: bool | None = None
- ) -> dict[str, Any] | None:
+ def get_meta(self) -> dict[str, Any] | None:
"""
Get the meta information about the component.
- If include_fastmcp_meta is True, a `_fastmcp` key will be added to the
- meta, containing a `tags` field with the tags of the component.
+ A `fastmcp` key will always be included in the meta, containing a `tags`
+ field with the tags of the component, and optionally a `version` field
+ if the component has a version.
"""
-
- if include_fastmcp_meta is None:
- include_fastmcp_meta = fastmcp.settings.include_fastmcp_meta
-
meta = self.meta or {}
- if include_fastmcp_meta:
- fastmcp_meta = FastMCPMeta(tags=sorted(self.tags))
- # overwrite any existing _fastmcp meta with keys from the new one
- if upstream_meta := meta.get("_fastmcp"):
- fastmcp_meta = upstream_meta | fastmcp_meta
- meta["_fastmcp"] = fastmcp_meta
+ fastmcp_meta: FastMCPMeta = {"tags": sorted(self.tags)}
+ if self.version is not None:
+ fastmcp_meta["version"] = self.version
+
+ # overwrite any existing fastmcp meta with keys from the new one
+ if upstream_meta := meta.get("fastmcp"):
+ fastmcp_meta = upstream_meta | fastmcp_meta
+ meta["fastmcp"] = fastmcp_meta
return meta or None
diff --git a/tests/server/middleware/test_tool_injection.py b/tests/server/middleware/test_tool_injection.py
index 863c575040..5a583f5435 100644
--- a/tests/server/middleware/test_tool_injection.py
+++ b/tests/server/middleware/test_tool_injection.py
@@ -333,7 +333,7 @@ async def test_list_prompts_tool_works(self, server_with_prompts: FastMCP):
[
TextContent(
type="text",
- text='[{"name":"greeting","title":null,"description":"Generate a greeting message.","arguments":[{"name":"name","description":null,"required":true}],"icons":null,"_meta":{"_fastmcp":{"tags":[]}}},{"name":"farewell","title":null,"description":"Generate a farewell message.","arguments":[{"name":"name","description":null,"required":true}],"icons":null,"_meta":{"_fastmcp":{"tags":[]}}}]',
+ text='[{"name":"greeting","title":null,"description":"Generate a greeting message.","arguments":[{"name":"name","description":null,"required":true}],"icons":null,"_meta":{"fastmcp":{"tags":[]}}},{"name":"farewell","title":null,"description":"Generate a farewell message.","arguments":[{"name":"name","description":null,"required":true}],"icons":null,"_meta":{"fastmcp":{"tags":[]}}}]',
)
]
)
@@ -348,7 +348,7 @@ async def test_list_prompts_tool_works(self, server_with_prompts: FastMCP):
{"name": "name", "description": None, "required": True}
],
"icons": None,
- "_meta": {"_fastmcp": {"tags": []}},
+ "_meta": {"fastmcp": {"tags": []}},
},
{
"name": "farewell",
@@ -358,7 +358,7 @@ async def test_list_prompts_tool_works(self, server_with_prompts: FastMCP):
{"name": "name", "description": None, "required": True}
],
"icons": None,
- "_meta": {"_fastmcp": {"tags": []}},
+ "_meta": {"fastmcp": {"tags": []}},
},
]
)
@@ -465,7 +465,7 @@ async def test_list_resources_tool_works(self, server_with_resources: FastMCP):
"size": None,
"icons": None,
"annotations": None,
- "_meta": {"_fastmcp": {"tags": []}},
+ "_meta": {"fastmcp": {"tags": []}},
},
{
"name": "data_resource",
@@ -476,7 +476,7 @@ async def test_list_resources_tool_works(self, server_with_resources: FastMCP):
"size": None,
"icons": None,
"annotations": None,
- "_meta": {"_fastmcp": {"tags": []}},
+ "_meta": {"fastmcp": {"tags": []}},
},
]
)
diff --git a/tests/server/providers/proxy/test_proxy_client.py b/tests/server/providers/proxy/test_proxy_client.py
index 8582a2257d..7b3bb19b96 100644
--- a/tests/server/providers/proxy/test_proxy_client.py
+++ b/tests/server/providers/proxy/test_proxy_client.py
@@ -99,7 +99,7 @@ async def test_forward_tool_meta(self, proxy_server: FastMCP):
async with Client(proxy_server) as client:
tools = await client.list_tools()
echo_tool = next(t for t in tools if t.name == "echo")
- assert echo_tool.meta == {"_fastmcp": {"tags": ["echo"]}}
+ assert echo_tool.meta == {"fastmcp": {"tags": ["echo"]}}
async def test_forward_error_response(self, proxy_server: FastMCP):
"""
diff --git a/tests/server/providers/proxy/test_proxy_server.py b/tests/server/providers/proxy/test_proxy_server.py
index 8c0ec2b7d1..ecad2062d3 100644
--- a/tests/server/providers/proxy/test_proxy_server.py
+++ b/tests/server/providers/proxy/test_proxy_server.py
@@ -234,7 +234,7 @@ async def test_get_tools_meta(self, proxy_server):
tools = await proxy_server.get_tools()
greet_tool = next(t for t in tools if t.name == "greet")
assert greet_tool.title == "Greet"
- assert greet_tool.meta == {"_fastmcp": {"tags": ["greet"]}}
+ assert greet_tool.meta == {"fastmcp": {"tags": ["greet"]}}
assert greet_tool.icons == [Icon(src="https://example.com/greet-icon.png")]
async def test_get_transformed_tools(self):
@@ -367,7 +367,7 @@ async def test_get_resources_meta(self, proxy_server):
resources = await proxy_server.get_resources()
wave_resource = next(r for r in resources if str(r.uri) == "resource://wave")
assert wave_resource.title == "Wave"
- assert wave_resource.meta == {"_fastmcp": {"tags": ["wave"]}}
+ assert wave_resource.meta == {"fastmcp": {"tags": ["wave"]}}
assert wave_resource.icons == [Icon(src="https://example.com/wave-icon.png")]
async def test_list_resources_same_as_original(self, fastmcp_server, proxy_server):
@@ -481,7 +481,7 @@ async def test_get_resource_templates_meta(self, proxy_server):
t for t in templates if t.uri_template == "data://user/{user_id}"
)
assert get_user_template.title == "User Template"
- assert get_user_template.meta == {"_fastmcp": {"tags": ["users"]}}
+ assert get_user_template.meta == {"fastmcp": {"tags": ["users"]}}
assert get_user_template.icons == [
Icon(src="https://example.com/user-icon.png")
]
@@ -589,7 +589,7 @@ async def test_get_prompts_meta(self, proxy_server):
prompts = await proxy_server.get_prompts()
welcome_prompt = next(p for p in prompts if p.name == "welcome")
assert welcome_prompt.title == "Welcome"
- assert welcome_prompt.meta == {"_fastmcp": {"tags": ["welcome"]}}
+ assert welcome_prompt.meta == {"fastmcp": {"tags": ["welcome"]}}
assert welcome_prompt.icons == [
Icon(src="https://example.com/welcome-icon.png")
]
diff --git a/tests/server/test_server.py b/tests/server/test_server.py
index e65f55d80e..a87c69a300 100644
--- a/tests/server/test_server.py
+++ b/tests/server/test_server.py
@@ -235,10 +235,10 @@ def greet(name: str) -> str:
class TestMeta:
- """Test that include_fastmcp_meta controls whether _fastmcp key is present in meta."""
+ """Test that fastmcp key is always present in meta."""
- async def test_tool_tags_in_meta_with_default_setting(self):
- """Test that tool tags appear in meta under _fastmcp key with default setting."""
+ async def test_tool_tags_in_meta(self):
+ """Test that tool tags appear in meta under fastmcp key."""
mcp = FastMCP()
@mcp.tool(tags={"tool-example", "test-tool-tag"})
@@ -250,13 +250,13 @@ def sample_tool(x: int) -> int:
tools = await client.list_tools()
tool = next(t for t in tools if t.name == "sample_tool")
assert tool.meta is not None
- assert set(tool.meta["_fastmcp"]["tags"]) == {
+ assert set(tool.meta["fastmcp"]["tags"]) == {
"tool-example",
"test-tool-tag",
}
- async def test_resource_tags_in_meta_with_default_setting(self):
- """Test that resource tags appear in meta under _fastmcp key with default setting."""
+ async def test_resource_tags_in_meta(self):
+ """Test that resource tags appear in meta under fastmcp key."""
mcp = FastMCP()
@mcp.resource(
@@ -270,13 +270,13 @@ def sample_resource() -> str:
resources = await client.list_resources()
resource = next(r for r in resources if str(r.uri) == "test://resource")
assert resource.meta is not None
- assert set(resource.meta["_fastmcp"]["tags"]) == {
+ assert set(resource.meta["fastmcp"]["tags"]) == {
"resource-example",
"test-resource-tag",
}
- async def test_resource_template_tags_in_meta_with_default_setting(self):
- """Test that resource template tags appear in meta under _fastmcp key with default setting."""
+ async def test_resource_template_tags_in_meta(self):
+ """Test that resource template tags appear in meta under fastmcp key."""
mcp = FastMCP()
@mcp.resource(
@@ -292,13 +292,13 @@ def sample_template(id: str) -> str:
t for t in templates if t.uriTemplate == "test://template/{id}"
)
assert template.meta is not None
- assert set(template.meta["_fastmcp"]["tags"]) == {
+ assert set(template.meta["fastmcp"]["tags"]) == {
"template-example",
"test-template-tag",
}
- async def test_prompt_tags_in_meta_with_default_setting(self):
- """Test that prompt tags appear in meta under _fastmcp key with default setting."""
+ async def test_prompt_tags_in_meta(self):
+ """Test that prompt tags appear in meta under fastmcp key."""
mcp = FastMCP()
@mcp.prompt(tags={"example", "test-tag"})
@@ -309,105 +309,7 @@ def sample_prompt() -> str:
prompts = await client.list_prompts()
prompt = next(p for p in prompts if p.name == "sample_prompt")
assert prompt.meta is not None
- assert set(prompt.meta["_fastmcp"]["tags"]) == {"example", "test-tag"}
-
- async def test_tool_meta_with_include_fastmcp_meta_false(self):
- mcp = FastMCP(include_fastmcp_meta=False)
-
- @mcp.tool(tags={"tool-example", "test-tool-tag"})
- def sample_tool(x: int) -> int:
- """A sample tool."""
- return x * 2
-
- async with Client(mcp) as client:
- tools = await client.list_tools()
- tool = next(t for t in tools if t.name == "sample_tool")
- # Meta should be None when include_fastmcp_meta is False
- assert tool.meta is None
-
- async def test_resource_meta_with_include_fastmcp_meta_false(self):
- mcp = FastMCP(include_fastmcp_meta=False)
-
- @mcp.resource(
- uri="test://resource", tags={"resource-example", "test-resource-tag"}
- )
- def sample_resource() -> str:
- """A sample resource."""
- return "resource content"
-
- async with Client(mcp) as client:
- resources = await client.list_resources()
- resource = next(r for r in resources if str(r.uri) == "test://resource")
- # Meta should be None when include_fastmcp_meta is False
- assert resource.meta is None
-
- async def test_resource_template_meta_with_include_fastmcp_meta_false(self):
- mcp = FastMCP(include_fastmcp_meta=False)
-
- @mcp.resource(
- "test://template/{id}", tags={"template-example", "test-template-tag"}
- )
- def sample_template(id: str) -> str:
- """A sample resource template."""
- return f"template content for {id}"
-
- async with Client(mcp) as client:
- templates = await client.list_resource_templates()
- template = next(
- t for t in templates if t.uriTemplate == "test://template/{id}"
- )
- # Meta should be None when include_fastmcp_meta is False
- assert template.meta is None
-
- async def test_prompt_meta_with_include_fastmcp_meta_false(self):
- mcp = FastMCP(include_fastmcp_meta=False)
-
- @mcp.prompt(tags={"example", "test-tag"})
- def sample_prompt() -> str:
- return "Hello, world!"
-
- async with Client(mcp) as client:
- prompts = await client.list_prompts()
- prompt = next(p for p in prompts if p.name == "sample_prompt")
- # Meta should be None when include_fastmcp_meta is False
- assert prompt.meta is None
-
- async def test_temporary_include_fastmcp_meta_setting(self):
- """Test that temporary_settings can toggle include_fastmcp_meta for new servers."""
-
- def make_server() -> FastMCP:
- mcp = FastMCP()
-
- @mcp.tool(tags={"test-tag"})
- def sample_tool(x: int) -> int:
- """A sample tool."""
- return x * 2
-
- return mcp
-
- # Default: meta should be present
- mcp = make_server()
- async with Client(mcp) as client:
- tools = await client.list_tools()
- tool = next(t for t in tools if t.name == "sample_tool")
- assert tool.meta is not None
- assert set(tool.meta["_fastmcp"]["tags"]) == {"test-tag"}
-
- # With setting disabled: new server should not include meta
- with temporary_settings(include_fastmcp_meta=False):
- mcp = make_server()
- async with Client(mcp) as client:
- tools = await client.list_tools()
- tool = next(t for t in tools if t.name == "sample_tool")
- assert tool.meta is None
-
- # After context: new server should have meta again
- mcp = make_server()
- async with Client(mcp) as client:
- tools = await client.list_tools()
- tool = next(t for t in tools if t.name == "sample_tool")
- assert tool.meta is not None
- assert set(tool.meta["_fastmcp"]["tags"]) == {"test-tag"}
+ assert set(prompt.meta["fastmcp"]["tags"]) == {"example", "test-tag"}
class TestShowServerBannerSetting:
diff --git a/tests/utilities/test_components.py b/tests/utilities/test_components.py
index fa01a7dd62..b64ee37d61 100644
--- a/tests/utilities/test_components.py
+++ b/tests/utilities/test_components.py
@@ -86,39 +86,50 @@ def test_key_property_without_custom_key(self, basic_component):
# Base component has no KEY_PREFIX, so key is just "name@version" (or "name@" for unversioned)
assert basic_component.key == "test_component@"
- def test_get_meta_without_fastmcp_meta(self, basic_component):
- """Test get_meta without including fastmcp meta."""
- basic_component.meta = {"custom": "data"}
- result = basic_component.get_meta(include_fastmcp_meta=False)
- assert result == {"custom": "data"}
- assert "_fastmcp" not in result
-
def test_get_meta_with_fastmcp_meta(self, basic_component):
- """Test get_meta including fastmcp meta."""
+ """Test get_meta always includes fastmcp meta."""
basic_component.meta = {"custom": "data"}
basic_component.tags = {"tag2", "tag1"} # Unordered to test sorting
- result = basic_component.get_meta(include_fastmcp_meta=True)
+ result = basic_component.get_meta()
assert result["custom"] == "data"
- assert "_fastmcp" in result
- assert result["_fastmcp"]["tags"] == ["tag1", "tag2"] # Should be sorted
+ assert "fastmcp" in result
+ assert result["fastmcp"]["tags"] == ["tag1", "tag2"] # Should be sorted
def test_get_meta_preserves_existing_fastmcp_meta(self):
- """Test that get_meta preserves existing _fastmcp meta."""
+ """Test that get_meta preserves existing fastmcp meta."""
component = FastMCPComponent(
name="test",
- meta={"_fastmcp": {"existing": "value"}},
+ meta={"fastmcp": {"existing": "value"}},
tags={"new_tag"},
)
- result = component.get_meta(include_fastmcp_meta=True)
+ result = component.get_meta()
assert result is not None
- assert result["_fastmcp"]["existing"] == "value"
- assert result["_fastmcp"]["tags"] == ["new_tag"]
+ assert result["fastmcp"]["existing"] == "value"
+ assert result["fastmcp"]["tags"] == ["new_tag"]
- def test_get_meta_returns_none_when_empty(self):
- """Test that get_meta returns None when no meta and fastmcp_meta is False."""
+ def test_get_meta_returns_dict_with_fastmcp_when_empty(self):
+ """Test that get_meta returns dict with fastmcp meta even when no custom meta."""
component = FastMCPComponent(name="test")
- result = component.get_meta(include_fastmcp_meta=False)
- assert result is None
+ result = component.get_meta()
+ assert result is not None
+ assert "fastmcp" in result
+ assert result["fastmcp"]["tags"] == []
+
+ def test_get_meta_includes_version(self):
+ """Test that get_meta includes version when component has a version."""
+ component = FastMCPComponent(name="test", version="v1.0.0", tags={"tag1"})
+ result = component.get_meta()
+ assert result is not None
+ assert result["fastmcp"]["version"] == "v1.0.0"
+ assert result["fastmcp"]["tags"] == ["tag1"]
+
+ def test_get_meta_excludes_version_when_none(self):
+ """Test that get_meta excludes version when component has no version."""
+ component = FastMCPComponent(name="test", tags={"tag1"})
+ result = component.get_meta()
+ assert result is not None
+ assert "version" not in result["fastmcp"]
+ assert result["fastmcp"]["tags"] == ["tag1"]
def test_equality_same_components(self):
"""Test that identical components are equal."""
@@ -289,10 +300,17 @@ def test_fastmcp_meta_structure(self):
meta: FastMCPMeta = {"tags": ["tag1", "tag2"]}
assert meta["tags"] == ["tag1", "tag2"]
+ def test_fastmcp_meta_with_version(self):
+ """Test that FastMCPMeta can include version."""
+ meta: FastMCPMeta = {"tags": ["tag1"], "version": "v1.0.0"}
+ assert meta["tags"] == ["tag1"]
+ assert meta["version"] == "v1.0.0"
+
def test_fastmcp_meta_optional_fields(self):
"""Test that FastMCPMeta fields are optional."""
meta: FastMCPMeta = {}
assert "tags" not in meta # Should be optional
+ assert "version" not in meta # Should be optional
class TestEdgeCasesAndIntegration:
@@ -312,7 +330,7 @@ def test_tags_with_none_values(self):
def test_meta_mutation_affects_original(self):
"""Test that get_meta returns a reference to the original meta."""
component = FastMCPComponent(name="test", meta={"key": "value"})
- meta = component.get_meta(include_fastmcp_meta=False)
+ meta = component.get_meta()
assert meta is not None
meta["key"] = "modified"
assert component.meta is not None
From d216ddf7fcf27acc7f00d61f17ee6dbf6addf148 Mon Sep 17 00:00:00 2001
From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
Date: Fri, 16 Jan 2026 21:20:23 -0500
Subject: [PATCH 2/5] Address review feedback
- Add get_fastmcp_metadata() helper with fallback to legacy _fastmcp namespace
- Update proxy.py to use helper for compatibility with older servers
- Update get_meta() return type to dict[str, Any] (always returns dict)
- Regenerate python-sdk API docs
---
docs/docs.json | 50 ++-
docs/python-sdk/fastmcp-cli-cli.mdx | 12 +-
docs/python-sdk/fastmcp-client-client.mdx | 88 +++---
docs/python-sdk/fastmcp-client-telemetry.mdx | 23 ++
docs/python-sdk/fastmcp-client-transports.mdx | 63 ++--
docs/python-sdk/fastmcp-decorators.mdx | 39 +++
docs/python-sdk/fastmcp-dependencies.mdx | 4 +
docs/python-sdk/fastmcp-exceptions.mdx | 6 +
docs/python-sdk/fastmcp-fs-__init__.mdx | 43 ---
docs/python-sdk/fastmcp-fs-decorators.mdx | 156 ----------
docs/python-sdk/fastmcp-fs-provider.mdx | 111 -------
docs/python-sdk/fastmcp-mcp_config.mdx | 32 +-
.../fastmcp-prompts-function_prompt.mdx | 106 +++++++
docs/python-sdk/fastmcp-prompts-prompt.mdx | 85 +-----
.../fastmcp-resources-function_resource.mdx | 93 ++++++
.../python-sdk/fastmcp-resources-resource.mdx | 75 ++---
.../python-sdk/fastmcp-resources-template.mdx | 52 ++--
.../fastmcp-server-auth-authorization.mdx | 139 +++++++++
...cp-server-auth-providers-introspection.mdx | 14 +-
docs/python-sdk/fastmcp-server-context.mdx | 143 ++++++---
.../fastmcp-server-dependencies.mdx | 259 ++++++++++++----
.../python-sdk/fastmcp-server-elicitation.mdx | 6 +-
docs/python-sdk/fastmcp-server-http.mdx | 18 +-
docs/python-sdk/fastmcp-server-low_level.mdx | 19 +-
...astmcp-server-middleware-authorization.mdx | 116 +++++++
.../fastmcp-server-middleware-ping.mdx | 32 ++
.../fastmcp-server-providers-aggregate.mdx | 139 +++++++++
.../fastmcp-server-providers-base.mdx | 135 ++++----
...tmcp-server-providers-fastmcp_provider.mdx | 118 ++++---
.../fastmcp-server-providers-filesystem.mdx | 128 ++++++++
...server-providers-filesystem_discovery.mdx} | 29 +-
...astmcp-server-providers-local_provider.mdx | 179 +++++------
...tmcp-server-providers-openapi-provider.mdx | 24 +-
.../fastmcp-server-providers-proxy.mdx | 88 ++++--
.../fastmcp-server-providers-transforming.mdx | 117 -------
docs/python-sdk/fastmcp-server-server.mdx | 287 ++++++++++--------
.../fastmcp-server-tasks-capabilities.mdx | 15 +-
.../fastmcp-server-tasks-config.mdx | 19 +-
.../fastmcp-server-tasks-requests.mdx | 10 +-
.../fastmcp-server-tasks-subscriptions.mdx | 4 +-
docs/python-sdk/fastmcp-server-telemetry.mdx | 56 ++++
.../fastmcp-server-transforms-__init__.mdx | 196 ++++++++++++
.../fastmcp-server-transforms-namespace.mdx | 96 ++++++
...stmcp-server-transforms-tool_transform.mdx | 40 +++
...stmcp-server-transforms-version_filter.mdx | 85 ++++++
.../fastmcp-server-transforms-visibility.mdx | 158 ++++++++++
docs/python-sdk/fastmcp-telemetry.mdx | 95 ++++++
.../fastmcp-tools-function_parsing.mdx | 21 ++
.../fastmcp-tools-function_tool.mdx | 108 +++++++
docs/python-sdk/fastmcp-tools-tool.mdx | 95 +-----
.../fastmcp-tools-tool_transform.mdx | 25 +-
.../fastmcp-utilities-async_utils.mdx | 15 +-
docs/python-sdk/fastmcp-utilities-cli.mdx | 6 +-
.../fastmcp-utilities-components.mdx | 59 +++-
.../fastmcp-utilities-json_schema_type.mdx | 4 +-
docs/python-sdk/fastmcp-utilities-logging.mdx | 2 +-
.../fastmcp-utilities-version_check.mdx | 40 +++
.../python-sdk/fastmcp-utilities-versions.mdx | 190 ++++++++++++
.../fastmcp-utilities-visibility.mdx | 86 ------
src/fastmcp/server/providers/proxy.py | 12 +-
src/fastmcp/utilities/components.py | 26 +-
61 files changed, 3067 insertions(+), 1424 deletions(-)
create mode 100644 docs/python-sdk/fastmcp-client-telemetry.mdx
create mode 100644 docs/python-sdk/fastmcp-decorators.mdx
delete mode 100644 docs/python-sdk/fastmcp-fs-__init__.mdx
delete mode 100644 docs/python-sdk/fastmcp-fs-decorators.mdx
delete mode 100644 docs/python-sdk/fastmcp-fs-provider.mdx
create mode 100644 docs/python-sdk/fastmcp-prompts-function_prompt.mdx
create mode 100644 docs/python-sdk/fastmcp-resources-function_resource.mdx
create mode 100644 docs/python-sdk/fastmcp-server-auth-authorization.mdx
create mode 100644 docs/python-sdk/fastmcp-server-middleware-authorization.mdx
create mode 100644 docs/python-sdk/fastmcp-server-middleware-ping.mdx
create mode 100644 docs/python-sdk/fastmcp-server-providers-aggregate.mdx
create mode 100644 docs/python-sdk/fastmcp-server-providers-filesystem.mdx
rename docs/python-sdk/{fastmcp-fs-discovery.mdx => fastmcp-server-providers-filesystem_discovery.mdx} (55%)
delete mode 100644 docs/python-sdk/fastmcp-server-providers-transforming.mdx
create mode 100644 docs/python-sdk/fastmcp-server-telemetry.mdx
create mode 100644 docs/python-sdk/fastmcp-server-transforms-__init__.mdx
create mode 100644 docs/python-sdk/fastmcp-server-transforms-namespace.mdx
create mode 100644 docs/python-sdk/fastmcp-server-transforms-tool_transform.mdx
create mode 100644 docs/python-sdk/fastmcp-server-transforms-version_filter.mdx
create mode 100644 docs/python-sdk/fastmcp-server-transforms-visibility.mdx
create mode 100644 docs/python-sdk/fastmcp-telemetry.mdx
create mode 100644 docs/python-sdk/fastmcp-tools-function_parsing.mdx
create mode 100644 docs/python-sdk/fastmcp-tools-function_tool.mdx
create mode 100644 docs/python-sdk/fastmcp-utilities-version_check.mdx
create mode 100644 docs/python-sdk/fastmcp-utilities-versions.mdx
delete mode 100644 docs/python-sdk/fastmcp-utilities-visibility.mdx
diff --git a/docs/docs.json b/docs/docs.json
index 5b1c59f23e..f6b0649d14 100644
--- a/docs/docs.json
+++ b/docs/docs.json
@@ -20,7 +20,10 @@
"primary": "#2d00f7"
},
"contextual": {
- "options": ["copy", "view"]
+ "options": [
+ "copy",
+ "view"
+ ]
},
"description": "The fast, Pythonic way to build MCP servers and clients.",
"errors": {
@@ -163,7 +166,10 @@
{
"group": "Essentials",
"icon": "cube",
- "pages": ["clients/client", "clients/transports"]
+ "pages": [
+ "clients/client",
+ "clients/transports"
+ ]
},
{
"group": "Core Operations",
@@ -190,7 +196,10 @@
{
"group": "Authentication",
"icon": "user-shield",
- "pages": ["clients/auth/oauth", "clients/auth/bearer"]
+ "pages": [
+ "clients/auth/oauth",
+ "clients/auth/bearer"
+ ]
}
]
},
@@ -200,7 +209,10 @@
{
"group": "Providers",
"icon": "globe",
- "pages": ["integrations/fastapi", "integrations/openapi"]
+ "pages": [
+ "integrations/fastapi",
+ "integrations/openapi"
+ ]
},
{
"group": "Authentication",
@@ -279,10 +291,12 @@
"anchor": "Python SDK",
"icon": "python",
"pages": [
+ "python-sdk/fastmcp-decorators",
"python-sdk/fastmcp-dependencies",
"python-sdk/fastmcp-exceptions",
"python-sdk/fastmcp-mcp_config",
"python-sdk/fastmcp-settings",
+ "python-sdk/fastmcp-telemetry",
{
"group": "fastmcp.cli",
"pages": [
@@ -338,6 +352,7 @@
]
},
"python-sdk/fastmcp-client-tasks",
+ "python-sdk/fastmcp-client-telemetry",
"python-sdk/fastmcp-client-transports"
]
},
@@ -345,6 +360,7 @@
"group": "fastmcp.prompts",
"pages": [
"python-sdk/fastmcp-prompts-__init__",
+ "python-sdk/fastmcp-prompts-function_prompt",
"python-sdk/fastmcp-prompts-prompt"
]
},
@@ -352,6 +368,7 @@
"group": "fastmcp.resources",
"pages": [
"python-sdk/fastmcp-resources-__init__",
+ "python-sdk/fastmcp-resources-function_resource",
"python-sdk/fastmcp-resources-resource",
"python-sdk/fastmcp-resources-template",
"python-sdk/fastmcp-resources-types"
@@ -366,6 +383,7 @@
"pages": [
"python-sdk/fastmcp-server-auth-__init__",
"python-sdk/fastmcp-server-auth-auth",
+ "python-sdk/fastmcp-server-auth-authorization",
"python-sdk/fastmcp-server-auth-jwt_issuer",
"python-sdk/fastmcp-server-auth-middleware",
"python-sdk/fastmcp-server-auth-oauth_proxy",
@@ -405,10 +423,12 @@
"group": "middleware",
"pages": [
"python-sdk/fastmcp-server-middleware-__init__",
+ "python-sdk/fastmcp-server-middleware-authorization",
"python-sdk/fastmcp-server-middleware-caching",
"python-sdk/fastmcp-server-middleware-error_handling",
"python-sdk/fastmcp-server-middleware-logging",
"python-sdk/fastmcp-server-middleware-middleware",
+ "python-sdk/fastmcp-server-middleware-ping",
"python-sdk/fastmcp-server-middleware-rate_limiting",
"python-sdk/fastmcp-server-middleware-timing",
"python-sdk/fastmcp-server-middleware-tool_injection"
@@ -427,8 +447,11 @@
"group": "providers",
"pages": [
"python-sdk/fastmcp-server-providers-__init__",
+ "python-sdk/fastmcp-server-providers-aggregate",
"python-sdk/fastmcp-server-providers-base",
"python-sdk/fastmcp-server-providers-fastmcp_provider",
+ "python-sdk/fastmcp-server-providers-filesystem",
+ "python-sdk/fastmcp-server-providers-filesystem_discovery",
"python-sdk/fastmcp-server-providers-local_provider",
{
"group": "openapi",
@@ -439,8 +462,7 @@
"python-sdk/fastmcp-server-providers-openapi-routing"
]
},
- "python-sdk/fastmcp-server-providers-proxy",
- "python-sdk/fastmcp-server-providers-transforming"
+ "python-sdk/fastmcp-server-providers-proxy"
]
},
"python-sdk/fastmcp-server-proxy",
@@ -465,6 +487,17 @@
"python-sdk/fastmcp-server-tasks-routing",
"python-sdk/fastmcp-server-tasks-subscriptions"
]
+ },
+ "python-sdk/fastmcp-server-telemetry",
+ {
+ "group": "transforms",
+ "pages": [
+ "python-sdk/fastmcp-server-transforms-__init__",
+ "python-sdk/fastmcp-server-transforms-namespace",
+ "python-sdk/fastmcp-server-transforms-tool_transform",
+ "python-sdk/fastmcp-server-transforms-version_filter",
+ "python-sdk/fastmcp-server-transforms-visibility"
+ ]
}
]
},
@@ -472,6 +505,8 @@
"group": "fastmcp.tools",
"pages": [
"python-sdk/fastmcp-tools-__init__",
+ "python-sdk/fastmcp-tools-function_parsing",
+ "python-sdk/fastmcp-tools-function_tool",
"python-sdk/fastmcp-tools-tool",
"python-sdk/fastmcp-tools-tool_transform"
]
@@ -535,7 +570,8 @@
"python-sdk/fastmcp-utilities-tests",
"python-sdk/fastmcp-utilities-types",
"python-sdk/fastmcp-utilities-ui",
- "python-sdk/fastmcp-utilities-visibility"
+ "python-sdk/fastmcp-utilities-version_check",
+ "python-sdk/fastmcp-utilities-versions"
]
}
]
diff --git a/docs/python-sdk/fastmcp-cli-cli.mdx b/docs/python-sdk/fastmcp-cli-cli.mdx
index cb0c4be1b4..759a4324d9 100644
--- a/docs/python-sdk/fastmcp-cli-cli.mdx
+++ b/docs/python-sdk/fastmcp-cli-cli.mdx
@@ -10,7 +10,7 @@ FastMCP CLI tools using Cyclopts.
## Functions
-### `with_argv`
+### `with_argv`
```python
with_argv(args: list[str] | None)
@@ -27,7 +27,7 @@ Args are provided without the script name, so we preserve sys.argv[0]
and replace the rest.
-### `version`
+### `version`
```python
version()
@@ -37,7 +37,7 @@ version()
Display version information and platform details.
-### `dev`
+### `dev`
```python
dev(server_spec: str | None = None) -> None
@@ -50,7 +50,7 @@ Run an MCP server with the MCP Inspector for development.
- `server_spec`: Python file to run, optionally with \:object suffix, or None to auto-detect fastmcp.json
-### `run`
+### `run`
```python
run(server_spec: str | None = None, *server_args: str) -> None
@@ -74,7 +74,7 @@ fastmcp run server.py -- --config config.json --debug
- `server_spec`: Python file, object specification (file\:obj), config file, URL, or None to auto-detect
-### `inspect`
+### `inspect`
```python
inspect(server_spec: str | None = None) -> None
@@ -105,7 +105,7 @@ fastmcp inspect # auto-detect fastmcp.json
- `server_spec`: Python file to inspect, optionally with \:object suffix, or fastmcp.json
-### `prepare`
+### `prepare`
```python
prepare(config_path: Annotated[str | None, cyclopts.Parameter(help='Path to fastmcp.json configuration file')] = None, output_dir: Annotated[str | None, cyclopts.Parameter(help='Directory to create the persistent environment in')] = None, skip_source: Annotated[bool, cyclopts.Parameter(help='Skip source preparation (e.g., git clone)')] = False) -> None
diff --git a/docs/python-sdk/fastmcp-client-client.mdx b/docs/python-sdk/fastmcp-client-client.mdx
index a638d3940a..9bdf9108a9 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.
-#### `list_resources_mcp`
+#### `list_resources_mcp`
```python
list_resources_mcp(self) -> mcp.types.ListResourcesResult
@@ -251,7 +251,7 @@ containing the list of resources and any additional metadata.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `list_resources`
+#### `list_resources`
```python
list_resources(self) -> list[mcp.types.Resource]
@@ -267,7 +267,7 @@ Retrieve a list of resources available on the server.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `list_resource_templates_mcp`
+#### `list_resource_templates_mcp`
```python
list_resource_templates_mcp(self) -> mcp.types.ListResourceTemplatesResult
@@ -284,7 +284,7 @@ containing the list of resource templates and any additional metadata.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `list_resource_templates`
+#### `list_resource_templates`
```python
list_resource_templates(self) -> list[mcp.types.ResourceTemplate]
@@ -300,7 +300,7 @@ Retrieve a list of resource templates available on the server.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `read_resource_mcp`
+#### `read_resource_mcp`
```python
read_resource_mcp(self, uri: AnyUrl | str, meta: dict[str, Any] | None = None) -> mcp.types.ReadResourceResult
@@ -321,19 +321,19 @@ containing the resource contents and any additional metadata.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `read_resource`
+#### `read_resource`
```python
read_resource(self, uri: AnyUrl | str) -> list[mcp.types.TextResourceContents | mcp.types.BlobResourceContents]
```
-#### `read_resource`
+#### `read_resource`
```python
read_resource(self, uri: AnyUrl | str) -> ResourceTask
```
-#### `read_resource`
+#### `read_resource`
```python
read_resource(self, uri: AnyUrl | str) -> list[mcp.types.TextResourceContents | mcp.types.BlobResourceContents] | ResourceTask
@@ -356,7 +356,7 @@ A list of content objects if task=False, or a ResourceTask object if task=True.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `list_prompts_mcp`
+#### `list_prompts_mcp`
```python
list_prompts_mcp(self) -> mcp.types.ListPromptsResult
@@ -373,7 +373,7 @@ containing the list of prompts and any additional metadata.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `list_prompts`
+#### `list_prompts`
```python
list_prompts(self) -> list[mcp.types.Prompt]
@@ -389,7 +389,7 @@ Retrieve a list of prompts available on the server.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `get_prompt_mcp`
+#### `get_prompt_mcp`
```python
get_prompt_mcp(self, name: str, arguments: dict[str, Any] | None = None, meta: dict[str, Any] | None = None) -> mcp.types.GetPromptResult
@@ -411,19 +411,19 @@ containing the prompt messages and any additional metadata.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `get_prompt`
+#### `get_prompt`
```python
get_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> mcp.types.GetPromptResult
```
-#### `get_prompt`
+#### `get_prompt`
```python
get_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> PromptTask
```
-#### `get_prompt`
+#### `get_prompt`
```python
get_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> mcp.types.GetPromptResult | PromptTask
@@ -447,7 +447,7 @@ or a PromptTask object if task=True.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `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
@@ -470,7 +470,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
@@ -492,7 +492,7 @@ include with the completion request. Defaults to None.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `list_tools_mcp`
+#### `list_tools_mcp`
```python
list_tools_mcp(self) -> mcp.types.ListToolsResult
@@ -509,7 +509,7 @@ containing the list of tools and any additional metadata.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `list_tools`
+#### `list_tools`
```python
list_tools(self) -> list[mcp.types.Tool]
@@ -525,7 +525,7 @@ Retrieve a list of tools available on the server.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `call_tool_mcp`
+#### `call_tool_mcp`
```python
call_tool_mcp(self, name: str, arguments: dict[str, Any], progress_handler: ProgressHandler | None = None, timeout: datetime.timedelta | float | int | None = None, meta: dict[str, Any] | None = None) -> mcp.types.CallToolResult
@@ -555,19 +555,19 @@ containing the tool result and any additional metadata.
- `McpError`: If the tool call requests results in a TimeoutError | JSONRPCError
-#### `call_tool`
+#### `call_tool`
```python
call_tool(self, name: str, arguments: dict[str, Any] | None = None) -> CallToolResult
```
-#### `call_tool`
+#### `call_tool`
```python
call_tool(self, name: str, arguments: dict[str, Any] | None = None) -> ToolTask
```
-#### `call_tool`
+#### `call_tool`
```python
call_tool(self, name: str, arguments: dict[str, Any] | None = None) -> CallToolResult | ToolTask
@@ -606,7 +606,7 @@ raw result object.
- `RuntimeError`: If called while the client is not connected.
-#### `get_task_status`
+#### `get_task_status`
```python
get_task_status(self, task_id: str) -> GetTaskResult
@@ -627,7 +627,7 @@ Sends a 'tasks/get' MCP protocol request over the existing transport.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `get_task_result`
+#### `get_task_result`
```python
get_task_result(self, task_id: str) -> Any
@@ -649,7 +649,7 @@ Returns the raw result - callers should parse it appropriately.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `list_tasks`
+#### `list_tasks`
```python
list_tasks(self, cursor: str | None = None, limit: int = 50) -> dict[str, Any]
@@ -675,7 +675,7 @@ querying status for locally tracked task IDs.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `cancel_task`
+#### `cancel_task`
```python
cancel_task(self, task_id: str) -> mcp.types.CancelTaskResult
@@ -697,7 +697,7 @@ and transition to cancelled state.
- `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-telemetry.mdx b/docs/python-sdk/fastmcp-client-telemetry.mdx
new file mode 100644
index 0000000000..42ec72e933
--- /dev/null
+++ b/docs/python-sdk/fastmcp-client-telemetry.mdx
@@ -0,0 +1,23 @@
+---
+title: telemetry
+sidebarTitle: telemetry
+---
+
+# `fastmcp.client.telemetry`
+
+
+Client-side telemetry helpers.
+
+## Functions
+
+### `client_span`
+
+```python
+client_span(name: str, method: str, component_key: str, session_id: str | None = None, resource_uri: str | None = None) -> Generator[Span, None, None]
+```
+
+
+Create a CLIENT span with standard MCP attributes.
+
+Automatically records any exception on the span and sets error status.
+
diff --git a/docs/python-sdk/fastmcp-client-transports.mdx b/docs/python-sdk/fastmcp-client-transports.mdx
index c9f748a322..bdf965c952 100644
--- a/docs/python-sdk/fastmcp-client-transports.mdx
+++ b/docs/python-sdk/fastmcp-client-transports.mdx
@@ -7,7 +7,7 @@ sidebarTitle: transports
## Functions
-### `infer_transport`
+### `infer_transport`
```python
infer_transport(transport: ClientTransport | FastMCP | FastMCP1Server | AnyUrl | Path | MCPConfig | dict[str, Any] | str) -> ClientTransport
@@ -57,13 +57,13 @@ transport = infer_transport(config)
## Classes
-### `SessionKwargs`
+### `SessionKwargs`
Keyword arguments for the MCP ClientSession constructor.
-### `ClientTransport`
+### `ClientTransport`
Abstract base class for different MCP client transport mechanisms.
@@ -74,7 +74,7 @@ to an MCP server, and providing a ClientSession within an async context.
**Methods:**
-#### `connect_session`
+#### `connect_session`
```python
connect_session(self, **session_kwargs: Unpack[SessionKwargs]) -> AsyncIterator[ClientSession]
@@ -93,7 +93,7 @@ within this context.
constructor (e.g., callbacks, timeouts).
-#### `close`
+#### `close`
```python
close(self)
@@ -102,7 +102,16 @@ close(self)
Close the transport.
-### `SSETransport`
+#### `get_session_id`
+
+```python
+get_session_id(self) -> str | None
+```
+
+Get the session ID for this transport, if available.
+
+
+### `SSETransport`
Transport implementation that connects to an MCP server via Server-Sent Events.
@@ -110,13 +119,13 @@ Transport implementation that connects to an MCP server via Server-Sent Events.
**Methods:**
-#### `connect_session`
+#### `connect_session`
```python
connect_session(self, **session_kwargs: Unpack[SessionKwargs]) -> AsyncIterator[ClientSession]
```
-### `StreamableHttpTransport`
+### `StreamableHttpTransport`
Transport implementation that connects to an MCP server via Streamable HTTP Requests.
@@ -124,25 +133,25 @@ Transport implementation that connects to an MCP server via Streamable HTTP Requ
**Methods:**
-#### `connect_session`
+#### `connect_session`
```python
connect_session(self, **session_kwargs: Unpack[SessionKwargs]) -> AsyncIterator[ClientSession]
```
-#### `get_session_id`
+#### `get_session_id`
```python
get_session_id(self) -> str | None
```
-#### `close`
+#### `close`
```python
close(self)
```
-### `StdioTransport`
+### `StdioTransport`
Base transport for connecting to an MCP server via subprocess with stdio.
@@ -153,67 +162,67 @@ transports like Python, Node, Uvx, etc.
**Methods:**
-#### `connect_session`
+#### `connect_session`
```python
connect_session(self, **session_kwargs: Unpack[SessionKwargs]) -> AsyncIterator[ClientSession]
```
-#### `connect`
+#### `connect`
```python
connect(self, **session_kwargs: Unpack[SessionKwargs]) -> ClientSession | None
```
-#### `disconnect`
+#### `disconnect`
```python
disconnect(self)
```
-#### `close`
+#### `close`
```python
close(self)
```
-### `PythonStdioTransport`
+### `PythonStdioTransport`
Transport for running Python scripts.
-### `FastMCPStdioTransport`
+### `FastMCPStdioTransport`
Transport for running FastMCP servers using the FastMCP CLI.
-### `NodeStdioTransport`
+### `NodeStdioTransport`
Transport for running Node.js scripts.
-### `UvStdioTransport`
+### `UvStdioTransport`
Transport for running commands via the uv tool.
-### `UvxStdioTransport`
+### `UvxStdioTransport`
Transport for running commands via the uvx tool.
-### `NpxStdioTransport`
+### `NpxStdioTransport`
Transport for running commands via the npx tool.
-### `FastMCPTransport`
+### `FastMCPTransport`
In-memory transport for FastMCP servers.
@@ -226,13 +235,13 @@ tests or scenarios where client and server run in the same runtime.
**Methods:**
-#### `connect_session`
+#### `connect_session`
```python
connect_session(self, **session_kwargs: Unpack[SessionKwargs]) -> AsyncIterator[ClientSession]
```
-### `MCPConfigTransport`
+### `MCPConfigTransport`
Transport for connecting to one or more MCP servers defined in an MCPConfig.
@@ -284,13 +293,13 @@ async with client:
**Methods:**
-#### `connect_session`
+#### `connect_session`
```python
connect_session(self, **session_kwargs: Unpack[SessionKwargs]) -> AsyncIterator[ClientSession]
```
-#### `close`
+#### `close`
```python
close(self)
diff --git a/docs/python-sdk/fastmcp-decorators.mdx b/docs/python-sdk/fastmcp-decorators.mdx
new file mode 100644
index 0000000000..b57712ad68
--- /dev/null
+++ b/docs/python-sdk/fastmcp-decorators.mdx
@@ -0,0 +1,39 @@
+---
+title: decorators
+sidebarTitle: decorators
+---
+
+# `fastmcp.decorators`
+
+
+Shared decorator utilities for FastMCP.
+
+## Functions
+
+### `resolve_task_config`
+
+```python
+resolve_task_config(task: bool | TaskConfig | None) -> bool | TaskConfig
+```
+
+
+Resolve task config, defaulting None to False.
+
+
+### `get_fastmcp_meta`
+
+```python
+get_fastmcp_meta(fn: Any) -> Any | None
+```
+
+
+Extract FastMCP metadata from a function, handling bound methods and wrappers.
+
+
+## Classes
+
+### `HasFastMCPMeta`
+
+
+Protocol for callables decorated with FastMCP metadata.
+
diff --git a/docs/python-sdk/fastmcp-dependencies.mdx b/docs/python-sdk/fastmcp-dependencies.mdx
index d53c370276..e803029c3f 100644
--- a/docs/python-sdk/fastmcp-dependencies.mdx
+++ b/docs/python-sdk/fastmcp-dependencies.mdx
@@ -12,3 +12,7 @@ This module re-exports dependency injection symbols from Docket and FastMCP
to provide a clean, centralized import location for all dependency-related
functionality.
+DI features (Depends, CurrentContext, CurrentFastMCP) work without pydocket
+using a vendored DI engine. Only task-related dependencies (CurrentDocket,
+CurrentWorker) and background task execution require fastmcp[tasks].
+
diff --git a/docs/python-sdk/fastmcp-exceptions.mdx b/docs/python-sdk/fastmcp-exceptions.mdx
index 26e62012ab..78d2e0110a 100644
--- a/docs/python-sdk/fastmcp-exceptions.mdx
+++ b/docs/python-sdk/fastmcp-exceptions.mdx
@@ -63,3 +63,9 @@ Object not found.
Object is disabled.
+
+### `AuthorizationError`
+
+
+Error when authorization check fails.
+
diff --git a/docs/python-sdk/fastmcp-fs-__init__.mdx b/docs/python-sdk/fastmcp-fs-__init__.mdx
deleted file mode 100644
index d49a61f5bc..0000000000
--- a/docs/python-sdk/fastmcp-fs-__init__.mdx
+++ /dev/null
@@ -1,43 +0,0 @@
----
-title: __init__
-sidebarTitle: __init__
----
-
-# `fastmcp.fs`
-
-
-Filesystem-based component discovery for FastMCP.
-
-This module provides decorators and a provider for discovering MCP components
-from the filesystem. Files are scanned for functions decorated with @tool,
-@resource, or @prompt, and automatically registered with the server.
-
-Example:
- ```python
- # server.py
- from fastmcp import FastMCP
- from fastmcp.fs import FileSystemProvider
-
- mcp = FastMCP("MyServer", providers=[FileSystemProvider("mcp/")])
- ```
-
- ```python
- # mcp/tools/greet.py
- from fastmcp.fs import tool
-
- @tool
- def greet(name: str) -> str:
- '''Greet someone by name.'''
- return f"Hello, {name}!"
- ```
-
- ```python
- # mcp/resources/config.py
- from fastmcp.fs import resource
-
- @resource("config://app")
- def get_config() -> dict:
- '''Get application configuration.'''
- return {"version": "1.0"}
- ```
-
diff --git a/docs/python-sdk/fastmcp-fs-decorators.mdx b/docs/python-sdk/fastmcp-fs-decorators.mdx
deleted file mode 100644
index 45ade09812..0000000000
--- a/docs/python-sdk/fastmcp-fs-decorators.mdx
+++ /dev/null
@@ -1,156 +0,0 @@
----
-title: decorators
-sidebarTitle: decorators
----
-
-# `fastmcp.fs.decorators`
-
-
-Decorators for marking functions in filesystem-based discovery.
-
-These decorators mark functions with metadata so that FileSystemProvider
-can discover and register them. Unlike LocalProvider's decorators, these
-do NOT register components immediately - they just store metadata on the
-function for later discovery.
-
-Example:
- ```python
- # mcp/tools/greet.py
- from fastmcp.fs import tool
-
- @tool
- def greet(name: str) -> str:
- '''Greet someone by name.'''
- return f"Hello, {name}!"
-
- @tool(name="custom-greet", tags={"greeting"})
- def my_greet(name: str) -> str:
- return f"Hi, {name}!"
- ```
-
-
-## Functions
-
-### `get_fs_meta`
-
-```python
-get_fs_meta(fn: Any) -> FSMeta | None
-```
-
-
-Get filesystem metadata from a function if it has been decorated.
-
-
-### `has_fs_meta`
-
-```python
-has_fs_meta(fn: Any) -> bool
-```
-
-
-Check if a function has filesystem metadata.
-
-
-### `tool`
-
-```python
-tool(fn: AnyFunction | str | None = None) -> Any
-```
-
-
-Mark a function as a tool for filesystem-based discovery.
-
-This decorator stores metadata on the function but does NOT register it.
-FileSystemProvider discovers marked functions when scanning directories.
-
-Supports multiple calling patterns:
-- @tool (without parentheses)
-- @tool() (with empty parentheses)
-- @tool("custom_name") (with name as first argument)
-- @tool(name="custom_name") (with keyword arguments)
-
-**Args:**
-- `fn`: The function to decorate, or a name string, or None
-- `name`: Optional name for the tool (defaults to function name)
-- `title`: Optional title for display
-- `description`: Optional description (defaults to docstring)
-- `icons`: Optional icons for the tool
-- `tags`: Optional tags for categorization
-- `output_schema`: Optional JSON schema for output
-- `annotations`: Optional tool annotations
-- `meta`: Optional metadata dict
-
-
-### `resource`
-
-```python
-resource(uri: str) -> Any
-```
-
-
-Mark a function as a resource for filesystem-based discovery.
-
-This decorator stores metadata on the function but does NOT register it.
-FileSystemProvider discovers marked functions when scanning directories.
-
-Unlike @tool and @prompt, @resource REQUIRES a URI argument.
-
-**Args:**
-- `uri`: URI for the resource (e.g., "config\://app" or "users\://{user_id}")
-- `name`: Optional name for the resource
-- `title`: Optional title for display
-- `description`: Optional description (defaults to docstring)
-- `icons`: Optional icons for the resource
-- `mime_type`: Optional MIME type
-- `tags`: Optional tags for categorization
-- `annotations`: Optional resource annotations
-- `meta`: Optional metadata dict
-
-
-### `prompt`
-
-```python
-prompt(fn: AnyFunction | str | None = None) -> Any
-```
-
-
-Mark a function as a prompt for filesystem-based discovery.
-
-This decorator stores metadata on the function but does NOT register it.
-FileSystemProvider discovers marked functions when scanning directories.
-
-Supports multiple calling patterns:
-- @prompt (without parentheses)
-- @prompt() (with empty parentheses)
-- @prompt("custom_name") (with name as first argument)
-- @prompt(name="custom_name") (with keyword arguments)
-
-**Args:**
-- `fn`: The function to decorate, or a name string, or None
-- `name`: Optional name for the prompt (defaults to function name)
-- `title`: Optional title for display
-- `description`: Optional description (defaults to docstring)
-- `icons`: Optional icons for the prompt
-- `tags`: Optional tags for categorization
-- `meta`: Optional metadata dict
-
-
-## Classes
-
-### `ToolMeta`
-
-
-Metadata stored on functions decorated with @tool.
-
-
-### `ResourceMeta`
-
-
-Metadata stored on functions decorated with @resource.
-
-
-### `PromptMeta`
-
-
-Metadata stored on functions decorated with @prompt.
-
diff --git a/docs/python-sdk/fastmcp-fs-provider.mdx b/docs/python-sdk/fastmcp-fs-provider.mdx
deleted file mode 100644
index 84bb30a4cb..0000000000
--- a/docs/python-sdk/fastmcp-fs-provider.mdx
+++ /dev/null
@@ -1,111 +0,0 @@
----
-title: provider
-sidebarTitle: provider
----
-
-# `fastmcp.fs.provider`
-
-
-FileSystemProvider for filesystem-based component discovery.
-
-FileSystemProvider scans a directory for Python files, imports them, and
-registers any functions decorated with @tool, @resource, or @prompt.
-
-Example:
- ```python
- from fastmcp import FastMCP
- from fastmcp.fs import FileSystemProvider
-
- mcp = FastMCP("MyServer", providers=[FileSystemProvider("mcp/")])
- ```
-
-
-## Classes
-
-### `FileSystemProvider`
-
-
-Provider that discovers components from the filesystem.
-
-Scans a directory for Python files and registers functions decorated
-with @tool, @resource, or @prompt from fastmcp.fs.
-
-**Args:**
-- `root`: Root directory to scan. Defaults to current directory.
-- `reload`: If True, re-scan files on every request (dev mode).
-Defaults to False (scan once at init, cache results).
-
-
-**Methods:**
-
-#### `list_tools`
-
-```python
-list_tools(self) -> Sequence[Tool]
-```
-
-Return all tools, reloading if in reload mode.
-
-
-#### `get_tool`
-
-```python
-get_tool(self, name: str) -> Tool | None
-```
-
-Get a tool by name, reloading if in reload mode.
-
-
-#### `list_resources`
-
-```python
-list_resources(self) -> Sequence[Resource]
-```
-
-Return all resources, reloading if in reload mode.
-
-
-#### `get_resource`
-
-```python
-get_resource(self, uri: str) -> Resource | None
-```
-
-Get a resource by URI, reloading if in reload mode.
-
-
-#### `list_resource_templates`
-
-```python
-list_resource_templates(self) -> Sequence[ResourceTemplate]
-```
-
-Return all resource templates, reloading if in reload mode.
-
-
-#### `get_resource_template`
-
-```python
-get_resource_template(self, uri: str) -> ResourceTemplate | None
-```
-
-Get a resource template, reloading if in reload mode.
-
-
-#### `list_prompts`
-
-```python
-list_prompts(self) -> Sequence[Prompt]
-```
-
-Return all prompts, reloading if in reload mode.
-
-
-#### `get_prompt`
-
-```python
-get_prompt(self, name: str) -> Prompt | None
-```
-
-Get a prompt by name, reloading if in reload mode.
-
diff --git a/docs/python-sdk/fastmcp-mcp_config.mdx b/docs/python-sdk/fastmcp-mcp_config.mdx
index 9b30dad856..87ed568a0e 100644
--- a/docs/python-sdk/fastmcp-mcp_config.mdx
+++ b/docs/python-sdk/fastmcp-mcp_config.mdx
@@ -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
```
-### `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
```
-### `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-prompts-function_prompt.mdx b/docs/python-sdk/fastmcp-prompts-function_prompt.mdx
new file mode 100644
index 0000000000..c8e48ef9cd
--- /dev/null
+++ b/docs/python-sdk/fastmcp-prompts-function_prompt.mdx
@@ -0,0 +1,106 @@
+---
+title: function_prompt
+sidebarTitle: function_prompt
+---
+
+# `fastmcp.prompts.function_prompt`
+
+
+Standalone @prompt decorator for FastMCP.
+
+## Functions
+
+### `prompt`
+
+```python
+prompt(name_or_fn: str | Callable[..., Any] | None = None) -> Any
+```
+
+
+Standalone decorator to mark a function as an MCP prompt.
+
+Returns the original function with metadata attached. Register with a server
+using mcp.add_prompt().
+
+
+## Classes
+
+### `DecoratedPrompt`
+
+
+Protocol for functions decorated with @prompt.
+
+
+### `PromptMeta`
+
+
+Metadata attached to functions by the @prompt decorator.
+
+
+### `FunctionPrompt`
+
+
+A prompt that is a function.
+
+
+**Methods:**
+
+#### `from_function`
+
+```python
+from_function(cls, fn: Callable[..., Any]) -> FunctionPrompt
+```
+
+Create a Prompt from a function.
+
+**Args:**
+- `fn`: The function to wrap
+- `metadata`: PromptMeta object with all configuration. If provided,
+individual parameters must not be passed.
+- `name, title, etc.`: Individual parameters for backwards compatibility.
+Cannot be used together with metadata parameter.
+
+The function can return:
+- str: wrapped as single user Message
+- list\[Message | str]: converted to list\[Message]
+- PromptResult: used directly
+
+
+#### `render`
+
+```python
+render(self, arguments: dict[str, Any] | None = None) -> PromptResult
+```
+
+Render the prompt with arguments.
+
+
+#### `register_with_docket`
+
+```python
+register_with_docket(self, docket: Docket) -> None
+```
+
+Register this prompt with docket for background execution.
+
+FunctionPrompt registers the underlying function, which has the user's
+Depends parameters for docket to resolve.
+
+
+#### `add_to_docket`
+
+```python
+add_to_docket(self, docket: Docket, arguments: dict[str, Any] | None, **kwargs: Any) -> Execution
+```
+
+Schedule this prompt for background execution via docket.
+
+FunctionPrompt splats the arguments dict since .fn expects **kwargs.
+
+**Args:**
+- `docket`: The Docket instance
+- `arguments`: Prompt arguments
+- `fn_key`: Function lookup key in Docket registry (defaults to self.key)
+- `task_key`: Redis storage key for the result
+- `**kwargs`: Additional kwargs passed to docket.add()
+
diff --git a/docs/python-sdk/fastmcp-prompts-prompt.mdx b/docs/python-sdk/fastmcp-prompts-prompt.mdx
index 8516742dd0..1541e9c580 100644
--- a/docs/python-sdk/fastmcp-prompts-prompt.mdx
+++ b/docs/python-sdk/fastmcp-prompts-prompt.mdx
@@ -10,7 +10,7 @@ Base classes for FastMCP prompts.
## Classes
-### `Message`
+### `Message`
Wrapper for prompt message with auto-serialization.
@@ -21,7 +21,7 @@ Accepts any content - strings pass through, other types
**Methods:**
-#### `to_mcp_prompt_message`
+#### `to_mcp_prompt_message`
```python
to_mcp_prompt_message(self) -> PromptMessage
@@ -30,13 +30,13 @@ to_mcp_prompt_message(self) -> PromptMessage
Convert to MCP PromptMessage.
-### `PromptArgument`
+### `PromptArgument`
An argument that can be passed to a prompt.
-### `PromptResult`
+### `PromptResult`
Canonical result type for prompt rendering.
@@ -47,7 +47,7 @@ roles, and metadata at both the message and result level.
**Methods:**
-#### `to_mcp_prompt_result`
+#### `to_mcp_prompt_result`
```python
to_mcp_prompt_result(self) -> GetPromptResult
@@ -56,7 +56,7 @@ to_mcp_prompt_result(self) -> GetPromptResult
Convert to MCP GetPromptResult.
-### `Prompt`
+### `Prompt`
A prompt template that can be rendered with parameters.
@@ -64,7 +64,7 @@ A prompt template that can be rendered with parameters.
**Methods:**
-#### `to_mcp_prompt`
+#### `to_mcp_prompt`
```python
to_mcp_prompt(self, **overrides: Any) -> SDKPrompt
@@ -73,10 +73,10 @@ to_mcp_prompt(self, **overrides: Any) -> SDKPrompt
Convert the prompt to an MCP prompt.
-#### `from_function`
+#### `from_function`
```python
-from_function(fn: Callable[..., Any], name: str | None = None, title: str | None = None, description: str | None = None, icons: list[Icon] | None = None, tags: set[str] | None = None, meta: dict[str, Any] | None = None, task: bool | TaskConfig | None = None) -> FunctionPrompt
+from_function(cls, fn: Callable[..., Any]) -> FunctionPrompt
```
Create a Prompt from a function.
@@ -87,7 +87,7 @@ The function can return:
- PromptResult: used directly
-#### `render`
+#### `render`
```python
render(self, arguments: dict[str, Any] | None = None) -> str | list[Message | str] | PromptResult
@@ -101,7 +101,7 @@ Subclasses must implement this method. Return one of:
- PromptResult: Used directly
-#### `convert_result`
+#### `convert_result`
```python
convert_result(self, raw_value: Any) -> PromptResult
@@ -113,7 +113,7 @@ Convert a raw return value to PromptResult.
- `TypeError`: for unsupported types
-#### `register_with_docket`
+#### `register_with_docket`
```python
register_with_docket(self, docket: Docket) -> None
@@ -122,7 +122,7 @@ register_with_docket(self, docket: Docket) -> None
Register this prompt with docket for background execution.
-#### `add_to_docket`
+#### `add_to_docket`
```python
add_to_docket(self, docket: Docket, arguments: dict[str, Any] | None, **kwargs: Any) -> Execution
@@ -138,63 +138,8 @@ Schedule this prompt for background execution via docket.
- `**kwargs`: Additional kwargs passed to docket.add()
-### `FunctionPrompt`
-
-
-A prompt that is a function.
-
-
-**Methods:**
-
-#### `from_function`
-
-```python
-from_function(cls, fn: Callable[..., Any], name: str | None = None, title: str | None = None, description: str | None = None, icons: list[Icon] | None = None, tags: set[str] | None = None, meta: dict[str, Any] | None = None, task: bool | TaskConfig | None = None) -> FunctionPrompt
-```
-
-Create a Prompt from a function.
-
-The function can return:
-- str: wrapped as single user Message
-- list\[Message | str]: converted to list\[Message]
-- PromptResult: used directly
-
-
-#### `render`
-
-```python
-render(self, arguments: dict[str, Any] | None = None) -> PromptResult
-```
-
-Render the prompt with arguments.
-
-
-#### `register_with_docket`
-
-```python
-register_with_docket(self, docket: Docket) -> None
-```
-
-Register this prompt with docket for background execution.
-
-FunctionPrompt registers the underlying function, which has the user's
-Depends parameters for docket to resolve.
-
-
-#### `add_to_docket`
+#### `get_span_attributes`
```python
-add_to_docket(self, docket: Docket, arguments: dict[str, Any] | None, **kwargs: Any) -> Execution
+get_span_attributes(self) -> dict[str, Any]
```
-
-Schedule this prompt for background execution via docket.
-
-FunctionPrompt splats the arguments dict since .fn expects **kwargs.
-
-**Args:**
-- `docket`: The Docket instance
-- `arguments`: Prompt arguments
-- `fn_key`: Function lookup key in Docket registry (defaults to self.key)
-- `task_key`: Redis storage key for the result
-- `**kwargs`: Additional kwargs passed to docket.add()
-
diff --git a/docs/python-sdk/fastmcp-resources-function_resource.mdx b/docs/python-sdk/fastmcp-resources-function_resource.mdx
new file mode 100644
index 0000000000..ad184b53c8
--- /dev/null
+++ b/docs/python-sdk/fastmcp-resources-function_resource.mdx
@@ -0,0 +1,93 @@
+---
+title: function_resource
+sidebarTitle: function_resource
+---
+
+# `fastmcp.resources.function_resource`
+
+
+Standalone @resource decorator for FastMCP.
+
+## Functions
+
+### `resource`
+
+```python
+resource(uri: str) -> Callable[[F], F]
+```
+
+
+Standalone decorator to mark a function as an MCP resource.
+
+Returns the original function with metadata attached. Register with a server
+using mcp.add_resource().
+
+
+## Classes
+
+### `DecoratedResource`
+
+
+Protocol for functions decorated with @resource.
+
+
+### `ResourceMeta`
+
+
+Metadata attached to functions by the @resource decorator.
+
+
+### `FunctionResource`
+
+
+A resource that defers data loading by wrapping a function.
+
+The function is only called when the resource is read, allowing for lazy loading
+of potentially expensive data. This is particularly useful when listing resources,
+as the function won't be called until the resource is actually accessed.
+
+The function can return:
+- str for text content (default)
+- bytes for binary content
+- other types will be converted to JSON
+
+
+**Methods:**
+
+#### `from_function`
+
+```python
+from_function(cls, fn: Callable[..., Any], uri: str | AnyUrl | None = None) -> FunctionResource
+```
+
+Create a FunctionResource from a function.
+
+**Args:**
+- `fn`: The function to wrap
+- `uri`: The URI for the resource (required if metadata not provided)
+- `metadata`: ResourceMeta object with all configuration. If provided,
+individual parameters must not be passed.
+- `name, title, etc.`: Individual parameters for backwards compatibility.
+Cannot be used together with metadata parameter.
+
+
+#### `read`
+
+```python
+read(self) -> str | bytes | ResourceResult
+```
+
+Read the resource by calling the wrapped function.
+
+
+#### `register_with_docket`
+
+```python
+register_with_docket(self, docket: Docket) -> None
+```
+
+Register this resource with docket for background execution.
+
+FunctionResource registers the underlying function, which has the user's
+Depends parameters for docket to resolve.
+
diff --git a/docs/python-sdk/fastmcp-resources-resource.mdx b/docs/python-sdk/fastmcp-resources-resource.mdx
index bbd17a04fa..b064ac47b3 100644
--- a/docs/python-sdk/fastmcp-resources-resource.mdx
+++ b/docs/python-sdk/fastmcp-resources-resource.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(fn: Callable[..., Any], uri: str | AnyUrl, name: str | 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) -> FunctionResource
+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
@@ -124,7 +124,7 @@ Handles ResourceResult passthrough and converts raw values using
ResourceResult's normalization.
-#### `to_mcp_resource`
+#### `to_mcp_resource`
```python
to_mcp_resource(self, **overrides: Any) -> SDKResource
@@ -133,7 +133,7 @@ to_mcp_resource(self, **overrides: Any) -> SDKResource
Convert the resource to an SDKResource.
-#### `key`
+#### `key`
```python
key(self) -> str
@@ -142,7 +142,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
@@ -151,7 +151,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
@@ -166,49 +166,8 @@ Schedule this resource for background execution via docket.
- `**kwargs`: Additional kwargs passed to docket.add()
-### `FunctionResource`
-
-
-A resource that defers data loading by wrapping a function.
-
-The function is only called when the resource is read, allowing for lazy loading
-of potentially expensive data. This is particularly useful when listing resources,
-as the function won't be called until the resource is actually accessed.
-
-The function can return:
-- str for text content (default)
-- bytes for binary content
-- other types will be converted to JSON
-
-
-**Methods:**
-
-#### `from_function`
-
-```python
-from_function(cls, fn: Callable[..., Any], uri: str | AnyUrl, name: str | 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) -> FunctionResource
-```
-
-Create a FunctionResource from a function.
-
-
-#### `read`
+#### `get_span_attributes`
```python
-read(self) -> str | bytes | ResourceResult
+get_span_attributes(self) -> dict[str, Any]
```
-
-Read the resource by calling the wrapped function.
-
-
-#### `register_with_docket`
-
-```python
-register_with_docket(self, docket: Docket) -> None
-```
-
-Register this resource with docket for background execution.
-
-FunctionResource registers the underlying function, which has the user's
-Depends parameters for docket to resolve.
-
diff --git a/docs/python-sdk/fastmcp-resources-template.mdx b/docs/python-sdk/fastmcp-resources-template.mdx
index e93d9f4be4..e1b932d889 100644
--- a/docs/python-sdk/fastmcp-resources-template.mdx
+++ b/docs/python-sdk/fastmcp-resources-template.mdx
@@ -10,7 +10,7 @@ Resource template functionality.
## Functions
-### `extract_query_params`
+### `extract_query_params`
```python
extract_query_params(uri_template: str) -> set[str]
@@ -20,7 +20,7 @@ extract_query_params(uri_template: str) -> set[str]
Extract query parameter names from RFC 6570 `{?param1,param2}` syntax.
-### `build_regex`
+### `build_regex`
```python
build_regex(template: str) -> re.Pattern
@@ -35,7 +35,7 @@ Supports:
- `{?var1,var2}` - query parameters (ignored in path matching)
-### `match_uri_template`
+### `match_uri_template`
```python
match_uri_template(uri: str, uri_template: str) -> dict[str, str] | None
@@ -51,7 +51,7 @@ Supports RFC 6570 URI templates:
## Classes
-### `ResourceTemplate`
+### `ResourceTemplate`
A template for dynamically creating resources.
@@ -59,13 +59,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, 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) -> FunctionResourceTemplate
+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: AuthCheckCallable | list[AuthCheckCallable] | None = None) -> FunctionResourceTemplate
```
-#### `set_default_mime_type`
+#### `set_default_mime_type`
```python
set_default_mime_type(cls, mime_type: str | None) -> str
@@ -74,7 +74,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
@@ -83,7 +83,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
@@ -92,7 +92,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
@@ -108,7 +108,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
@@ -120,7 +120,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
@@ -129,7 +129,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
@@ -138,7 +138,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
@@ -147,7 +147,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
@@ -156,7 +156,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
@@ -172,7 +172,13 @@ Schedule this template for background execution via docket.
- `**kwargs`: Additional kwargs passed to docket.add()
-### `FunctionResourceTemplate`
+#### `get_span_attributes`
+
+```python
+get_span_attributes(self) -> dict[str, Any]
+```
+
+### `FunctionResourceTemplate`
A template for dynamically creating resources.
@@ -180,7 +186,7 @@ A template for dynamically creating resources.
**Methods:**
-#### `create_resource`
+#### `create_resource`
```python
create_resource(self, uri: str, params: dict[str, Any]) -> Resource
@@ -189,7 +195,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
@@ -198,7 +204,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
@@ -210,7 +216,7 @@ FunctionResourceTemplate registers the underlying function, which has the
user's Depends parameters for docket to resolve.
-#### `add_to_docket`
+#### `add_to_docket`
```python
add_to_docket(self, docket: Docket, params: dict[str, Any], **kwargs: Any) -> Execution
@@ -228,10 +234,10 @@ 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, 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) -> FunctionResourceTemplate
+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: AuthCheckCallable | list[AuthCheckCallable] | None = None) -> FunctionResourceTemplate
```
Create a template from a function.
diff --git a/docs/python-sdk/fastmcp-server-auth-authorization.mdx b/docs/python-sdk/fastmcp-server-auth-authorization.mdx
new file mode 100644
index 0000000000..d8e0611a95
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-auth-authorization.mdx
@@ -0,0 +1,139 @@
+---
+title: authorization
+sidebarTitle: authorization
+---
+
+# `fastmcp.server.auth.authorization`
+
+
+Authorization checks for FastMCP components.
+
+This module provides callable-based authorization for tools, resources, and prompts.
+Auth checks are functions that receive an AuthContext and return True to allow access
+or False to deny.
+
+Auth checks can also raise exceptions:
+- AuthorizationError: Propagates with the custom message for explicit denial
+- Other exceptions: Masked for security (logged, treated as auth failure)
+
+Example:
+ ```python
+ from fastmcp import FastMCP
+ from fastmcp.server.auth import require_auth, require_scopes
+
+ mcp = FastMCP()
+
+ @mcp.tool(auth=require_auth)
+ def protected_tool(): ...
+
+ @mcp.resource("data://secret", auth=require_scopes("read"))
+ def secret_data(): ...
+
+ @mcp.prompt(auth=require_auth)
+ def admin_prompt(): ...
+ ```
+
+
+## Functions
+
+### `require_auth`
+
+```python
+require_auth(ctx: AuthContext) -> bool
+```
+
+
+Require any valid authentication.
+
+Returns True if the request has a valid token, False otherwise.
+
+
+### `require_scopes`
+
+```python
+require_scopes(*scopes: str) -> AuthCheck
+```
+
+
+Require specific OAuth scopes.
+
+Returns an auth check that requires ALL specified scopes to be present
+in the token (AND logic).
+
+**Args:**
+- `*scopes`: One or more scope strings that must all be present.
+
+
+### `restrict_tag`
+
+```python
+restrict_tag(tag: str) -> AuthCheck
+```
+
+
+Restrict components with a specific tag to require certain scopes.
+
+If the component has the specified tag, the token must have ALL the
+required scopes. If the component doesn't have the tag, access is allowed.
+
+**Args:**
+- `tag`: The tag that triggers the scope requirement.
+- `scopes`: List of scopes required when the tag is present.
+
+
+### `run_auth_checks`
+
+```python
+run_auth_checks(checks: AuthCheck | list[AuthCheck], ctx: AuthContext) -> bool
+```
+
+
+Run auth checks with AND logic.
+
+All checks must pass for authorization to succeed.
+
+Auth checks can:
+- Return True to allow access
+- Return False to deny access
+- Raise AuthorizationError to deny with a custom message (propagates)
+- Raise other exceptions (masked for security, treated as denial)
+
+**Args:**
+- `checks`: A single check function or list of check functions.
+- `ctx`: The auth context to pass to each check.
+
+**Returns:**
+- True if all checks pass, False if any check fails.
+
+**Raises:**
+- `AuthorizationError`: If an auth check explicitly raises it.
+
+
+## Classes
+
+### `AuthContext`
+
+
+Context passed to auth check callables.
+
+This object is passed to each auth check function and provides
+access to the current authentication token and the component being accessed.
+
+**Attributes:**
+- `token`: The current access token, or None if unauthenticated.
+- `component`: The component (tool, resource, or prompt) being accessed.
+- `tool`: Backwards-compatible alias for component when it's a Tool.
+
+
+**Methods:**
+
+#### `tool`
+
+```python
+tool(self) -> Tool | None
+```
+
+Backwards-compatible access to the component as a Tool.
+
+Returns the component if it's a Tool, None otherwise.
+
diff --git a/docs/python-sdk/fastmcp-server-auth-providers-introspection.mdx b/docs/python-sdk/fastmcp-server-auth-providers-introspection.mdx
index 2a0d2e22d9..32943d6b21 100644
--- a/docs/python-sdk/fastmcp-server-auth-providers-introspection.mdx
+++ b/docs/python-sdk/fastmcp-server-auth-providers-introspection.mdx
@@ -31,7 +31,7 @@ Example:
## Classes
-### `IntrospectionTokenVerifier`
+### `IntrospectionTokenVerifier`
OAuth 2.0 Token Introspection verifier (RFC 7662).
@@ -40,8 +40,11 @@ This verifier validates opaque tokens by calling an OAuth 2.0 token introspectio
endpoint. Unlike JWT verification which is stateless, token introspection requires
a network call to the authorization server for each token validation.
-The verifier authenticates to the introspection endpoint using HTTP Basic Auth
-with the provided client_id and client_secret, as specified in RFC 7662.
+The verifier authenticates to the introspection endpoint using either:
+- HTTP Basic Auth (client_secret_basic, default): credentials in Authorization header
+- POST body authentication (client_secret_post): credentials in request body
+
+Both methods are specified in RFC 6749 (OAuth 2.0) and RFC 7662 (Token Introspection).
Use this when:
- Your authorization server issues opaque (non-JWT) tokens
@@ -52,7 +55,7 @@ Use this when:
**Methods:**
-#### `verify_token`
+#### `verify_token`
```python
verify_token(self, token: str) -> AccessToken | None
@@ -61,7 +64,8 @@ verify_token(self, token: str) -> AccessToken | None
Verify a bearer token using OAuth 2.0 Token Introspection (RFC 7662).
This method makes a POST request to the introspection endpoint with the token,
-authenticated using HTTP Basic Auth with the client credentials.
+authenticated using the configured client authentication method (client_secret_basic
+or client_secret_post).
**Args:**
- `token`: The opaque token string to validate
diff --git a/docs/python-sdk/fastmcp-server-context.mdx b/docs/python-sdk/fastmcp-server-context.mdx
index 91e4c1195c..822efb8c6a 100644
--- a/docs/python-sdk/fastmcp-server-context.mdx
+++ b/docs/python-sdk/fastmcp-server-context.mdx
@@ -7,7 +7,27 @@ sidebarTitle: context
## Functions
-### `set_context`
+### `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]
@@ -15,7 +35,7 @@ set_context(context: Context) -> Generator[Context, None, None]
## Classes
-### `LogData`
+### `LogData`
Data object for passing log arguments to client-side handlers.
@@ -24,7 +44,7 @@ This provides an interface to match the Python standard library logging,
for compatibility with structured logging.
-### `Context`
+### `Context`
Context object providing access to MCP capabilities.
@@ -53,18 +73,22 @@ async def my_tool(x: int, ctx: Context) -> str:
request_id = ctx.request_id
client_id = ctx.client_id
- # Manage state across the request
- ctx.set_state("key", "value")
- value = ctx.get_state("key")
+ # Manage state across the session (persists across requests)
+ await ctx.set_state("key", "value")
+ value = await ctx.get_state("key")
return str(x)
```
State Management:
-Context objects maintain a state dictionary that can be used to store and share
-data across middleware and tool calls within a request. When a new context
-is created (nested contexts), it inherits a copy of its parent's state, ensuring
-that modifications in child contexts don't affect parent contexts.
+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.
@@ -72,7 +96,7 @@ The context is optional - tools that don't need it can omit the parameter.
**Methods:**
-#### `fastmcp`
+#### `fastmcp`
```python
fastmcp(self) -> FastMCP
@@ -81,7 +105,7 @@ fastmcp(self) -> FastMCP
Get the FastMCP instance.
-#### `request_context`
+#### `request_context`
```python
request_context(self) -> RequestContext[ServerSession, Any, Request] | None
@@ -110,7 +134,7 @@ async def on_request(self, context, call_next):
```
-#### `lifespan_context`
+#### `lifespan_context`
```python
lifespan_context(self) -> dict[str, Any]
@@ -133,7 +157,7 @@ def my_tool(ctx: Context) -> str:
```
-#### `report_progress`
+#### `report_progress`
```python
report_progress(self, progress: float, total: float | None = None, message: str | None = None) -> None
@@ -146,7 +170,7 @@ Report progress for the current operation.
- `total`: Optional total value e.g. 100
-#### `list_resources`
+#### `list_resources`
```python
list_resources(self) -> list[SDKResource]
@@ -158,7 +182,7 @@ List all available resources from the server.
- List of Resource objects available on the server
-#### `list_prompts`
+#### `list_prompts`
```python
list_prompts(self) -> list[SDKPrompt]
@@ -170,7 +194,7 @@ List all available prompts from the server.
- List of Prompt objects available on the server
-#### `get_prompt`
+#### `get_prompt`
```python
get_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> GetPromptResult
@@ -186,7 +210,7 @@ Get a prompt by name with optional arguments.
- The prompt result
-#### `read_resource`
+#### `read_resource`
```python
read_resource(self, uri: str | AnyUrl) -> ResourceResult
@@ -201,7 +225,7 @@ Read a resource by URI.
- ResourceResult with contents
-#### `log`
+#### `log`
```python
log(self, message: str, level: LoggingLevel | None = None, logger_name: str | None = None, extra: Mapping[str, Any] | None = None) -> None
@@ -219,7 +243,19 @@ Messages sent to Clients are also logged to the `fastmcp.server.context.to_clien
- `extra`: Optional mapping for additional arguments
-#### `client_id`
+#### `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_id`
```python
client_id(self) -> str | None
@@ -228,7 +264,7 @@ client_id(self) -> str | None
Get the client ID if available.
-#### `request_id`
+#### `request_id`
```python
request_id(self) -> str
@@ -239,7 +275,7 @@ Get the unique ID for this request.
Raises RuntimeError if MCP request context is not available.
-#### `session_id`
+#### `session_id`
```python
session_id(self) -> str
@@ -256,7 +292,7 @@ the same client session.
- for other transports.
-#### `session`
+#### `session`
```python
session(self) -> ServerSession
@@ -267,7 +303,7 @@ Access to the underlying session for advanced usage.
Raises RuntimeError if MCP request context is not available.
-#### `debug`
+#### `debug`
```python
debug(self, message: str, logger_name: str | None = None, extra: Mapping[str, Any] | None = None) -> None
@@ -278,7 +314,7 @@ 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`
+#### `info`
```python
info(self, message: str, logger_name: str | None = None, extra: Mapping[str, Any] | None = None) -> None
@@ -289,7 +325,7 @@ 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`
+#### `warning`
```python
warning(self, message: str, logger_name: str | None = None, extra: Mapping[str, Any] | None = None) -> None
@@ -300,7 +336,7 @@ 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`
+#### `error`
```python
error(self, message: str, logger_name: str | None = None, extra: Mapping[str, Any] | None = None) -> None
@@ -311,7 +347,7 @@ 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`.
-#### `list_roots`
+#### `list_roots`
```python
list_roots(self) -> list[Root]
@@ -320,7 +356,7 @@ list_roots(self) -> list[Root]
List the roots available to the server, as indicated by the client.
-#### `send_notification`
+#### `send_notification`
```python
send_notification(self, notification: mcp.types.ServerNotificationType) -> None
@@ -336,7 +372,7 @@ for the background flusher.
- `notification`: An MCP notification instance (e.g., ToolListChangedNotification())
-#### `send_notification_sync`
+#### `send_notification_sync`
```python
send_notification_sync(self, notification: mcp.types.ServerNotificationType) -> None
@@ -351,7 +387,7 @@ sent within ~1 second by the background flusher.
- `notification`: An MCP notification instance (e.g., ToolListChangedNotification())
-#### `close_sse_stream`
+#### `close_sse_stream`
```python
close_sse_stream(self) -> None
@@ -369,7 +405,7 @@ Instead of holding a connection open for minutes, you can periodically close
and let the client reconnect.
-#### `sample_step`
+#### `sample_step`
```python
sample_step(self, messages: str | Sequence[str | SamplingMessage]) -> SampleStep
@@ -406,7 +442,7 @@ Tools can raise ToolError to bypass masking.
- - .text: The text content (if any)
-#### `sample`
+#### `sample`
```python
sample(self, messages: str | Sequence[str | SamplingMessage]) -> SamplingResult[ResultT]
@@ -415,7 +451,7 @@ sample(self, messages: str | Sequence[str | SamplingMessage]) -> SamplingResult[
Overload: With result_type, returns SamplingResult[ResultT].
-#### `sample`
+#### `sample`
```python
sample(self, messages: str | Sequence[str | SamplingMessage]) -> SamplingResult[str]
@@ -424,7 +460,7 @@ sample(self, messages: str | Sequence[str | SamplingMessage]) -> SamplingResult[
Overload: Without result_type, returns SamplingResult[str].
-#### `sample`
+#### `sample`
```python
sample(self, messages: str | Sequence[str | SamplingMessage]) -> SamplingResult[ResultT] | SamplingResult[str]
@@ -466,43 +502,43 @@ Tools can raise ToolError to bypass masking.
- - .history: All messages exchanged during sampling
-#### `elicit`
+#### `elicit`
```python
elicit(self, message: str, response_type: None) -> AcceptedElicitation[dict[str, Any]] | DeclinedElicitation | CancelledElicitation
```
-#### `elicit`
+#### `elicit`
```python
elicit(self, message: str, response_type: type[T]) -> AcceptedElicitation[T] | DeclinedElicitation | CancelledElicitation
```
-#### `elicit`
+#### `elicit`
```python
elicit(self, message: str, response_type: list[str]) -> AcceptedElicitation[str] | DeclinedElicitation | CancelledElicitation
```
-#### `elicit`
+#### `elicit`
```python
elicit(self, message: str, response_type: dict[str, dict[str, str]]) -> AcceptedElicitation[str] | DeclinedElicitation | CancelledElicitation
```
-#### `elicit`
+#### `elicit`
```python
elicit(self, message: str, response_type: list[list[str]]) -> AcceptedElicitation[list[str]] | DeclinedElicitation | CancelledElicitation
```
-#### `elicit`
+#### `elicit`
```python
elicit(self, message: str, response_type: list[dict[str, dict[str, str]]]) -> AcceptedElicitation[list[str]] | DeclinedElicitation | CancelledElicitation
```
-#### `elicit`
+#### `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]]] | None = None) -> AcceptedElicitation[T] | AcceptedElicitation[dict[str, Any]] | AcceptedElicitation[str] | AcceptedElicitation[list[str]] | DeclinedElicitation | CancelledElicitation
@@ -531,20 +567,35 @@ type or dataclass or BaseModel. If it is a primitive type, an
object schema with a single "value" field will be generated.
-#### `set_state`
+#### `set_state`
```python
set_state(self, key: str, value: Any) -> None
```
-Set a value in the context state.
+Set a value in the session-scoped state store.
+
+Values persist across requests within the same MCP session.
+The key is automatically prefixed with the session identifier.
+State expires after 1 day to prevent unbounded memory growth.
-#### `get_state`
+#### `get_state`
```python
get_state(self, key: str) -> Any
```
-Get a value from the context state. Returns None if the key is not found.
+Get a value from 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 session-scoped state store.
diff --git a/docs/python-sdk/fastmcp-server-dependencies.mdx b/docs/python-sdk/fastmcp-server-dependencies.mdx
index 125ba2ecb3..2eebf8f5dd 100644
--- a/docs/python-sdk/fastmcp-server-dependencies.mdx
+++ b/docs/python-sdk/fastmcp-server-dependencies.mdx
@@ -5,9 +5,139 @@ sidebarTitle: dependencies
# `fastmcp.server.dependencies`
+
+Dependency injection for FastMCP.
+
+DI features (Depends, CurrentContext, CurrentFastMCP) work without pydocket
+using a vendored DI engine. Only task-related dependencies (CurrentDocket,
+CurrentWorker) and background task execution require fastmcp[tasks].
+
+
## Functions
-### `without_injected_parameters`
+### `is_docket_available`
+
+```python
+is_docket_available() -> bool
+```
+
+
+Check if pydocket is installed.
+
+
+### `require_docket`
+
+```python
+require_docket(feature: str) -> None
+```
+
+
+Raise ImportError with install instructions if docket not available.
+
+**Args:**
+- `feature`: Description of what requires docket (e.g., "`task=True`",
+ "CurrentDocket()"). Will be included in the error message.
+
+
+### `transform_context_annotations`
+
+```python
+transform_context_annotations(fn: Callable[..., Any]) -> Callable[..., Any]
+```
+
+
+Transform ctx: Context into ctx: Context = CurrentContext().
+
+Transforms ALL params typed as Context to use Docket's DI system,
+unless they already have a Dependency-based default (like CurrentContext()).
+
+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.
+
+**Returns:**
+- The active FastMCP server
+
+**Raises:**
+- `RuntimeError`: If no server in context
+
+
+### `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) -> 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` that cause issues
+if forwarded to downstream clients. If `include_all` is True, all headers are returned.
+
+
+### `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]
@@ -21,6 +151,10 @@ 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
@@ -28,37 +162,33 @@ Context injection when called.
- 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]
```
-Resolve dependencies and inject Context for a FastMCP function.
+Resolve dependencies for a FastMCP function.
This function:
1. Filters out any dependency parameter names from user arguments (security)
-2. Resolves Docket dependencies
-3. Injects Context if needed
-4. Merges everything together
+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)
-### `get_context`
-
-```python
-get_context() -> Context
-```
-
-### `CurrentContext`
+### `CurrentContext`
```python
CurrentContext() -> Context
@@ -77,7 +207,7 @@ current MCP operation (tool/resource/prompt call).
- `RuntimeError`: If no active context found (during resolution)
-### `CurrentDocket`
+### `CurrentDocket`
```python
CurrentDocket() -> Docket
@@ -94,9 +224,10 @@ automatically creates for background task scheduling.
**Raises:**
- `RuntimeError`: If not within a FastMCP server context
+- `ImportError`: If fastmcp[tasks] not installed
-### `CurrentWorker`
+### `CurrentWorker`
```python
CurrentWorker() -> Worker
@@ -113,12 +244,13 @@ automatically creates for background task processing.
**Raises:**
- `RuntimeError`: If not within a FastMCP server context
+- `ImportError`: If fastmcp[tasks] not installed
-### `CurrentFastMCP`
+### `CurrentFastMCP`
```python
-CurrentFastMCP()
+CurrentFastMCP() -> FastMCP
```
@@ -133,95 +265,104 @@ This dependency provides access to the active FastMCP server.
- `RuntimeError`: If no server in context (during resolution)
-### `get_server`
+## Classes
-```python
-get_server()
-```
+### `ProgressLike`
-Get the current FastMCP server instance directly.
+Protocol for progress tracking interface.
-**Returns:**
-- The active FastMCP server
+Defines the common interface between InMemoryProgress (server context)
+and Docket's Progress (worker context).
-**Raises:**
-- `RuntimeError`: If no server in context
+**Methods:**
-### `get_http_request`
+#### `current`
```python
-get_http_request() -> Request
+current(self) -> int | None
```
-### `get_http_headers`
+Current progress value.
+
+
+#### `total`
```python
-get_http_headers(include_all: bool = False) -> dict[str, str]
+total(self) -> int
```
+Total/target progress value.
-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).
+#### `message`
-By default, strips problematic headers like `content-length` that cause issues if forwarded to downstream clients.
-If `include_all` is True, all headers are returned.
+```python
+message(self) -> str | None
+```
+Current progress message.
-### `get_access_token`
+
+#### `set_total`
```python
-get_access_token() -> AccessToken | None
+set_total(self, total: int) -> None
```
+Set the total/target value for progress tracking.
-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.
+#### `increment`
-**Returns:**
-- The access token if an authenticated user is available, None otherwise.
+```python
+increment(self, amount: int = 1) -> None
+```
+
+Atomically increment the current progress value.
-## Classes
+#### `set_message`
+
+```python
+set_message(self, message: str | None) -> None
+```
+
+Update the progress status message.
+
-### `InMemoryProgress`
+### `InMemoryProgress`
In-memory progress tracker for immediate tool execution.
-Provides the same interface as Progress but stores state in memory
+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`
+#### `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
@@ -230,7 +371,7 @@ set_total(self, total: int) -> None
Set the total/target value for progress tracking.
-#### `increment`
+#### `increment`
```python
increment(self, amount: int = 1) -> None
@@ -239,7 +380,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
@@ -248,15 +389,17 @@ set_message(self, message: str | None) -> None
Update the progress status message.
-### `Progress`
+### `Progress`
FastMCP Progress dependency that works in both server and worker contexts.
-Extends Docket's Progress to handle two execution modes:
-- In Docket worker: Uses the execution's progress (standard Docket behavior)
-- In FastMCP server: Uses in-memory progress (not observable remotely)
+Handles three execution modes:
+- In Docket worker: Uses the execution's progress (observable via Redis)
+- In FastMCP server with Docket: Falls back to in-memory progress
+- In FastMCP server without Docket: Uses in-memory progress
This allows tools to use Progress() regardless of whether they're called
-immediately or as background tasks.
+immediately or as background tasks, and regardless of whether pydocket
+is installed.
diff --git a/docs/python-sdk/fastmcp-server-elicitation.mdx b/docs/python-sdk/fastmcp-server-elicitation.mdx
index c8c3267d00..47b1d0c4c2 100644
--- a/docs/python-sdk/fastmcp-server-elicitation.mdx
+++ b/docs/python-sdk/fastmcp-server-elicitation.mdx
@@ -28,7 +28,7 @@ Supports multiple syntaxes:
- Other types (dataclass, BaseModel): use directly
-### `handle_elicit_accept`
+### `handle_elicit_accept`
```python
handle_elicit_accept(config: ElicitConfig, content: Any) -> AcceptedElicitation[Any]
@@ -45,7 +45,7 @@ Handle an accepted elicitation response.
- AcceptedElicitation with the extracted/validated data
-### `get_elicitation_schema`
+### `get_elicitation_schema`
```python
get_elicitation_schema(response_type: type[T]) -> dict[str, Any]
@@ -58,7 +58,7 @@ Get the schema for an elicitation response.
- `response_type`: The type of the response
-### `validate_elicitation_json_schema`
+### `validate_elicitation_json_schema`
```python
validate_elicitation_json_schema(schema: dict[str, Any]) -> None
diff --git a/docs/python-sdk/fastmcp-server-http.mdx b/docs/python-sdk/fastmcp-server-http.mdx
index 8aaf2c9343..64e82d57d4 100644
--- a/docs/python-sdk/fastmcp-server-http.mdx
+++ b/docs/python-sdk/fastmcp-server-http.mdx
@@ -7,13 +7,13 @@ sidebarTitle: http
## Functions
-### `set_http_request`
+### `set_http_request`
```python
set_http_request(request: Request) -> Generator[Request, None, None]
```
-### `create_base_app`
+### `create_base_app`
```python
create_base_app(routes: list[BaseRoute], middleware: list[Middleware], debug: bool = False, lifespan: Callable | None = None) -> StarletteWithLifespan
@@ -32,7 +32,7 @@ Create a base Starlette app with common middleware and routes.
- A Starlette application
-### `create_sse_app`
+### `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
@@ -54,7 +54,7 @@ Returns:
A Starlette application with RequestContextMiddleware
-### `create_streamable_http_app`
+### `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) -> StarletteWithLifespan
@@ -83,24 +83,24 @@ disconnections. Requires event_store to be set. Defaults to SDK default.
## Classes
-### `StreamableHTTPASGIApp`
+### `StreamableHTTPASGIApp`
ASGI application wrapper for Streamable HTTP server transport.
-### `StarletteWithLifespan`
+### `StarletteWithLifespan`
**Methods:**
-#### `lifespan`
+#### `lifespan`
```python
lifespan(self) -> Lifespan[Starlette]
```
-### `RequestContextMiddleware`
+### `RequestContextMiddleware`
-Middleware that stores each request in a ContextVar
+Middleware that stores each request in a ContextVar and sets transport type.
diff --git a/docs/python-sdk/fastmcp-server-low_level.mdx b/docs/python-sdk/fastmcp-server-low_level.mdx
index 40ef65ff11..4a2212305b 100644
--- a/docs/python-sdk/fastmcp-server-low_level.mdx
+++ b/docs/python-sdk/fastmcp-server-low_level.mdx
@@ -43,7 +43,20 @@ Get the FastMCP instance.
create_initialization_options(self, notification_options: NotificationOptions | None = None, experimental_capabilities: dict[str, dict[str, Any]] | None = None, **kwargs: Any) -> InitializationOptions
```
-#### `run`
+#### `get_capabilities`
+
+```python
+get_capabilities(self, notification_options: NotificationOptions, experimental_capabilities: dict[str, dict[str, Any]]) -> mcp.types.ServerCapabilities
+```
+
+Override to set capabilities.tasks as a first-class field per SEP-1686.
+
+This ensures task capabilities appear in capabilities.tasks instead of
+capabilities.experimental.tasks, which is required by the MCP spec and
+enables proper task detection by clients like VS Code Copilot 1.107+.
+
+
+#### `run`
```python
run(self, read_stream: MemoryObjectReceiveStream[SessionMessage | Exception], write_stream: MemoryObjectSendStream[SessionMessage], initialization_options: InitializationOptions, raise_exceptions: bool = False, stateless: bool = False)
@@ -52,7 +65,7 @@ run(self, read_stream: MemoryObjectReceiveStream[SessionMessage | Exception], wr
Overrides the run method to use the MiddlewareServerSession.
-#### `read_resource`
+#### `read_resource`
```python
read_resource(self) -> Callable[[Callable[[AnyUrl], Awaitable[mcp.types.ReadResourceResult | mcp.types.CreateTaskResult]]], Callable[[AnyUrl], Awaitable[mcp.types.ReadResourceResult | mcp.types.CreateTaskResult]]]
@@ -67,7 +80,7 @@ This decorator can be removed once the MCP SDK adds native CreateTaskResult supp
for resources.
-#### `get_prompt`
+#### `get_prompt`
```python
get_prompt(self) -> Callable[[Callable[[str, dict[str, Any] | None], Awaitable[mcp.types.GetPromptResult | mcp.types.CreateTaskResult]]], Callable[[str, dict[str, Any] | None], Awaitable[mcp.types.GetPromptResult | mcp.types.CreateTaskResult]]]
diff --git a/docs/python-sdk/fastmcp-server-middleware-authorization.mdx b/docs/python-sdk/fastmcp-server-middleware-authorization.mdx
new file mode 100644
index 0000000000..f5a41afdcd
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-middleware-authorization.mdx
@@ -0,0 +1,116 @@
+---
+title: authorization
+sidebarTitle: authorization
+---
+
+# `fastmcp.server.middleware.authorization`
+
+
+Authorization middleware for FastMCP.
+
+This module provides middleware-based authorization using callable auth checks.
+AuthMiddleware applies auth checks globally to all components on the server.
+
+Example:
+ ```python
+ from fastmcp import FastMCP
+ from fastmcp.server.auth import require_auth, require_scopes, restrict_tag
+ from fastmcp.server.middleware import AuthMiddleware
+
+ # Require auth for all components
+ mcp = FastMCP(middleware=[
+ AuthMiddleware(auth=require_auth)
+ ])
+
+ # Tag-based: components tagged "admin" require "admin" scope
+ mcp = FastMCP(middleware=[
+ AuthMiddleware(auth=restrict_tag("admin", scopes=["admin"]))
+ ])
+ ```
+
+
+## Classes
+
+### `AuthMiddleware`
+
+
+Global authorization middleware using callable checks.
+
+This middleware applies auth checks to all components (tools, resources,
+prompts) on the server. It uses the same callable API as component-level
+auth checks.
+
+The middleware:
+- Filters tools/resources/prompts from list responses based on auth checks
+- Checks auth before tool execution, resource read, and prompt render
+- Skips all auth checks for STDIO transport (no OAuth concept)
+
+**Args:**
+- `auth`: A single auth check function or list of check functions.
+All checks must pass for authorization to succeed (AND logic).
+
+
+**Methods:**
+
+#### `on_list_tools`
+
+```python
+on_list_tools(self, context: MiddlewareContext[mt.ListToolsRequest], call_next: CallNext[mt.ListToolsRequest, Sequence[Tool]]) -> Sequence[Tool]
+```
+
+Filter tools/list response based on auth checks.
+
+
+#### `on_call_tool`
+
+```python
+on_call_tool(self, context: MiddlewareContext[mt.CallToolRequestParams], call_next: CallNext[mt.CallToolRequestParams, ToolResult]) -> ToolResult
+```
+
+Check auth before tool execution.
+
+
+#### `on_list_resources`
+
+```python
+on_list_resources(self, context: MiddlewareContext[mt.ListResourcesRequest], call_next: CallNext[mt.ListResourcesRequest, Sequence[Resource]]) -> Sequence[Resource]
+```
+
+Filter resources/list response based on auth checks.
+
+
+#### `on_read_resource`
+
+```python
+on_read_resource(self, context: MiddlewareContext[mt.ReadResourceRequestParams], call_next: CallNext[mt.ReadResourceRequestParams, ResourceResult]) -> ResourceResult
+```
+
+Check auth before resource read.
+
+
+#### `on_list_resource_templates`
+
+```python
+on_list_resource_templates(self, context: MiddlewareContext[mt.ListResourceTemplatesRequest], call_next: CallNext[mt.ListResourceTemplatesRequest, Sequence[ResourceTemplate]]) -> Sequence[ResourceTemplate]
+```
+
+Filter resource templates/list response based on auth checks.
+
+
+#### `on_list_prompts`
+
+```python
+on_list_prompts(self, context: MiddlewareContext[mt.ListPromptsRequest], call_next: CallNext[mt.ListPromptsRequest, Sequence[Prompt]]) -> Sequence[Prompt]
+```
+
+Filter prompts/list response based on auth checks.
+
+
+#### `on_get_prompt`
+
+```python
+on_get_prompt(self, context: MiddlewareContext[mt.GetPromptRequestParams], call_next: CallNext[mt.GetPromptRequestParams, PromptResult]) -> PromptResult
+```
+
+Check auth before prompt render.
+
diff --git a/docs/python-sdk/fastmcp-server-middleware-ping.mdx b/docs/python-sdk/fastmcp-server-middleware-ping.mdx
new file mode 100644
index 0000000000..fe81c216dd
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-middleware-ping.mdx
@@ -0,0 +1,32 @@
+---
+title: ping
+sidebarTitle: ping
+---
+
+# `fastmcp.server.middleware.ping`
+
+
+Ping middleware for keeping client connections alive.
+
+## Classes
+
+### `PingMiddleware`
+
+
+Middleware that sends periodic pings to keep client connections alive.
+
+Starts a background ping task on first message from each session. The task
+sends server-to-client pings at the configured interval until the session
+ends.
+
+
+**Methods:**
+
+#### `on_message`
+
+```python
+on_message(self, context: MiddlewareContext, call_next: CallNext) -> Any
+```
+
+Start ping task on first message from a session.
+
diff --git a/docs/python-sdk/fastmcp-server-providers-aggregate.mdx b/docs/python-sdk/fastmcp-server-providers-aggregate.mdx
new file mode 100644
index 0000000000..61b90c87ff
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-providers-aggregate.mdx
@@ -0,0 +1,139 @@
+---
+title: aggregate
+sidebarTitle: aggregate
+---
+
+# `fastmcp.server.providers.aggregate`
+
+
+AggregateProvider for combining multiple providers into one.
+
+This module provides `AggregateProvider` which presents multiple providers
+as a single unified provider. Used internally by FastMCP for aggregating
+components from all providers.
+
+
+## Classes
+
+### `AggregateProvider`
+
+
+Presents multiple providers as a single provider.
+
+Components are aggregated from all providers. For get_* operations,
+providers are queried in parallel and the highest version is returned.
+
+Errors from individual providers are logged and skipped (graceful degradation).
+
+
+**Methods:**
+
+#### `list_tools`
+
+```python
+list_tools(self) -> Sequence[Tool]
+```
+
+List all tools from all providers (with transforms applied).
+
+
+#### `get_tool`
+
+```python
+get_tool(self, name: str, version: VersionSpec | None = None) -> Tool | None
+```
+
+Get tool by name.
+
+**Args:**
+- `name`: The tool name.
+- `version`: If None, returns highest version across all providers.
+If specified, returns highest version matching the spec from any provider.
+
+
+#### `list_resources`
+
+```python
+list_resources(self) -> Sequence[Resource]
+```
+
+List all resources from all providers (with transforms applied).
+
+
+#### `get_resource`
+
+```python
+get_resource(self, uri: str, version: VersionSpec | None = None) -> Resource | None
+```
+
+Get resource by URI.
+
+**Args:**
+- `uri`: The resource URI.
+- `version`: If None, returns highest version across all providers.
+If specified, returns highest version matching the spec from any provider.
+
+
+#### `list_resource_templates`
+
+```python
+list_resource_templates(self) -> Sequence[ResourceTemplate]
+```
+
+List all resource templates from all providers (with transforms applied).
+
+
+#### `get_resource_template`
+
+```python
+get_resource_template(self, uri: str, version: VersionSpec | None = None) -> ResourceTemplate | None
+```
+
+Get resource template by URI.
+
+**Args:**
+- `uri`: The template URI to match.
+- `version`: If None, returns highest version across all providers.
+If specified, returns highest version matching the spec from any provider.
+
+
+#### `list_prompts`
+
+```python
+list_prompts(self) -> Sequence[Prompt]
+```
+
+List all prompts from all providers (with transforms applied).
+
+
+#### `get_prompt`
+
+```python
+get_prompt(self, name: str, version: VersionSpec | None = None) -> Prompt | None
+```
+
+Get prompt by name.
+
+**Args:**
+- `name`: The prompt name.
+- `version`: If None, returns highest version across all providers.
+If specified, returns highest version matching the spec from any provider.
+
+
+#### `get_tasks`
+
+```python
+get_tasks(self) -> Sequence[FastMCPComponent]
+```
+
+Get all task-eligible components from all providers.
+
+
+#### `lifespan`
+
+```python
+lifespan(self) -> AsyncIterator[None]
+```
+
+Combine lifespans of all providers.
+
diff --git a/docs/python-sdk/fastmcp-server-providers-base.mdx b/docs/python-sdk/fastmcp-server-providers-base.mdx
index 12c036a084..623c24e21b 100644
--- a/docs/python-sdk/fastmcp-server-providers-base.mdx
+++ b/docs/python-sdk/fastmcp-server-providers-base.mdx
@@ -36,7 +36,7 @@ Example:
## Classes
-### `Provider`
+### `Provider`
Base class for dynamic component providers.
@@ -48,44 +48,22 @@ supports.
**Methods:**
-#### `with_transforms`
+#### `add_transform`
```python
-with_transforms(self) -> Provider
+add_transform(self, transform: Transform) -> None
```
-Apply transformations to this provider's components.
+Add a transform to this provider.
-Returns a TransformingProvider that wraps this provider and applies
-the specified transformations. Can be chained - each call creates a
-new wrapper that composes with the previous.
+Transforms modify components (tools, resources, prompts) as they flow
+through the provider. They're applied in order - first added is innermost.
**Args:**
-- `namespace`: Prefix for tools/prompts ("namespace_name"), path segment
-for resources ("protocol\://namespace/path").
-- `tool_renames`: Map of original_name → final_name. Tools in this map
-use the specified name instead of namespace prefixing.
+- `transform`: The transform to add.
-**Returns:**
-- A TransformingProvider wrapping this provider.
-
-
-#### `with_namespace`
-
-```python
-with_namespace(self, namespace: str) -> Provider
-```
-
-Shorthand for with_transforms(namespace=...).
-
-**Args:**
-- `namespace`: The namespace to apply.
-
-**Returns:**
-- A TransformingProvider wrapping this provider.
-
-#### `list_tools`
+#### `list_tools`
```python
list_tools(self) -> Sequence[Tool]
@@ -93,25 +71,31 @@ list_tools(self) -> Sequence[Tool]
Return all available tools.
-Override to provide tools dynamically.
+Override to provide tools dynamically. Returns ALL versions of all tools.
+The server handles deduplication to show one tool per name.
-#### `get_tool`
+#### `get_tool`
```python
-get_tool(self, name: str) -> Tool | None
+get_tool(self, name: str, version: VersionSpec | None = None) -> Tool | None
```
Get a specific tool by name.
-Default implementation lists all tools and finds by name.
-Override for more efficient single-tool lookup.
+Default implementation filters list_tools() and picks the highest version
+that matches the spec.
+
+**Args:**
+- `name`: The tool name.
+- `version`: Optional version filter. If None, returns highest version.
+ If specified, returns highest version matching the spec.
**Returns:**
- The Tool if found, or None to continue searching other providers.
-#### `list_resources`
+#### `list_resources`
```python
list_resources(self) -> Sequence[Resource]
@@ -119,25 +103,30 @@ list_resources(self) -> Sequence[Resource]
Return all available resources.
-Override to provide resources dynamically.
+Override to provide resources dynamically. Returns ALL versions of all resources.
+The server handles deduplication to show one resource per URI.
-#### `get_resource`
+#### `get_resource`
```python
-get_resource(self, uri: str) -> Resource | None
+get_resource(self, uri: str, version: VersionSpec | None = None) -> Resource | None
```
Get a specific resource by URI.
-Default implementation lists all resources and finds by URI.
-Override for more efficient single-resource lookup.
+Default implementation filters list_resources() and returns highest
+version matching the spec.
+
+**Args:**
+- `uri`: The resource URI.
+- `version`: Optional version filter. If None, returns highest version.
**Returns:**
- The Resource if found, or None to continue searching other providers.
-#### `list_resource_templates`
+#### `list_resource_templates`
```python
list_resource_templates(self) -> Sequence[ResourceTemplate]
@@ -145,26 +134,30 @@ list_resource_templates(self) -> Sequence[ResourceTemplate]
Return all available resource templates.
-Override to provide resource templates dynamically.
+Override to provide resource templates dynamically. Returns ALL versions.
+The server handles deduplication.
-#### `get_resource_template`
+#### `get_resource_template`
```python
-get_resource_template(self, uri: str) -> ResourceTemplate | None
+get_resource_template(self, uri: str, version: VersionSpec | None = None) -> ResourceTemplate | None
```
Get a resource template that matches the given URI.
-Default implementation lists all templates and finds one whose pattern
-matches the URI.
-Override for more efficient lookup.
+Default implementation lists all templates, finds those whose pattern
+matches the URI, and returns the highest version matching the spec.
+
+**Args:**
+- `uri`: The URI to match against templates.
+- `version`: Optional version filter. If None, returns highest version.
**Returns:**
- The ResourceTemplate if a matching one is found, or None to continue searching.
-#### `list_prompts`
+#### `list_prompts`
```python
list_prompts(self) -> Sequence[Prompt]
@@ -172,40 +165,30 @@ list_prompts(self) -> Sequence[Prompt]
Return all available prompts.
-Override to provide prompts dynamically.
+Override to provide prompts dynamically. Returns ALL versions of all prompts.
+The server handles deduplication to show one prompt per name.
-#### `get_prompt`
+#### `get_prompt`
```python
-get_prompt(self, name: str) -> Prompt | None
+get_prompt(self, name: str, version: VersionSpec | None = None) -> Prompt | None
```
Get a specific prompt by name.
-Default implementation lists all prompts and finds by name.
-Override for more efficient single-prompt lookup.
-
-**Returns:**
-- The Prompt if found, or None to continue searching other providers.
-
-
-#### `get_component`
-
-```python
-get_component(self, key: str) -> Tool | Resource | ResourceTemplate | Prompt | None
-```
-
-Get a component by its prefixed key.
+Default implementation filters list_prompts() and picks the highest version
+matching the spec.
**Args:**
-- `key`: The prefixed key (e.g., "tool\:name", "resource\:uri", "template\:uri").
+- `name`: The prompt name.
+- `version`: Optional version filter. If None, returns highest version.
**Returns:**
-- The component if found, or None to continue searching other providers.
+- The Prompt if found, or None to continue searching other providers.
-#### `get_tasks`
+#### `get_tasks`
```python
get_tasks(self) -> Sequence[FastMCPComponent]
@@ -214,13 +197,13 @@ get_tasks(self) -> Sequence[FastMCPComponent]
Return components that should be registered as background tasks.
Override to customize which components are task-eligible.
-Default calls list_* methods and filters for components
-with task_config.mode != 'forbidden'.
+Default calls list_* methods, applies provider transforms, and filters
+for components with task_config.mode != 'forbidden'.
Used by the server during startup to register functions with Docket.
-#### `lifespan`
+#### `lifespan`
```python
lifespan(self) -> AsyncIterator[None]
@@ -236,7 +219,7 @@ The lifespan scope matches the server's lifespan - code before yield
runs at startup, code after yield runs at shutdown.
-#### `enable`
+#### `enable`
```python
enable(self) -> None
@@ -245,12 +228,12 @@ enable(self) -> None
Enable components by removing from blocklist, or set allowlist with only=True.
**Args:**
-- `keys`: Keys to enable (e.g., "tool\:my_tool").
+- `keys`: Keys to enable (e.g., "tool\:my_tool@" for unversioned, "tool\:my_tool@1.0" for versioned).
- `tags`: Tags to enable - components with these tags will be enabled.
- `only`: If True, switches to allowlist mode - ONLY show these keys/tags.
-#### `disable`
+#### `disable`
```python
disable(self) -> None
@@ -259,6 +242,6 @@ disable(self) -> None
Disable components by adding to the blocklist.
**Args:**
-- `keys`: Keys to disable (e.g., "tool\:my_tool").
+- `keys`: Keys to disable (e.g., "tool\:my_tool@" for unversioned, "tool\:my_tool@1.0" for versioned).
- `tags`: Tags to disable - components with these tags will be disabled.
diff --git a/docs/python-sdk/fastmcp-server-providers-fastmcp_provider.mdx b/docs/python-sdk/fastmcp-server-providers-fastmcp_provider.mdx
index 32f940c040..b12db1ca1b 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,19 +39,25 @@ 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 | mcp.types.CreateTaskResult
+run(self, arguments: dict[str, Any]) -> ToolResult
```
-Not implemented - use _run() which delegates to child server.
+Delegate to child server's call_tool() without task_meta.
-FastMCPProviderTool._run() handles all execution by delegating
-to the child server's call_tool() with task_meta.
+This is called when the tool is used within a TransformedTool
+forwarding function or other contexts where task_meta is not available.
-### `FastMCPProviderResource`
+#### `get_span_attributes`
+
+```python
+get_span_attributes(self) -> dict[str, Any]
+```
+
+### `FastMCPProviderResource`
Resource that delegates reading to a wrapped server's read_resource().
@@ -62,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
@@ -71,7 +77,13 @@ wrap(cls, server: Any, resource: Resource) -> FastMCPProviderResource
Wrap a Resource to delegate reading to the server's middleware.
-### `FastMCPProviderPrompt`
+#### `get_span_attributes`
+
+```python
+get_span_attributes(self) -> dict[str, Any]
+```
+
+### `FastMCPProviderPrompt`
Prompt that delegates rendering to a wrapped server's render_prompt().
@@ -82,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
@@ -91,19 +103,25 @@ 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 | mcp.types.CreateTaskResult
+render(self, arguments: dict[str, Any] | None = None) -> PromptResult
```
-Not implemented - use _render() which delegates to child server.
+Delegate to child server's render_prompt() without task_meta.
+
+This is called when the prompt is used within a transformed context
+or other contexts where task_meta is not available.
-FastMCPProviderPrompt._render() handles all execution by delegating
-to the child server's render_prompt() with task_meta.
+#### `get_span_attributes`
-### `FastMCPProviderResourceTemplate`
+```python
+get_span_attributes(self) -> dict[str, Any]
+```
+
+### `FastMCPProviderResourceTemplate`
Resource template that creates FastMCPProviderResources.
@@ -115,7 +133,7 @@ when read.
**Methods:**
-#### `wrap`
+#### `wrap`
```python
wrap(cls, server: Any, template: ResourceTemplate) -> FastMCPProviderResourceTemplate
@@ -124,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
@@ -137,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
@@ -149,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
@@ -158,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
@@ -170,7 +188,13 @@ The child's FunctionResourceTemplate.fn is registered (via get_tasks),
and it expects splatted **kwargs, so we splat params here.
-### `FastMCPProvider`
+#### `get_span_attributes`
+
+```python
+get_span_attributes(self) -> dict[str, Any]
+```
+
+### `FastMCPProvider`
Provider that wraps a FastMCP server.
@@ -186,7 +210,7 @@ This ensures middleware runs when components are executed.
**Methods:**
-#### `list_tools`
+#### `list_tools`
```python
list_tools(self) -> Sequence[Tool]
@@ -199,16 +223,19 @@ each tool as a FastMCPProviderTool that delegates execution to the
nested server's middleware.
-#### `get_tool`
+#### `get_tool`
```python
-get_tool(self, name: str) -> Tool | None
+get_tool(self, name: str, version: VersionSpec | None = None) -> Tool | None
```
Get a tool by name as a FastMCPProviderTool.
+Passes the full VersionSpec to the nested server, which handles both
+exact version matching and range filtering.
-#### `list_resources`
+
+#### `list_resources`
```python
list_resources(self) -> Sequence[Resource]
@@ -221,16 +248,19 @@ each resource as a FastMCPProviderResource that delegates reading to the
nested server's middleware.
-#### `get_resource`
+#### `get_resource`
```python
-get_resource(self, uri: str) -> Resource | None
+get_resource(self, uri: str, version: VersionSpec | None = None) -> Resource | None
```
Get a concrete resource by URI as a FastMCPProviderResource.
+Passes the full VersionSpec to the nested server, which handles both
+exact version matching and range filtering.
+
-#### `list_resource_templates`
+#### `list_resource_templates`
```python
list_resource_templates(self) -> Sequence[ResourceTemplate]
@@ -242,16 +272,19 @@ Returns FastMCPProviderResourceTemplate instances that create
FastMCPProviderResources when materialized.
-#### `get_resource_template`
+#### `get_resource_template`
```python
-get_resource_template(self, uri: str) -> ResourceTemplate | None
+get_resource_template(self, uri: str, version: VersionSpec | None = None) -> ResourceTemplate | None
```
Get a resource template that matches the given URI.
+Passes the full VersionSpec to the nested server, which handles both
+exact version matching and range filtering.
+
-#### `list_prompts`
+#### `list_prompts`
```python
list_prompts(self) -> Sequence[Prompt]
@@ -263,16 +296,19 @@ Returns FastMCPProviderPrompt instances that delegate rendering to the
wrapped server's middleware.
-#### `get_prompt`
+#### `get_prompt`
```python
-get_prompt(self, name: str) -> Prompt | None
+get_prompt(self, name: str, version: VersionSpec | None = None) -> Prompt | None
```
Get a prompt by name as a FastMCPProviderPrompt.
+Passes the full VersionSpec to the nested server, which handles both
+exact version matching and range filtering.
-#### `get_tasks`
+
+#### `get_tasks`
```python
get_tasks(self) -> Sequence[FastMCPComponent]
@@ -281,14 +317,12 @@ get_tasks(self) -> Sequence[FastMCPComponent]
Return task-eligible components from the mounted server.
Returns the child's ACTUAL components (not wrapped) so their actual
-functions get registered with Docket. TransformingProvider.get_tasks()
-handles namespace transformation of keys.
-
-Iterates through all providers in the wrapped server (including its
-LocalProvider) to collect task-eligible components.
+functions get registered with Docket. Uses _source_get_tasks() to get
+components with child 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-providers-filesystem.mdx b/docs/python-sdk/fastmcp-server-providers-filesystem.mdx
new file mode 100644
index 0000000000..55e9b342cd
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-providers-filesystem.mdx
@@ -0,0 +1,128 @@
+---
+title: filesystem
+sidebarTitle: filesystem
+---
+
+# `fastmcp.server.providers.filesystem`
+
+
+FileSystemProvider for filesystem-based component discovery.
+
+FileSystemProvider scans a directory for Python files, imports them, and
+registers any Tool, Resource, ResourceTemplate, or Prompt objects found.
+
+Components are created using the standalone decorators from fastmcp.tools,
+fastmcp.resources, and fastmcp.prompts:
+
+Example:
+ ```python
+ # In mcp/tools.py
+ from fastmcp.tools import tool
+
+ @tool
+ def greet(name: str) -> str:
+ return f"Hello, {name}!"
+
+ # In main.py
+ from pathlib import Path
+
+ from fastmcp import FastMCP
+ from fastmcp.server.providers import FileSystemProvider
+
+ mcp = FastMCP("MyServer", providers=[FileSystemProvider(Path(__file__).parent / "mcp")])
+ ```
+
+
+## Classes
+
+### `FileSystemProvider`
+
+
+Provider that discovers components from the filesystem.
+
+Scans a directory for Python files and registers any Tool, Resource,
+ResourceTemplate, or Prompt objects found. Components are created using
+the standalone decorators:
+- @tool from fastmcp.tools
+- @resource from fastmcp.resources
+- @prompt from fastmcp.prompts
+
+**Args:**
+- `root`: Root directory to scan. Defaults to current directory.
+- `reload`: If True, re-scan files on every request (dev mode).
+Defaults to False (scan once at init, cache results).
+
+
+**Methods:**
+
+#### `list_tools`
+
+```python
+list_tools(self) -> Sequence[Tool]
+```
+
+Return all tools, reloading if in reload mode.
+
+
+#### `get_tool`
+
+```python
+get_tool(self, name: str, version: VersionSpec | None = None) -> Tool | None
+```
+
+Get a tool by name, reloading if in reload mode.
+
+
+#### `list_resources`
+
+```python
+list_resources(self) -> Sequence[Resource]
+```
+
+Return all resources, reloading if in reload mode.
+
+
+#### `get_resource`
+
+```python
+get_resource(self, uri: str, version: VersionSpec | None = None) -> Resource | None
+```
+
+Get a resource by URI, reloading if in reload mode.
+
+
+#### `list_resource_templates`
+
+```python
+list_resource_templates(self) -> Sequence[ResourceTemplate]
+```
+
+Return all resource templates, reloading if in reload mode.
+
+
+#### `get_resource_template`
+
+```python
+get_resource_template(self, uri: str, version: VersionSpec | None = None) -> ResourceTemplate | None
+```
+
+Get a resource template, reloading if in reload mode.
+
+
+#### `list_prompts`
+
+```python
+list_prompts(self) -> Sequence[Prompt]
+```
+
+Return all prompts, reloading if in reload mode.
+
+
+#### `get_prompt`
+
+```python
+get_prompt(self, name: str, version: VersionSpec | None = None) -> Prompt | None
+```
+
+Get a prompt by name, reloading if in reload mode.
+
diff --git a/docs/python-sdk/fastmcp-fs-discovery.mdx b/docs/python-sdk/fastmcp-server-providers-filesystem_discovery.mdx
similarity index 55%
rename from docs/python-sdk/fastmcp-fs-discovery.mdx
rename to docs/python-sdk/fastmcp-server-providers-filesystem_discovery.mdx
index 4d6720be43..0a02129c97 100644
--- a/docs/python-sdk/fastmcp-fs-discovery.mdx
+++ b/docs/python-sdk/fastmcp-server-providers-filesystem_discovery.mdx
@@ -1,9 +1,9 @@
---
-title: discovery
-sidebarTitle: discovery
+title: filesystem_discovery
+sidebarTitle: filesystem_discovery
---
-# `fastmcp.fs.discovery`
+# `fastmcp.server.providers.filesystem_discovery`
File discovery and module import utilities for filesystem-based routing.
@@ -11,12 +11,12 @@ File discovery and module import utilities for filesystem-based routing.
This module provides functions to:
1. Discover Python files in a directory tree
2. Import modules (as packages if __init__.py exists, else directly)
-3. Extract decorated functions from imported modules
+3. Extract decorated components (Tool, Resource, Prompt objects) from imported modules
## Functions
-### `discover_files`
+### `discover_files`
```python
discover_files(root: Path) -> list[Path]
@@ -34,7 +34,7 @@ Excludes __init__.py files (they're for package structure, not components).
- List of .py file paths, sorted for deterministic order.
-### `import_module_from_file`
+### `import_module_from_file`
```python
import_module_from_file(file_path: Path) -> ModuleType
@@ -57,26 +57,27 @@ imports directly using spec_from_file_location.
- `ImportError`: If the module cannot be imported.
-### `extract_components`
+### `extract_components`
```python
-extract_components(module: ModuleType) -> list[tuple[Any, FSMeta]]
+extract_components(module: ModuleType) -> list[FastMCPComponent]
```
-Extract all decorated functions from a module.
+Extract all MCP components from a module.
-Scans all module attributes for functions that have been decorated
-with @tool, @resource, or @prompt.
+Scans all module attributes for instances of Tool, Resource,
+ResourceTemplate, or Prompt objects created by standalone decorators,
+or functions decorated with @tool/@resource/@prompt that have __fastmcp__ metadata.
**Args:**
- `module`: The imported module to scan.
**Returns:**
-- List of (function, metadata) tuples for each decorated function.
+- List of component objects (Tool, Resource, ResourceTemplate, Prompt).
-### `discover_and_import`
+### `discover_and_import`
```python
discover_and_import(root: Path) -> DiscoveryResult
@@ -96,7 +97,7 @@ This is the main entry point for filesystem-based discovery.
## Classes
-### `DiscoveryResult`
+### `DiscoveryResult`
Result of filesystem discovery.
diff --git a/docs/python-sdk/fastmcp-server-providers-local_provider.mdx b/docs/python-sdk/fastmcp-server-providers-local_provider.mdx
index f002b48b1d..247d9e1ba7 100644
--- a/docs/python-sdk/fastmcp-server-providers-local_provider.mdx
+++ b/docs/python-sdk/fastmcp-server-providers-local_provider.mdx
@@ -47,137 +47,135 @@ like `_tool_serializer` and `_support_tasks_by_default` are injected.
**Methods:**
-#### `add_tool`
+#### `add_tool`
```python
-add_tool(self, tool: Tool) -> Tool
+add_tool(self, tool: Tool | Callable[..., Any]) -> Tool
```
Add a tool to this provider's storage.
+Accepts either a Tool object or a decorated function with __fastmcp__ metadata.
-#### `remove_tool`
-```python
-remove_tool(self, name: str) -> None
-```
-
-Remove a tool from this provider's storage.
-
-
-#### `add_resource`
+#### `remove_tool`
```python
-add_resource(self, resource: Resource) -> Resource
+remove_tool(self, name: str, version: str | None = None) -> None
```
-Add a resource to this provider's storage.
+Remove tool(s) from this provider's storage.
+**Args:**
+- `name`: The tool name.
+- `version`: If None, removes ALL versions. If specified, removes only that version.
-#### `remove_resource`
-
-```python
-remove_resource(self, uri: str) -> None
-```
-
-Remove a resource from this provider's storage.
+**Raises:**
+- `KeyError`: If no matching tool is found.
-#### `add_template`
+#### `add_resource`
```python
-add_template(self, template: ResourceTemplate) -> ResourceTemplate
+add_resource(self, resource: Resource | ResourceTemplate | Callable[..., Any]) -> Resource | ResourceTemplate
```
-Add a resource template to this provider's storage.
+Add a resource to this provider's storage.
+Accepts either a Resource/ResourceTemplate object or a decorated function with __fastmcp__ metadata.
-#### `remove_template`
+
+#### `remove_resource`
```python
-remove_template(self, uri_template: str) -> None
+remove_resource(self, uri: str, version: str | None = None) -> None
```
-Remove a resource template from this provider's storage.
-
+Remove resource(s) from this provider's storage.
-#### `add_prompt`
-
-```python
-add_prompt(self, prompt: Prompt) -> Prompt
-```
+**Args:**
+- `uri`: The resource URI.
+- `version`: If None, removes ALL versions. If specified, removes only that version.
-Add a prompt to this provider's storage.
+**Raises:**
+- `KeyError`: If no matching resource is found.
-#### `remove_prompt`
+#### `add_template`
```python
-remove_prompt(self, name: str) -> None
+add_template(self, template: ResourceTemplate) -> ResourceTemplate
```
-Remove a prompt from this provider's storage.
+Add a resource template to this provider's storage.
-#### `add_tool_transformation`
+#### `remove_template`
```python
-add_tool_transformation(self, tool_name: str, transformation: ToolTransformConfig) -> None
+remove_template(self, uri_template: str, version: str | None = None) -> None
```
-Add a tool transformation.
+Remove resource template(s) from this provider's storage.
**Args:**
-- `tool_name`: The name of the tool to transform.
-- `transformation`: The transformation configuration.
+- `uri_template`: The template URI pattern.
+- `version`: If None, removes ALL versions. If specified, removes only that version.
+
+**Raises:**
+- `KeyError`: If no matching template is found.
-#### `get_tool_transformation`
+#### `add_prompt`
```python
-get_tool_transformation(self, tool_name: str) -> ToolTransformConfig | None
+add_prompt(self, prompt: Prompt | Callable[..., Any]) -> Prompt
```
-Get a tool transformation.
+Add a prompt to this provider's storage.
-**Args:**
-- `tool_name`: The name of the tool.
+Accepts either a Prompt object or a decorated function with __fastmcp__ metadata.
-**Returns:**
-- The transformation config, or None if not found.
-
-#### `remove_tool_transformation`
+#### `remove_prompt`
```python
-remove_tool_transformation(self, tool_name: str) -> None
+remove_prompt(self, name: str, version: str | None = None) -> None
```
-Remove a tool transformation.
+Remove prompt(s) from this provider's storage.
**Args:**
-- `tool_name`: The name of the tool.
+- `name`: The prompt name.
+- `version`: If None, removes ALL versions. If specified, removes only that version.
+
+**Raises:**
+- `KeyError`: If no matching prompt is found.
-#### `list_tools`
+#### `list_tools`
```python
list_tools(self) -> Sequence[Tool]
```
-Return all visible tools with transformations applied.
+Return all visible tools.
-#### `get_tool`
+#### `get_tool`
```python
-get_tool(self, name: str) -> Tool | None
+get_tool(self, name: str, version: VersionSpec | None = None) -> Tool | None
```
-Get a tool by name, with transformations applied.
+Get a tool by name.
+**Args:**
+- `name`: The tool name.
+- `version`: Optional version filter. If None, returns highest version.
-#### `list_resources`
+
+#### `list_resources`
```python
list_resources(self) -> Sequence[Resource]
@@ -186,16 +184,20 @@ list_resources(self) -> Sequence[Resource]
Return all visible resources.
-#### `get_resource`
+#### `get_resource`
```python
-get_resource(self, uri: str) -> Resource | None
+get_resource(self, uri: str, version: VersionSpec | None = None) -> Resource | None
```
-Get a resource by URI if visible.
+Get a resource by URI.
+**Args:**
+- `uri`: The resource URI.
+- `version`: Optional version filter. If None, returns highest version.
-#### `list_resource_templates`
+
+#### `list_resource_templates`
```python
list_resource_templates(self) -> Sequence[ResourceTemplate]
@@ -204,16 +206,20 @@ list_resource_templates(self) -> Sequence[ResourceTemplate]
Return all visible resource templates.
-#### `get_resource_template`
+#### `get_resource_template`
```python
-get_resource_template(self, uri: str) -> ResourceTemplate | None
+get_resource_template(self, uri: str, version: VersionSpec | None = None) -> ResourceTemplate | None
```
-Get a resource template that matches the given URI if visible.
+Get a resource template that matches the given URI.
+
+**Args:**
+- `uri`: The URI to match against templates.
+- `version`: Optional version filter. If None, returns highest version.
-#### `list_prompts`
+#### `list_prompts`
```python
list_prompts(self) -> Sequence[Prompt]
@@ -222,27 +228,20 @@ list_prompts(self) -> Sequence[Prompt]
Return all visible prompts.
-#### `get_prompt`
-
-```python
-get_prompt(self, name: str) -> Prompt | None
-```
-
-Get a prompt by name if visible.
-
-
-#### `get_component`
+#### `get_prompt`
```python
-get_component(self, key: str) -> Tool | Resource | ResourceTemplate | Prompt | None
+get_prompt(self, name: str, version: VersionSpec | None = None) -> Prompt | None
```
-Get a component by its prefixed key.
+Get a prompt by name.
-Efficient O(1) lookup in the unified components dict.
+**Args:**
+- `name`: The prompt name.
+- `version`: Optional version filter. If None, returns highest version.
-#### `get_tasks`
+#### `get_tasks`
```python
get_tasks(self) -> Sequence[FastMCPComponent]
@@ -255,19 +254,19 @@ This includes both FunctionTool/Resource/Prompt instances created via
decorators and custom Tool/Resource/Prompt subclasses.
-#### `tool`
+#### `tool`
```python
tool(self, name_or_fn: AnyFunction) -> FunctionTool
```
-#### `tool`
+#### `tool`
```python
tool(self, name_or_fn: str | None = None) -> Callable[[AnyFunction], FunctionTool]
```
-#### `tool`
+#### `tool`
```python
tool(self, name_or_fn: str | AnyFunction | None = None) -> Callable[[AnyFunction], FunctionTool] | FunctionTool | partial[Callable[[AnyFunction], FunctionTool] | FunctionTool]
@@ -301,10 +300,10 @@ This decorator supports multiple calling patterns:
- The registered FunctionTool or a decorator function.
-#### `resource`
+#### `resource`
```python
-resource(self, uri: str) -> Callable[[AnyFunction], Resource | ResourceTemplate]
+resource(self, uri: str) -> Callable[[AnyFunction], Resource | ResourceTemplate | AnyFunction]
```
Decorator to register a function as a resource.
@@ -324,24 +323,25 @@ has parameters, it will be registered as a template resource.
- `annotations`: Optional annotations about the resource's behavior
- `meta`: Optional meta information about the resource
- `task`: Optional task configuration for background execution
+- `auth`: Optional authorization checks for the resource
**Returns:**
- A decorator function.
-#### `prompt`
+#### `prompt`
```python
prompt(self, name_or_fn: AnyFunction) -> FunctionPrompt
```
-#### `prompt`
+#### `prompt`
```python
prompt(self, name_or_fn: str | None = None) -> Callable[[AnyFunction], FunctionPrompt]
```
-#### `prompt`
+#### `prompt`
```python
prompt(self, name_or_fn: str | AnyFunction | None = None) -> Callable[[AnyFunction], FunctionPrompt] | FunctionPrompt | partial[Callable[[AnyFunction], FunctionPrompt] | FunctionPrompt]
@@ -366,6 +366,7 @@ This decorator supports multiple calling patterns:
- `enabled`: Whether the prompt is enabled (default True). If False, adds to blocklist.
- `meta`: Optional meta information about the prompt
- `task`: Optional task configuration for background execution
+- `auth`: Optional authorization checks for the prompt
**Returns:**
- The registered FunctionPrompt or a decorator function.
diff --git a/docs/python-sdk/fastmcp-server-providers-openapi-provider.mdx b/docs/python-sdk/fastmcp-server-providers-openapi-provider.mdx
index 2df5a64491..2e262c5258 100644
--- a/docs/python-sdk/fastmcp-server-providers-openapi-provider.mdx
+++ b/docs/python-sdk/fastmcp-server-providers-openapi-provider.mdx
@@ -10,7 +10,7 @@ OpenAPIProvider for creating MCP components from OpenAPI specifications.
## Classes
-### `OpenAPIProvider`
+### `OpenAPIProvider`
Provider that creates MCP components from an OpenAPI specification.
@@ -21,7 +21,7 @@ spec. Each component makes HTTP calls to the described API endpoints.
**Methods:**
-#### `list_tools`
+#### `list_tools`
```python
list_tools(self) -> Sequence[Tool]
@@ -30,16 +30,16 @@ list_tools(self) -> Sequence[Tool]
Return all tools created from the OpenAPI spec.
-#### `get_tool`
+#### `get_tool`
```python
-get_tool(self, name: str) -> Tool | None
+get_tool(self, name: str, version: VersionSpec | None = None) -> Tool | None
```
Get a tool by name.
-#### `list_resources`
+#### `list_resources`
```python
list_resources(self) -> Sequence[Resource]
@@ -48,16 +48,16 @@ list_resources(self) -> Sequence[Resource]
Return all resources created from the OpenAPI spec.
-#### `get_resource`
+#### `get_resource`
```python
-get_resource(self, uri: str) -> Resource | None
+get_resource(self, uri: str, version: VersionSpec | None = None) -> Resource | None
```
Get a resource by URI.
-#### `list_resource_templates`
+#### `list_resource_templates`
```python
list_resource_templates(self) -> Sequence[ResourceTemplate]
@@ -66,16 +66,16 @@ list_resource_templates(self) -> Sequence[ResourceTemplate]
Return all resource templates created from the OpenAPI spec.
-#### `get_resource_template`
+#### `get_resource_template`
```python
-get_resource_template(self, uri: str) -> ResourceTemplate | None
+get_resource_template(self, uri: str, version: VersionSpec | None = None) -> ResourceTemplate | None
```
Get a resource template that matches the given URI.
-#### `list_prompts`
+#### `list_prompts`
```python
list_prompts(self) -> Sequence[Prompt]
@@ -84,7 +84,7 @@ list_prompts(self) -> Sequence[Prompt]
Return empty list - OpenAPI doesn't create prompts.
-#### `get_tasks`
+#### `get_tasks`
```python
get_tasks(self) -> Sequence[FastMCPComponent]
diff --git a/docs/python-sdk/fastmcp-server-providers-proxy.mdx b/docs/python-sdk/fastmcp-server-providers-proxy.mdx
index 90e7796470..55aca8243f 100644
--- a/docs/python-sdk/fastmcp-server-providers-proxy.mdx
+++ b/docs/python-sdk/fastmcp-server-providers-proxy.mdx
@@ -15,7 +15,7 @@ classes that forward execution to remote servers.
## Functions
-### `default_proxy_roots_handler`
+### `default_proxy_roots_handler`
```python
default_proxy_roots_handler(context: RequestContext[ClientSession, LifespanContextT]) -> RootsList
@@ -25,7 +25,7 @@ default_proxy_roots_handler(context: RequestContext[ClientSession, LifespanConte
Forward list roots request from remote server to proxy's connected clients.
-### `default_proxy_sampling_handler`
+### `default_proxy_sampling_handler`
```python
default_proxy_sampling_handler(messages: list[mcp.types.SamplingMessage], params: mcp.types.CreateMessageRequestParams, context: RequestContext[ClientSession, LifespanContextT]) -> mcp.types.CreateMessageResult
@@ -35,7 +35,7 @@ default_proxy_sampling_handler(messages: list[mcp.types.SamplingMessage], params
Forward sampling request from remote server to proxy's connected clients.
-### `default_proxy_elicitation_handler`
+### `default_proxy_elicitation_handler`
```python
default_proxy_elicitation_handler(message: str, response_type: type, params: mcp.types.ElicitRequestParams, context: RequestContext[ClientSession, LifespanContextT]) -> ElicitResult
@@ -45,7 +45,7 @@ default_proxy_elicitation_handler(message: str, response_type: type, params: mcp
Forward elicitation request from remote server to proxy's connected clients.
-### `default_proxy_log_handler`
+### `default_proxy_log_handler`
```python
default_proxy_log_handler(message: LogMessage) -> None
@@ -55,7 +55,7 @@ default_proxy_log_handler(message: LogMessage) -> None
Forward log notification from remote server to proxy's connected clients.
-### `default_proxy_progress_handler`
+### `default_proxy_progress_handler`
```python
default_proxy_progress_handler(progress: float, total: float | None, message: str | None) -> None
@@ -67,7 +67,7 @@ Forward progress notification from remote server to proxy's connected clients.
## Classes
-### `ProxyTool`
+### `ProxyTool`
A Tool that represents and executes a tool on a remote server.
@@ -75,7 +75,7 @@ A Tool that represents and executes a tool on a remote server.
**Methods:**
-#### `model_copy`
+#### `model_copy`
```python
model_copy(self, **kwargs: Any) -> ProxyTool
@@ -84,7 +84,7 @@ model_copy(self, **kwargs: Any) -> ProxyTool
Override to preserve _backend_name when name changes.
-#### `from_mcp_tool`
+#### `from_mcp_tool`
```python
from_mcp_tool(cls, client_factory: ClientFactoryT, mcp_tool: mcp.types.Tool) -> ProxyTool
@@ -93,7 +93,7 @@ from_mcp_tool(cls, client_factory: ClientFactoryT, mcp_tool: mcp.types.Tool) ->
Factory method to create a ProxyTool from a raw MCP tool schema.
-#### `run`
+#### `run`
```python
run(self, arguments: dict[str, Any], context: Context | None = None) -> ToolResult
@@ -102,7 +102,13 @@ run(self, arguments: dict[str, Any], context: Context | None = None) -> ToolResu
Executes the tool by making a call through the client.
-### `ProxyResource`
+#### `get_span_attributes`
+
+```python
+get_span_attributes(self) -> dict[str, Any]
+```
+
+### `ProxyResource`
A Resource that represents and reads a resource from a remote server.
@@ -110,7 +116,7 @@ A Resource that represents and reads a resource from a remote server.
**Methods:**
-#### `model_copy`
+#### `model_copy`
```python
model_copy(self, **kwargs: Any) -> ProxyResource
@@ -119,7 +125,7 @@ model_copy(self, **kwargs: Any) -> ProxyResource
Override to preserve _backend_uri when uri changes.
-#### `from_mcp_resource`
+#### `from_mcp_resource`
```python
from_mcp_resource(cls, client_factory: ClientFactoryT, mcp_resource: mcp.types.Resource) -> ProxyResource
@@ -128,7 +134,7 @@ from_mcp_resource(cls, client_factory: ClientFactoryT, mcp_resource: mcp.types.R
Factory method to create a ProxyResource from a raw MCP resource schema.
-#### `read`
+#### `read`
```python
read(self) -> ResourceResult
@@ -137,7 +143,13 @@ read(self) -> ResourceResult
Read the resource content from the remote server.
-### `ProxyTemplate`
+#### `get_span_attributes`
+
+```python
+get_span_attributes(self) -> dict[str, Any]
+```
+
+### `ProxyTemplate`
A ResourceTemplate that represents and creates resources from a remote server template.
@@ -145,7 +157,7 @@ A ResourceTemplate that represents and creates resources from a remote server te
**Methods:**
-#### `model_copy`
+#### `model_copy`
```python
model_copy(self, **kwargs: Any) -> ProxyTemplate
@@ -154,7 +166,7 @@ model_copy(self, **kwargs: Any) -> ProxyTemplate
Override to preserve _backend_uri_template when uri_template changes.
-#### `from_mcp_template`
+#### `from_mcp_template`
```python
from_mcp_template(cls, client_factory: ClientFactoryT, mcp_template: mcp.types.ResourceTemplate) -> ProxyTemplate
@@ -163,7 +175,7 @@ from_mcp_template(cls, client_factory: ClientFactoryT, mcp_template: mcp.types.R
Factory method to create a ProxyTemplate from a raw MCP template schema.
-#### `create_resource`
+#### `create_resource`
```python
create_resource(self, uri: str, params: dict[str, Any], context: Context | None = None) -> ProxyResource
@@ -172,7 +184,13 @@ create_resource(self, uri: str, params: dict[str, Any], context: Context | None
Create a resource from the template by calling the remote server.
-### `ProxyPrompt`
+#### `get_span_attributes`
+
+```python
+get_span_attributes(self) -> dict[str, Any]
+```
+
+### `ProxyPrompt`
A Prompt that represents and renders a prompt from a remote server.
@@ -180,7 +198,7 @@ A Prompt that represents and renders a prompt from a remote server.
**Methods:**
-#### `model_copy`
+#### `model_copy`
```python
model_copy(self, **kwargs: Any) -> ProxyPrompt
@@ -189,7 +207,7 @@ model_copy(self, **kwargs: Any) -> ProxyPrompt
Override to preserve _backend_name when name changes.
-#### `from_mcp_prompt`
+#### `from_mcp_prompt`
```python
from_mcp_prompt(cls, client_factory: ClientFactoryT, mcp_prompt: mcp.types.Prompt) -> ProxyPrompt
@@ -198,7 +216,7 @@ from_mcp_prompt(cls, client_factory: ClientFactoryT, mcp_prompt: mcp.types.Promp
Factory method to create a ProxyPrompt from a raw MCP prompt schema.
-#### `render`
+#### `render`
```python
render(self, arguments: dict[str, Any]) -> PromptResult
@@ -207,7 +225,13 @@ render(self, arguments: dict[str, Any]) -> PromptResult
Render the prompt by making a call through the client.
-### `ProxyProvider`
+#### `get_span_attributes`
+
+```python
+get_span_attributes(self) -> dict[str, Any]
+```
+
+### `ProxyProvider`
Provider that proxies to a remote MCP server via a client factory.
@@ -221,7 +245,7 @@ because tasks cannot be executed through a proxy.
**Methods:**
-#### `list_tools`
+#### `list_tools`
```python
list_tools(self) -> Sequence[Tool]
@@ -230,7 +254,7 @@ list_tools(self) -> Sequence[Tool]
List all tools from the remote server.
-#### `list_resources`
+#### `list_resources`
```python
list_resources(self) -> Sequence[Resource]
@@ -239,7 +263,7 @@ list_resources(self) -> Sequence[Resource]
List all resources from the remote server.
-#### `list_resource_templates`
+#### `list_resource_templates`
```python
list_resource_templates(self) -> Sequence[ResourceTemplate]
@@ -248,7 +272,7 @@ list_resource_templates(self) -> Sequence[ResourceTemplate]
List all resource templates from the remote server.
-#### `list_prompts`
+#### `list_prompts`
```python
list_prompts(self) -> Sequence[Prompt]
@@ -257,7 +281,7 @@ list_prompts(self) -> Sequence[Prompt]
List all prompts from the remote server.
-#### `get_tasks`
+#### `get_tasks`
```python
get_tasks(self) -> Sequence[FastMCPComponent]
@@ -270,7 +294,7 @@ server lifespan initialization, which would open the client before any
context is set. All Proxy* components have task_config.mode="forbidden".
-### `FastMCPProxy`
+### `FastMCPProxy`
A FastMCP server that acts as a proxy to a remote MCP-compliant server.
@@ -279,7 +303,7 @@ This is a convenience wrapper that creates a FastMCP server with a
ProxyProvider. For more control, use FastMCP with add_provider(ProxyProvider(...)).
-### `ProxyClient`
+### `ProxyClient`
A proxy client that forwards advanced interactions between a remote MCP server and the proxy's connected clients.
@@ -287,7 +311,7 @@ A proxy client that forwards advanced interactions between a remote MCP server a
Supports forwarding roots, sampling, elicitation, logging, and progress.
-### `StatefulProxyClient`
+### `StatefulProxyClient`
A proxy client that provides a stateful client factory for the proxy server.
@@ -301,7 +325,7 @@ Note that it is essential to ensure that the proxy server itself is also statefu
**Methods:**
-#### `clear`
+#### `clear`
```python
clear(self)
@@ -310,7 +334,7 @@ clear(self)
Clear all cached clients and force disconnect them.
-#### `new_stateful`
+#### `new_stateful`
```python
new_stateful(self) -> Client[ClientTransportT]
diff --git a/docs/python-sdk/fastmcp-server-providers-transforming.mdx b/docs/python-sdk/fastmcp-server-providers-transforming.mdx
deleted file mode 100644
index 94952eac2a..0000000000
--- a/docs/python-sdk/fastmcp-server-providers-transforming.mdx
+++ /dev/null
@@ -1,117 +0,0 @@
----
-title: transforming
-sidebarTitle: transforming
----
-
-# `fastmcp.server.providers.transforming`
-
-
-TransformingProvider for applying component transformations.
-
-This module provides the `TransformingProvider` class that wraps any Provider
-and applies transformations like namespace prefixes and tool renames.
-
-
-## Classes
-
-### `TransformingProvider`
-
-
-Wraps any provider and applies component transformations.
-
-Users typically use `provider.with_transforms()` rather than instantiating
-this class directly. Multiple `.with_transforms()` calls stack - each
-creates a new wrapper that composes with the previous.
-
-
-**Methods:**
-
-#### `list_tools`
-
-```python
-list_tools(self) -> Sequence[Tool]
-```
-
-List tools with transformations applied.
-
-
-#### `get_tool`
-
-```python
-get_tool(self, name: str) -> Tool | None
-```
-
-Get tool by transformed name.
-
-
-#### `list_resources`
-
-```python
-list_resources(self) -> Sequence[Resource]
-```
-
-List resources with URI transformations applied.
-
-
-#### `get_resource`
-
-```python
-get_resource(self, uri: str) -> Resource | None
-```
-
-Get resource by transformed URI.
-
-
-#### `list_resource_templates`
-
-```python
-list_resource_templates(self) -> Sequence[ResourceTemplate]
-```
-
-List resource templates with URI transformations applied.
-
-
-#### `get_resource_template`
-
-```python
-get_resource_template(self, uri: str) -> ResourceTemplate | None
-```
-
-Get resource template by transformed URI.
-
-
-#### `list_prompts`
-
-```python
-list_prompts(self) -> Sequence[Prompt]
-```
-
-List prompts with transformations applied.
-
-
-#### `get_prompt`
-
-```python
-get_prompt(self, name: str) -> Prompt | None
-```
-
-Get prompt by transformed name.
-
-
-#### `get_tasks`
-
-```python
-get_tasks(self) -> Sequence[FastMCPComponent]
-```
-
-Get tasks with transformations applied to all components.
-
-
-#### `lifespan`
-
-```python
-lifespan(self) -> AsyncIterator[None]
-```
-
-Delegate lifespan to wrapped provider.
-
diff --git a/docs/python-sdk/fastmcp-server-server.mdx b/docs/python-sdk/fastmcp-server-server.mdx
index da73702c32..b627ea0bb4 100644
--- a/docs/python-sdk/fastmcp-server-server.mdx
+++ b/docs/python-sdk/fastmcp-server-server.mdx
@@ -10,7 +10,7 @@ FastMCP - A more ergonomic interface for MCP servers.
## Functions
-### `default_lifespan`
+### `default_lifespan`
```python
default_lifespan(server: FastMCP[LifespanResultT]) -> AsyncIterator[Any]
@@ -26,7 +26,7 @@ Default lifespan context manager that does nothing.
- An empty dictionary as the lifespan result.
-### `create_proxy`
+### `create_proxy`
```python
create_proxy(target: Client[ClientTransportT] | ClientTransport | FastMCP[Any] | FastMCP1Server | AnyUrl | Path | MCPConfig | dict[str, Any] | str, **settings: Any) -> FastMCPProxy
@@ -54,53 +54,59 @@ use `FastMCPProxy` or `ProxyProvider` directly from `fastmcp.server.providers.pr
## Classes
-### `FastMCP`
+### `StateValue`
+
+
+Wrapper for stored context state values.
+
+
+### `FastMCP`
**Methods:**
-#### `settings`
+#### `settings`
```python
settings(self) -> Settings
```
-#### `name`
+#### `name`
```python
name(self) -> str
```
-#### `instructions`
+#### `instructions`
```python
instructions(self) -> str | None
```
-#### `instructions`
+#### `instructions`
```python
instructions(self, value: str | None) -> None
```
-#### `version`
+#### `version`
```python
version(self) -> str | None
```
-#### `website_url`
+#### `website_url`
```python
website_url(self) -> str | None
```
-#### `icons`
+#### `icons`
```python
icons(self) -> list[mcp.types.Icon]
```
-#### `docket`
+#### `docket`
```python
docket(self) -> Docket | None
@@ -111,7 +117,7 @@ Get the Docket instance if Docket support is enabled.
Returns None if Docket is not enabled or server hasn't been started yet.
-#### `run_async`
+#### `run_async`
```python
run_async(self, transport: Transport | None = None, show_banner: bool | None = None, **transport_kwargs: Any) -> None
@@ -125,7 +131,7 @@ Run the FastMCP server asynchronously.
FASTMCP_SHOW_SERVER_BANNER setting (default\: True).
-#### `run`
+#### `run`
```python
run(self, transport: Transport | None = None, show_banner: bool | None = None, **transport_kwargs: Any) -> None
@@ -139,13 +145,13 @@ Run the FastMCP server. Note this is a synchronous function.
FASTMCP_SHOW_SERVER_BANNER setting (default\: True).
-#### `add_middleware`
+#### `add_middleware`
```python
add_middleware(self, middleware: Middleware) -> None
```
-#### `add_provider`
+#### `add_provider`
```python
add_provider(self, provider: Provider) -> None
@@ -161,7 +167,46 @@ always take precedence over providers.
- `provider`: A Provider instance that will provide components dynamically.
-#### `enable`
+#### `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.
+
+
+#### `add_tool_transformation`
+
+```python
+add_tool_transformation(self, tool_name: str, transformation: ToolTransformConfig) -> None
+```
+
+Add a tool transformation.
+
+.. deprecated::
+ Use ``add_transform(ToolTransform({...}))`` instead.
+
+
+#### `remove_tool_transformation`
+
+```python
+remove_tool_transformation(self, _tool_name: str) -> None
+```
+
+Remove a tool transformation.
+
+.. deprecated::
+ Tool transformations are now immutable. Use visibility controls instead.
+
+
+#### `enable`
```python
enable(self) -> None
@@ -170,13 +215,13 @@ enable(self) -> None
Enable components by removing from blocklist, or set allowlist with only=True.
**Args:**
-- `keys`: Keys to enable (e.g., ``"tool\:my_tool"``).
+- `keys`: Keys to enable (e.g., ``"tool\:my_tool@"`` for unversioned, ``"tool\:my_tool@1.0"`` for versioned).
- `tags`: Tags to enable - components with these tags will be enabled.
- `only`: If True, switches to allowlist mode - ONLY show these keys/tags.
This clears existing allowlists and sets default visibility to False.
-#### `disable`
+#### `disable`
```python
disable(self) -> None
@@ -185,11 +230,11 @@ disable(self) -> None
Disable components by adding to the blocklist.
**Args:**
-- `keys`: Keys to disable (e.g., ``"tool\:my_tool"``).
+- `keys`: Keys to disable (e.g., ``"tool\:my_tool@"`` for unversioned, ``"tool\:my_tool@1.0"`` for versioned).
- `tags`: Tags to disable - components with these tags will be disabled.
-#### `get_tools`
+#### `get_tools`
```python
get_tools(self) -> list[Tool]
@@ -197,27 +242,34 @@ get_tools(self) -> list[Tool]
Get all enabled tools from providers.
-Queries all providers in parallel and collects tools.
-First provider wins for duplicate keys. Filters by server blocklist.
+Queries all providers via the root provider (which applies provider transforms,
+server transforms, and visibility filtering). First provider wins for duplicate keys.
**Args:**
- `run_middleware`: If True, apply the middleware chain before
returning results. Used by MCP handlers and mounted servers.
-#### `get_tool`
+#### `get_tool`
```python
-get_tool(self, name: str) -> Tool
+get_tool(self, name: str, version: VersionSpec | str | None = None) -> Tool
```
Get an enabled tool by name.
-Queries all providers in parallel to find the tool.
-First provider wins. Returns only if enabled.
+Queries providers with full transform chain (provider transforms + server transforms + visibility).
+Returns only if enabled and authorized.
+
+**Args:**
+- `name`: The tool name.
+- `version`: Version filter. Can be\:
+- None\: returns highest version
+- str\: returns exact version match
+- VersionSpec\: returns best match within spec (highest matching)
-#### `get_resources`
+#### `get_resources`
```python
get_resources(self) -> list[Resource]
@@ -225,27 +277,34 @@ get_resources(self) -> list[Resource]
Get all enabled resources from providers.
-Queries all providers in parallel and collects resources.
-First provider wins for duplicate keys. Filters by server blocklist.
+Queries all providers via the root provider (which applies provider transforms,
+server transforms, and visibility filtering). First provider wins for duplicate keys.
**Args:**
- `run_middleware`: If True, apply the middleware chain before
returning results. Used by MCP handlers and mounted servers.
-#### `get_resource`
+#### `get_resource`
```python
-get_resource(self, uri: str) -> Resource
+get_resource(self, uri: str, version: VersionSpec | str | None = None) -> Resource
```
Get an enabled resource by URI.
-Queries all providers in parallel to find the resource.
-First provider wins. Returns only if enabled.
+Queries providers with full transform chain (provider transforms + server transforms + visibility).
+Returns only if enabled and authorized.
+
+**Args:**
+- `uri`: The resource URI.
+- `version`: Version filter. Can be\:
+- None\: returns highest version
+- str\: returns exact version match
+- VersionSpec\: returns best match within spec (highest matching)
-#### `get_resource_templates`
+#### `get_resource_templates`
```python
get_resource_templates(self) -> list[ResourceTemplate]
@@ -253,27 +312,34 @@ get_resource_templates(self) -> list[ResourceTemplate]
Get all enabled resource templates from providers.
-Queries all providers in parallel and collects templates.
-First provider wins for duplicate keys. Filters by server blocklist.
+Queries all providers via the root provider (which applies provider transforms,
+server transforms, and visibility filtering). First provider wins for duplicate keys.
**Args:**
- `run_middleware`: If True, apply the middleware chain before
returning results. Used by MCP handlers and mounted servers.
-#### `get_resource_template`
+#### `get_resource_template`
```python
-get_resource_template(self, uri: str) -> ResourceTemplate
+get_resource_template(self, uri: str, version: VersionSpec | str | None = None) -> ResourceTemplate
```
Get an enabled resource template that matches the given URI.
-Queries all providers in parallel to find the template.
-First provider wins. Returns only if enabled.
+Queries providers with full transform chain (provider transforms + server transforms + visibility).
+Returns only if enabled and authorized.
+
+**Args:**
+- `uri`: The template URI to match.
+- `version`: Version filter. Can be\:
+- None\: returns highest version
+- str\: returns exact version match
+- VersionSpec\: returns best match within spec (highest matching)
-#### `get_prompts`
+#### `get_prompts`
```python
get_prompts(self) -> list[Prompt]
@@ -281,60 +347,46 @@ get_prompts(self) -> list[Prompt]
Get all enabled prompts from providers.
-Queries all providers in parallel and collects prompts.
-First provider wins for duplicate keys. Filters by server blocklist.
+Queries all providers via the root provider (which applies provider transforms,
+server transforms, and visibility filtering). First provider wins for duplicate keys.
**Args:**
- `run_middleware`: If True, apply the middleware chain before
returning results. Used by MCP handlers and mounted servers.
-#### `get_prompt`
+#### `get_prompt`
```python
-get_prompt(self, name: str) -> Prompt
+get_prompt(self, name: str, version: VersionSpec | str | None = None) -> Prompt
```
Get an enabled prompt by name.
-Queries all providers in parallel to find the prompt.
-First provider wins. Returns only if enabled.
-
-
-#### `get_component`
-
-```python
-get_component(self, key: str) -> Tool | Resource | ResourceTemplate | Prompt
-```
-
-Get a component by its prefixed key.
-
-Queries all providers in parallel to find the component.
-First provider wins.
+Queries providers with full transform chain (provider transforms + server transforms + visibility).
+Returns only if enabled and authorized.
**Args:**
-- `key`: The prefixed key (e.g., "tool\:name", "resource\:uri", "template\:uri").
-
-**Returns:**
-- The component if found.
-
-**Raises:**
-- `NotFoundError`: If no component is found with the given key.
+- `name`: The prompt name.
+- `version`: Version filter. Can be\:
+- None\: returns highest version
+- str\: returns exact version match
+- VersionSpec\: returns best match within spec (highest matching)
-#### `call_tool`
+#### `call_tool`
```python
call_tool(self, name: str, arguments: dict[str, Any] | None = None) -> ToolResult
```
-#### `call_tool`
+#### `call_tool`
```python
call_tool(self, name: str, arguments: dict[str, Any] | None = None) -> mcp.types.CreateTaskResult
```
-#### `call_tool`
+#### `call_tool`
```python
call_tool(self, name: str, arguments: dict[str, Any] | None = None) -> ToolResult | mcp.types.CreateTaskResult
@@ -363,19 +415,19 @@ return ToolResult.
- `ValidationError`: If arguments fail validation
-#### `read_resource`
+#### `read_resource`
```python
read_resource(self, uri: str) -> ResourceResult
```
-#### `read_resource`
+#### `read_resource`
```python
read_resource(self, uri: str) -> mcp.types.CreateTaskResult
```
-#### `read_resource`
+#### `read_resource`
```python
read_resource(self, uri: str) -> ResourceResult | mcp.types.CreateTaskResult
@@ -403,19 +455,19 @@ return ResourceResult.
- `ResourceError`: If resource read fails
-#### `render_prompt`
+#### `render_prompt`
```python
render_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> PromptResult
```
-#### `render_prompt`
+#### `render_prompt`
```python
render_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> mcp.types.CreateTaskResult
```
-#### `render_prompt`
+#### `render_prompt`
```python
render_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> PromptResult | mcp.types.CreateTaskResult
@@ -444,7 +496,7 @@ return PromptResult.
- `PromptError`: If prompt rendering fails
-#### `custom_route`
+#### `custom_route`
```python
custom_route(self, path: str, methods: list[str], name: str | None = None, include_in_schema: bool = True) -> Callable[[Callable[[Request], Awaitable[Response]]], Callable[[Request], Awaitable[Response]]]
@@ -465,10 +517,10 @@ Starlette's reverse URL lookup feature)
- `include_in_schema`: Whether to include in OpenAPI schema, defaults to True
-#### `add_tool`
+#### `add_tool`
```python
-add_tool(self, tool: Tool) -> Tool
+add_tool(self, tool: Tool | Callable[..., Any]) -> Tool
```
Add a tool to the server.
@@ -477,58 +529,41 @@ 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 to register
+- `tool`: The Tool instance or @tool-decorated function to register
**Returns:**
- The tool instance that was added to the server.
-#### `remove_tool`
+#### `remove_tool`
```python
-remove_tool(self, name: str) -> None
+remove_tool(self, name: str, version: str | None = None) -> None
```
-Remove a tool from the server.
+Remove tool(s) from the server.
**Args:**
-- `name`: The name of the tool to remove
+- `name`: The name of the tool to remove.
+- `version`: If None, removes ALL versions. If specified, removes only that version.
**Raises:**
-- `NotFoundError`: If the tool is not found
-
-
-#### `add_tool_transformation`
-
-```python
-add_tool_transformation(self, tool_name: str, transformation: ToolTransformConfig) -> None
-```
-
-Add a tool transformation.
-
-
-#### `remove_tool_transformation`
-
-```python
-remove_tool_transformation(self, tool_name: str) -> None
-```
-
-Remove a tool transformation.
+- `NotFoundError`: If no matching tool is found.
-#### `tool`
+#### `tool`
```python
tool(self, name_or_fn: AnyFunction) -> FunctionTool
```
-#### `tool`
+#### `tool`
```python
tool(self, name_or_fn: str | None = None) -> Callable[[AnyFunction], FunctionTool]
```
-#### `tool`
+#### `tool`
```python
tool(self, name_or_fn: str | AnyFunction | None = None) -> Callable[[AnyFunction], FunctionTool] | FunctionTool | partial[Callable[[AnyFunction], FunctionTool] | FunctionTool]
@@ -584,22 +619,22 @@ server.tool(my_function, name="custom_name")
```
-#### `add_resource`
+#### `add_resource`
```python
-add_resource(self, resource: Resource) -> Resource
+add_resource(self, resource: Resource | Callable[..., Any]) -> Resource | ResourceTemplate
```
Add a resource to the server.
**Args:**
-- `resource`: A Resource instance to add
+- `resource`: A Resource instance or @resource-decorated function to add
**Returns:**
- The resource instance that was added to the server.
-#### `add_template`
+#### `add_template`
```python
add_template(self, template: ResourceTemplate) -> ResourceTemplate
@@ -614,10 +649,10 @@ Add a resource template to the server.
- The template instance that was added to the server.
-#### `resource`
+#### `resource`
```python
-resource(self, uri: str) -> Callable[[AnyFunction], Resource | ResourceTemplate]
+resource(self, uri: str) -> Callable[[AnyFunction], Resource | ResourceTemplate | AnyFunction]
```
Decorator to register a function as a resource.
@@ -673,34 +708,34 @@ async def get_weather(city: str) -> str:
```
-#### `add_prompt`
+#### `add_prompt`
```python
-add_prompt(self, prompt: Prompt) -> Prompt
+add_prompt(self, prompt: Prompt | Callable[..., Any]) -> Prompt
```
Add a prompt to the server.
**Args:**
-- `prompt`: A Prompt instance to add
+- `prompt`: A Prompt instance or @prompt-decorated function to add
**Returns:**
- The prompt instance that was added to the server.
-#### `prompt`
+#### `prompt`
```python
prompt(self, name_or_fn: AnyFunction) -> FunctionPrompt
```
-#### `prompt`
+#### `prompt`
```python
prompt(self, name_or_fn: str | None = None) -> Callable[[AnyFunction], FunctionPrompt]
```
-#### `prompt`
+#### `prompt`
```python
prompt(self, name_or_fn: str | AnyFunction | None = None) -> Callable[[AnyFunction], FunctionPrompt] | FunctionPrompt | partial[Callable[[AnyFunction], FunctionPrompt] | FunctionPrompt]
@@ -777,7 +812,7 @@ Decorator to register a prompt.
```
-#### `run_stdio_async`
+#### `run_stdio_async`
```python
run_stdio_async(self, show_banner: bool = True, log_level: str | None = None, stateless: bool = False) -> None
@@ -791,7 +826,7 @@ Run the server using stdio transport.
- `stateless`: Whether to run in stateless mode (no session initialization)
-#### `run_http_async`
+#### `run_http_async`
```python
run_http_async(self, show_banner: bool = True, transport: Literal['http', 'streamable-http', 'sse'] = 'http', host: str | None = None, port: int | None = None, log_level: str | None = None, path: str | None = None, uvicorn_config: dict[str, Any] | None = None, middleware: list[ASGIMiddleware] | None = None, json_response: bool | None = None, stateless_http: bool | None = None, stateless: bool | None = None) -> None
@@ -812,7 +847,7 @@ Run the server using HTTP transport.
- `stateless`: Alias for stateless_http for CLI consistency
-#### `http_app`
+#### `http_app`
```python
http_app(self, path: str | None = None, middleware: list[ASGIMiddleware] | None = None, json_response: bool | None = None, stateless_http: bool | None = None, transport: Literal['http', 'streamable-http', 'sse'] = 'http', event_store: EventStore | None = None, retry_interval: int | None = None) -> StarletteWithLifespan
@@ -838,7 +873,7 @@ streamable-http transport.
- A Starlette application configured with the specified transport
-#### `mount`
+#### `mount`
```python
mount(self, server: FastMCP[LifespanResultT], namespace: str | None = None, as_proxy: bool | None = None, tool_names: dict[str, str] | None = None, prefix: str | None = None) -> None
@@ -885,7 +920,7 @@ mounted server.
- `prefix`: Deprecated. Use namespace instead.
-#### `import_server`
+#### `import_server`
```python
import_server(self, server: FastMCP[LifespanResultT], prefix: str | None = None) -> None
@@ -926,7 +961,7 @@ templates, and prompts are imported with their original names.
objects are imported with their original names.
-#### `from_openapi`
+#### `from_openapi`
```python
from_openapi(cls, openapi_spec: dict[str, Any], client: httpx.AsyncClient, 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, timeout: float | None = None, **settings: Any) -> Self
@@ -950,7 +985,7 @@ Create a FastMCP server from an OpenAPI specification.
- A FastMCP server with an OpenAPIProvider attached.
-#### `from_fastapi`
+#### `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, timeout: float | None = None, **settings: Any) -> Self
@@ -974,7 +1009,7 @@ Create a FastMCP server from a FastAPI application.
- A FastMCP server with an OpenAPIProvider attached.
-#### `as_proxy`
+#### `as_proxy`
```python
as_proxy(cls, backend: Client[ClientTransportT] | ClientTransport | FastMCP[Any] | FastMCP1Server | AnyUrl | Path | MCPConfig | dict[str, Any] | str, **settings: Any) -> FastMCPProxy
@@ -992,7 +1027,7 @@ instance or any value accepted as the `transport` argument of
`fastmcp.client.Client` constructor.
-#### `generate_name`
+#### `generate_name`
```python
generate_name(cls, name: str | None = None) -> str
diff --git a/docs/python-sdk/fastmcp-server-tasks-capabilities.mdx b/docs/python-sdk/fastmcp-server-tasks-capabilities.mdx
index 6b8c78e3e1..77c1467d37 100644
--- a/docs/python-sdk/fastmcp-server-tasks-capabilities.mdx
+++ b/docs/python-sdk/fastmcp-server-tasks-capabilities.mdx
@@ -10,15 +10,20 @@ SEP-1686 task capabilities declaration.
## Functions
-### `get_task_capabilities`
+### `get_task_capabilities`
```python
-get_task_capabilities() -> dict[str, Any]
+get_task_capabilities() -> ServerTasksCapability | None
```
-Return the SEP-1686 task capabilities structure.
+Return the SEP-1686 task capabilities.
-This is the standard capabilities map advertised to clients,
-declaring support for list, cancel, and request operations.
+Returns task capabilities as a first-class ServerCapabilities field,
+declaring support for list, cancel, and request operations per SEP-1686.
+
+Returns None if pydocket is not installed (no task support).
+
+Note: prompts/resources are passed via extra_data since the SDK types
+don't include them yet (FastMCP supports them ahead of the spec).
diff --git a/docs/python-sdk/fastmcp-server-tasks-config.mdx b/docs/python-sdk/fastmcp-server-tasks-config.mdx
index 129fe896c2..2dbbc63dd0 100644
--- a/docs/python-sdk/fastmcp-server-tasks-config.mdx
+++ b/docs/python-sdk/fastmcp-server-tasks-config.mdx
@@ -14,7 +14,7 @@ handle task-augmented execution as specified in SEP-1686.
## Classes
-### `TaskMeta`
+### `TaskMeta`
Metadata for task-augmented execution requests.
@@ -27,7 +27,7 @@ the operation should be submitted as a background task.
- `fn_key`: Docket routing key. Auto-derived from component name if None.
-### `TaskConfig`
+### `TaskConfig`
Configuration for MCP background task execution (SEP-1686).
@@ -44,7 +44,7 @@ Controls how a component handles task-augmented requests:
**Methods:**
-#### `from_bool`
+#### `from_bool`
```python
from_bool(cls, value: bool) -> TaskConfig
@@ -59,7 +59,7 @@ Convert boolean task flag to TaskConfig.
- TaskConfig with appropriate mode.
-#### `supports_tasks`
+#### `supports_tasks`
```python
supports_tasks(self) -> bool
@@ -71,7 +71,7 @@ Check if this component supports task execution.
- True if mode is "optional" or "required", False if "forbidden".
-#### `validate_function`
+#### `validate_function`
```python
validate_function(self, fn: Callable[..., Any], name: str) -> None
@@ -79,13 +79,18 @@ validate_function(self, fn: Callable[..., Any], name: str) -> None
Validate that function is compatible with this task config.
-Task execution requires async functions. Raises ValueError if mode
-is "optional" or "required" but function is synchronous.
+Task execution requires:
+1. fastmcp[tasks] to be installed (pydocket)
+2. Async functions
+
+Raises ImportError if mode is "optional" or "required" but pydocket
+is not installed. Raises ValueError if function is synchronous.
**Args:**
- `fn`: The function to validate (handles callable classes and staticmethods).
- `name`: Name for error messages.
**Raises:**
+- `ImportError`: If task execution is enabled but pydocket not installed.
- `ValueError`: If task execution is enabled but function is sync.
diff --git a/docs/python-sdk/fastmcp-server-tasks-requests.mdx b/docs/python-sdk/fastmcp-server-tasks-requests.mdx
index 75fe1ca676..50f77596ac 100644
--- a/docs/python-sdk/fastmcp-server-tasks-requests.mdx
+++ b/docs/python-sdk/fastmcp-server-tasks-requests.mdx
@@ -11,10 +11,12 @@ SEP-1686 task request handlers.
Handles MCP task protocol requests: tasks/get, tasks/result, tasks/list, tasks/cancel.
These handlers query and manage existing tasks (contrast with handlers.py which creates tasks).
+This module requires fastmcp[tasks] (pydocket). It is only imported when docket is available.
+
## Functions
-### `tasks_get_handler`
+### `tasks_get_handler`
```python
tasks_get_handler(server: FastMCP, params: dict[str, Any]) -> GetTaskResult
@@ -31,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
@@ -50,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
@@ -69,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
diff --git a/docs/python-sdk/fastmcp-server-tasks-subscriptions.mdx b/docs/python-sdk/fastmcp-server-tasks-subscriptions.mdx
index 1b4331212f..1b611ea9c7 100644
--- a/docs/python-sdk/fastmcp-server-tasks-subscriptions.mdx
+++ b/docs/python-sdk/fastmcp-server-tasks-subscriptions.mdx
@@ -11,10 +11,12 @@ Task subscription helpers for sending MCP notifications (SEP-1686).
Subscribes to Docket execution state changes and sends notifications/tasks/status
to clients when their tasks change state.
+This module requires fastmcp[tasks] (pydocket). It is only imported when docket is available.
+
## Functions
-### `subscribe_to_task_updates`
+### `subscribe_to_task_updates`
```python
subscribe_to_task_updates(task_id: str, task_key: str, session: ServerSession, docket: Docket, poll_interval_ms: int = 5000) -> None
diff --git a/docs/python-sdk/fastmcp-server-telemetry.mdx b/docs/python-sdk/fastmcp-server-telemetry.mdx
new file mode 100644
index 0000000000..a842c468d0
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-telemetry.mdx
@@ -0,0 +1,56 @@
+---
+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.
+
+
+### `server_span`
+
+```python
+server_span(name: str, method: str, server_name: str, component_type: str, component_key: str, resource_uri: str | None = None) -> Generator[Span, None, None]
+```
+
+
+Create a SERVER span with standard MCP attributes and auth context.
+
+Automatically records any exception on the span and sets error status.
+
+
+### `delegate_span`
+
+```python
+delegate_span(name: str, provider_type: str, component_key: str) -> 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-__init__.mdx b/docs/python-sdk/fastmcp-server-transforms-__init__.mdx
new file mode 100644
index 0000000000..6b7e5db176
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-transforms-__init__.mdx
@@ -0,0 +1,196 @@
+---
+title: __init__
+sidebarTitle: __init__
+---
+
+# `fastmcp.server.transforms`
+
+
+Transform system for component transformations.
+
+Transforms modify components (tools, resources, prompts) using a middleware pattern.
+Each transform wraps the next in the chain via `call_next`, allowing transforms to
+intercept, modify, or replace component queries.
+
+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.
+
+Transforms use a middleware pattern with `call_next` to chain operations.
+Each transform can intercept, modify, or pass through component queries.
+
+For list operations, call `call_next()` to get components from downstream,
+then transform the result. For get operations, optionally transform the
+name/uri before calling `call_next`, then transform the result.
+
+
+**Methods:**
+
+#### `list_tools`
+
+```python
+list_tools(self, call_next: ListToolsNext) -> Sequence[Tool]
+```
+
+List tools with transformation applied.
+
+**Args:**
+- `call_next`: Callable to get tools from downstream transforms/provider.
+
+**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, call_next: ListResourcesNext) -> Sequence[Resource]
+```
+
+List resources with transformation applied.
+
+**Args:**
+- `call_next`: Callable to get resources from downstream transforms/provider.
+
+**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, call_next: ListResourceTemplatesNext) -> Sequence[ResourceTemplate]
+```
+
+List resource templates with transformation applied.
+
+**Args:**
+- `call_next`: Callable to get templates from downstream transforms/provider.
+
+**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, call_next: ListPromptsNext) -> Sequence[Prompt]
+```
+
+List prompts with transformation applied.
+
+**Args:**
+- `call_next`: Callable to get prompts from downstream transforms/provider.
+
+**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-server-transforms-namespace.mdx b/docs/python-sdk/fastmcp-server-transforms-namespace.mdx
new file mode 100644
index 0000000000..0260e3a2e0
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-transforms-namespace.mdx
@@ -0,0 +1,96 @@
+---
+title: namespace
+sidebarTitle: namespace
+---
+
+# `fastmcp.server.transforms.namespace`
+
+
+Namespace transform for prefixing component names.
+
+## Classes
+
+### `Namespace`
+
+
+Prefixes component names with a namespace.
+
+- Tools: name → namespace_name
+- Prompts: name → namespace_name
+- Resources: protocol://path → protocol://namespace/path
+- Resource Templates: same as resources
+
+
+**Methods:**
+
+#### `list_tools`
+
+```python
+list_tools(self, call_next: ListToolsNext) -> Sequence[Tool]
+```
+
+Prefix tool names with namespace.
+
+
+#### `get_tool`
+
+```python
+get_tool(self, name: str, call_next: GetToolNext) -> Tool | None
+```
+
+Get tool by namespaced name.
+
+
+#### `list_resources`
+
+```python
+list_resources(self, call_next: ListResourcesNext) -> Sequence[Resource]
+```
+
+Add namespace path segment to resource URIs.
+
+
+#### `get_resource`
+
+```python
+get_resource(self, uri: str, call_next: GetResourceNext) -> Resource | None
+```
+
+Get resource by namespaced URI.
+
+
+#### `list_resource_templates`
+
+```python
+list_resource_templates(self, call_next: ListResourceTemplatesNext) -> Sequence[ResourceTemplate]
+```
+
+Add namespace path segment to template URIs.
+
+
+#### `get_resource_template`
+
+```python
+get_resource_template(self, uri: str, call_next: GetResourceTemplateNext) -> ResourceTemplate | None
+```
+
+Get resource template by namespaced URI.
+
+
+#### `list_prompts`
+
+```python
+list_prompts(self, call_next: ListPromptsNext) -> Sequence[Prompt]
+```
+
+Prefix prompt names with namespace.
+
+
+#### `get_prompt`
+
+```python
+get_prompt(self, name: str, call_next: GetPromptNext) -> Prompt | None
+```
+
+Get prompt by namespaced name.
+
diff --git a/docs/python-sdk/fastmcp-server-transforms-tool_transform.mdx b/docs/python-sdk/fastmcp-server-transforms-tool_transform.mdx
new file mode 100644
index 0000000000..417e18f778
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-transforms-tool_transform.mdx
@@ -0,0 +1,40 @@
+---
+title: tool_transform
+sidebarTitle: tool_transform
+---
+
+# `fastmcp.server.transforms.tool_transform`
+
+
+Transform for applying tool transformations.
+
+## Classes
+
+### `ToolTransform`
+
+
+Applies tool transformations to modify tool schemas.
+
+Wraps ToolTransformConfig to apply argument renames, schema changes,
+hidden arguments, and other transformations at the transform level.
+
+
+**Methods:**
+
+#### `list_tools`
+
+```python
+list_tools(self, call_next: ListToolsNext) -> Sequence[Tool]
+```
+
+Apply transforms to matching tools.
+
+
+#### `get_tool`
+
+```python
+get_tool(self, name: str, call_next: GetToolNext) -> Tool | None
+```
+
+Get tool by transformed name.
+
diff --git a/docs/python-sdk/fastmcp-server-transforms-version_filter.mdx b/docs/python-sdk/fastmcp-server-transforms-version_filter.mdx
new file mode 100644
index 0000000000..7a2e434312
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-transforms-version_filter.mdx
@@ -0,0 +1,85 @@
+---
+title: version_filter
+sidebarTitle: version_filter
+---
+
+# `fastmcp.server.transforms.version_filter`
+
+
+Version filter transform for filtering components by version range.
+
+## Classes
+
+### `VersionFilter`
+
+
+Filters components by version range.
+
+When applied to a provider or server, only components within the version
+range are visible. Within that filtered set, the highest version of each
+component is exposed to clients (standard deduplication behavior).
+
+Parameters mirror comparison operators for clarity:
+
+ # Versions < 3.0 (v1 and v2)
+ server.add_transform(VersionFilter(version_lt="3.0"))
+
+ # Versions >= 2.0 and < 3.0 (only v2.x)
+ server.add_transform(VersionFilter(version_gte="2.0", version_lt="3.0"))
+
+Works with any version string - PEP 440 (1.0, 2.0) or dates (2025-01-01).
+
+**Args:**
+- `version_gte`: Versions >= this value pass through.
+- `version_lt`: Versions < this value pass through.
+
+
+**Methods:**
+
+#### `list_tools`
+
+```python
+list_tools(self, call_next: ListToolsNext) -> Sequence[Tool]
+```
+
+#### `get_tool`
+
+```python
+get_tool(self, name: str, call_next: GetToolNext) -> Tool | None
+```
+
+#### `list_resources`
+
+```python
+list_resources(self, call_next: ListResourcesNext) -> Sequence[Resource]
+```
+
+#### `get_resource`
+
+```python
+get_resource(self, uri: str, call_next: GetResourceNext) -> Resource | None
+```
+
+#### `list_resource_templates`
+
+```python
+list_resource_templates(self, call_next: ListResourceTemplatesNext) -> Sequence[ResourceTemplate]
+```
+
+#### `get_resource_template`
+
+```python
+get_resource_template(self, uri: str, call_next: GetResourceTemplateNext) -> ResourceTemplate | None
+```
+
+#### `list_prompts`
+
+```python
+list_prompts(self, call_next: ListPromptsNext) -> Sequence[Prompt]
+```
+
+#### `get_prompt`
+
+```python
+get_prompt(self, name: str, call_next: GetPromptNext) -> Prompt | None
+```
diff --git a/docs/python-sdk/fastmcp-server-transforms-visibility.mdx b/docs/python-sdk/fastmcp-server-transforms-visibility.mdx
new file mode 100644
index 0000000000..25ef0478d1
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-transforms-visibility.mdx
@@ -0,0 +1,158 @@
+---
+title: visibility
+sidebarTitle: visibility
+---
+
+# `fastmcp.server.transforms.visibility`
+
+
+Visibility transform for filtering components based on enable/disable settings.
+
+This module provides the `Visibility` class which manages component visibility
+with blocklist and allowlist support. Components can be hidden by key or tag,
+and the visibility state is mutable - changes take effect on subsequent queries.
+
+
+## Classes
+
+### `Visibility`
+
+
+Filters components based on visibility settings.
+
+Manages blocklist and allowlist logic for controlling component visibility.
+Both servers and providers use this class. Visibility is hierarchical: if a
+component is hidden at any level (provider or server), it's hidden to the client.
+
+Filtering logic (blocklist wins over allowlist):
+1. If component key is in _disabled_keys → HIDDEN
+2. If any component tag is in _disabled_tags → HIDDEN
+3. If _default_enabled is False and component not in allowlist → HIDDEN
+4. Otherwise → VISIBLE
+
+The `only=True` flag on enable() switches to allowlist mode:
+- Sets _default_enabled = False
+- Clears existing allowlists
+- Adds specified keys/tags to allowlist
+
+
+**Methods:**
+
+#### `disable`
+
+```python
+disable(self) -> None
+```
+
+Add to blocklist (hide components).
+
+**Args:**
+- `keys`: Component keys to hide (e.g., "tool\:my_tool@", "resource\:file\://x@")
+- `tags`: Tags to hide - any component with these tags will be hidden
+
+
+#### `enable`
+
+```python
+enable(self) -> None
+```
+
+Remove from blocklist, or set allowlist with only=True.
+
+**Args:**
+- `keys`: Component keys to show
+- `tags`: Tags to show
+- `only`: If True, switches to allowlist mode - ONLY show these keys/tags.
+This sets default visibility to False, clears existing allowlists,
+and adds the specified keys/tags to the allowlist.
+
+
+#### `reset`
+
+```python
+reset(self) -> None
+```
+
+Reset to default state (everything enabled, no filters).
+
+
+#### `is_enabled`
+
+```python
+is_enabled(self, component: FastMCPComponent) -> bool
+```
+
+Check if component is enabled. Blocklist wins over allowlist.
+
+
+#### `list_tools`
+
+```python
+list_tools(self, call_next: ListToolsNext) -> Sequence[Tool]
+```
+
+Filter tools by visibility.
+
+
+#### `get_tool`
+
+```python
+get_tool(self, name: str, call_next: GetToolNext) -> Tool | None
+```
+
+Get tool if enabled, None otherwise.
+
+
+#### `list_resources`
+
+```python
+list_resources(self, call_next: ListResourcesNext) -> Sequence[Resource]
+```
+
+Filter resources by visibility.
+
+
+#### `get_resource`
+
+```python
+get_resource(self, uri: str, call_next: GetResourceNext) -> Resource | None
+```
+
+Get resource if enabled, None otherwise.
+
+
+#### `list_resource_templates`
+
+```python
+list_resource_templates(self, call_next: ListResourceTemplatesNext) -> Sequence[ResourceTemplate]
+```
+
+Filter resource templates by visibility.
+
+
+#### `get_resource_template`
+
+```python
+get_resource_template(self, uri: str, call_next: GetResourceTemplateNext) -> ResourceTemplate | None
+```
+
+Get resource template if enabled, None otherwise.
+
+
+#### `list_prompts`
+
+```python
+list_prompts(self, call_next: ListPromptsNext) -> Sequence[Prompt]
+```
+
+Filter prompts by visibility.
+
+
+#### `get_prompt`
+
+```python
+get_prompt(self, name: str, call_next: GetPromptNext) -> Prompt | None
+```
+
+Get prompt if enabled, None otherwise.
+
diff --git a/docs/python-sdk/fastmcp-telemetry.mdx b/docs/python-sdk/fastmcp-telemetry.mdx
new file mode 100644
index 0000000000..805e9940d9
--- /dev/null
+++ b/docs/python-sdk/fastmcp-telemetry.mdx
@@ -0,0 +1,95 @@
+---
+title: telemetry
+sidebarTitle: telemetry
+---
+
+# `fastmcp.telemetry`
+
+
+OpenTelemetry instrumentation for FastMCP.
+
+This module provides native OpenTelemetry integration for FastMCP servers and clients.
+It uses only the opentelemetry-api package, so telemetry is a no-op unless the user
+installs an OpenTelemetry SDK and configures exporters.
+
+Example usage with SDK:
+ ```python
+ from opentelemetry import trace
+ from opentelemetry.sdk.trace import TracerProvider
+ from opentelemetry.sdk.trace.export import ConsoleSpanExporter, SimpleSpanProcessor
+
+ # Configure the SDK (user responsibility)
+ provider = TracerProvider()
+ provider.add_span_processor(SimpleSpanProcessor(ConsoleSpanExporter()))
+ trace.set_tracer_provider(provider)
+
+ # Now FastMCP will emit traces
+ from fastmcp import FastMCP
+ mcp = FastMCP("my-server")
+ ```
+
+
+## Functions
+
+### `get_tracer`
+
+```python
+get_tracer(version: str | None = None) -> Tracer
+```
+
+
+Get the FastMCP tracer for creating spans.
+
+**Args:**
+- `version`: Optional version string for the instrumentation
+
+**Returns:**
+- A tracer instance. Returns a no-op tracer if no SDK is configured.
+
+
+### `inject_trace_context`
+
+```python
+inject_trace_context(meta: dict[str, Any] | None = None) -> dict[str, Any] | None
+```
+
+
+Inject current trace context into a meta dict for MCP request propagation.
+
+**Args:**
+- `meta`: Optional existing meta dict to merge with trace context
+
+**Returns:**
+- A new dict containing the original meta (if any) plus trace context keys,
+- or None if no trace context to inject and meta was None
+
+
+### `record_span_error`
+
+```python
+record_span_error(span: Span, exception: BaseException) -> None
+```
+
+
+Record an exception on a span and set error status.
+
+
+### `extract_trace_context`
+
+```python
+extract_trace_context(meta: dict[str, Any] | None) -> Context
+```
+
+
+Extract trace context from an MCP request meta dict.
+
+If already in a valid trace (e.g., from HTTP propagation), the existing
+trace context is preserved and meta is not used.
+
+**Args:**
+- `meta`: The meta dict from an MCP request (ctx.request_context.meta)
+
+**Returns:**
+- An OpenTelemetry Context with the extracted trace context,
+- or the current context if no trace context found or already in a trace
+
diff --git a/docs/python-sdk/fastmcp-tools-function_parsing.mdx b/docs/python-sdk/fastmcp-tools-function_parsing.mdx
new file mode 100644
index 0000000000..2f69d15482
--- /dev/null
+++ b/docs/python-sdk/fastmcp-tools-function_parsing.mdx
@@ -0,0 +1,21 @@
+---
+title: function_parsing
+sidebarTitle: function_parsing
+---
+
+# `fastmcp.tools.function_parsing`
+
+
+Function introspection and schema generation for FastMCP tools.
+
+## Classes
+
+### `ParsedFunction`
+
+**Methods:**
+
+#### `from_function`
+
+```python
+from_function(cls, fn: Callable[..., Any], exclude_args: list[str] | None = None, validate: bool = True, wrap_non_object_output_schema: bool = True) -> ParsedFunction
+```
diff --git a/docs/python-sdk/fastmcp-tools-function_tool.mdx b/docs/python-sdk/fastmcp-tools-function_tool.mdx
new file mode 100644
index 0000000000..b9bd0e7da2
--- /dev/null
+++ b/docs/python-sdk/fastmcp-tools-function_tool.mdx
@@ -0,0 +1,108 @@
+---
+title: function_tool
+sidebarTitle: function_tool
+---
+
+# `fastmcp.tools.function_tool`
+
+
+Standalone @tool decorator for FastMCP.
+
+## Functions
+
+### `tool`
+
+```python
+tool(name_or_fn: str | Callable[..., Any] | None = None) -> Any
+```
+
+
+Standalone decorator to mark a function as an MCP tool.
+
+Returns the original function with metadata attached. Register with a server
+using mcp.add_tool().
+
+
+## Classes
+
+### `DecoratedTool`
+
+
+Protocol for functions decorated with @tool.
+
+
+### `ToolMeta`
+
+
+Metadata attached to functions by the @tool decorator.
+
+
+### `FunctionTool`
+
+**Methods:**
+
+#### `to_mcp_tool`
+
+```python
+to_mcp_tool(self, **overrides: Any) -> mcp.types.Tool
+```
+
+Convert the FastMCP tool to an MCP tool.
+
+Extends the base implementation to add task execution mode if enabled.
+
+
+#### `from_function`
+
+```python
+from_function(cls, fn: Callable[..., Any]) -> FunctionTool
+```
+
+Create a FunctionTool from a function.
+
+**Args:**
+- `fn`: The function to wrap
+- `metadata`: ToolMeta object with all configuration. If provided,
+individual parameters must not be passed.
+- `name, title, etc.`: Individual parameters for backwards compatibility.
+Cannot be used together with metadata parameter.
+
+
+#### `run`
+
+```python
+run(self, arguments: dict[str, Any]) -> ToolResult
+```
+
+Run the tool with arguments.
+
+
+#### `register_with_docket`
+
+```python
+register_with_docket(self, docket: Docket) -> None
+```
+
+Register this tool with docket for background execution.
+
+FunctionTool registers the underlying function, which has the user's
+Depends parameters for docket to resolve.
+
+
+#### `add_to_docket`
+
+```python
+add_to_docket(self, docket: Docket, arguments: dict[str, Any], **kwargs: Any) -> Execution
+```
+
+Schedule this tool for background execution via docket.
+
+FunctionTool splats the arguments dict since .fn expects **kwargs.
+
+**Args:**
+- `docket`: The Docket instance
+- `arguments`: Tool arguments
+- `fn_key`: Function lookup key in Docket registry (defaults to self.key)
+- `task_key`: Redis storage key for the result
+- `**kwargs`: Additional kwargs passed to docket.add()
+
diff --git a/docs/python-sdk/fastmcp-tools-tool.mdx b/docs/python-sdk/fastmcp-tools-tool.mdx
index c5e5e1c3a3..9acb156951 100644
--- a/docs/python-sdk/fastmcp-tools-tool.mdx
+++ b/docs/python-sdk/fastmcp-tools-tool.mdx
@@ -7,7 +7,7 @@ sidebarTitle: tool
## Functions
-### `default_serializer`
+### `default_serializer`
```python
default_serializer(data: Any) -> str
@@ -15,17 +15,17 @@ default_serializer(data: Any) -> str
## Classes
-### `ToolResult`
+### `ToolResult`
**Methods:**
-#### `to_mcp_result`
+#### `to_mcp_result`
```python
to_mcp_result(self) -> list[ContentBlock] | tuple[list[ContentBlock], dict[str, Any]] | CallToolResult
```
-### `Tool`
+### `Tool`
Internal tool registration info.
@@ -33,7 +33,7 @@ Internal tool registration info.
**Methods:**
-#### `to_mcp_tool`
+#### `to_mcp_tool`
```python
to_mcp_tool(self, **overrides: Any) -> MCPTool
@@ -42,16 +42,16 @@ to_mcp_tool(self, **overrides: Any) -> MCPTool
Convert the FastMCP tool to an MCP tool.
-#### `from_function`
+#### `from_function`
```python
-from_function(fn: Callable[..., Any], name: str | None = None, title: str | None = None, description: str | None = None, icons: list[Icon] | None = None, tags: set[str] | None = None, annotations: ToolAnnotations | None = None, exclude_args: list[str] | None = None, output_schema: dict[str, Any] | NotSetT | None = NotSet, serializer: ToolResultSerializerType | None = None, meta: dict[str, Any] | None = None, task: bool | TaskConfig | None = None) -> FunctionTool
+from_function(cls, fn: Callable[..., Any]) -> FunctionTool
```
Create a Tool from a function.
-#### `run`
+#### `run`
```python
run(self, arguments: dict[str, Any]) -> ToolResult
@@ -66,7 +66,7 @@ implemented by subclasses.
(list of ContentBlocks, dict of structured output).
-#### `convert_result`
+#### `convert_result`
```python
convert_result(self, raw_value: Any) -> ToolResult
@@ -78,7 +78,7 @@ Handles ToolResult passthrough and converts raw values using the tool's
attributes (serializer, output_schema) for proper conversion.
-#### `register_with_docket`
+#### `register_with_docket`
```python
register_with_docket(self, docket: Docket) -> None
@@ -87,7 +87,7 @@ register_with_docket(self, docket: Docket) -> None
Register this tool with docket for background execution.
-#### `add_to_docket`
+#### `add_to_docket`
```python
add_to_docket(self, docket: Docket, arguments: dict[str, Any], **kwargs: Any) -> Execution
@@ -103,81 +103,14 @@ Schedule this tool for background execution via docket.
- `**kwargs`: Additional kwargs passed to docket.add()
-#### `from_tool`
+#### `from_tool`
```python
from_tool(cls, tool: Tool) -> TransformedTool
```
-### `FunctionTool`
-
-**Methods:**
-
-#### `to_mcp_tool`
-
-```python
-to_mcp_tool(self, **overrides: Any) -> MCPTool
-```
-
-Convert the FastMCP tool to an MCP tool.
-
-Extends the base implementation to add task execution mode if enabled.
-
-
-#### `from_function`
-
-```python
-from_function(cls, fn: Callable[..., Any], name: str | None = None, title: str | None = None, description: str | None = None, icons: list[Icon] | None = None, tags: set[str] | None = None, annotations: ToolAnnotations | None = None, exclude_args: list[str] | None = None, output_schema: dict[str, Any] | NotSetT | None = NotSet, serializer: ToolResultSerializerType | None = None, meta: dict[str, Any] | None = None, task: bool | TaskConfig | None = None) -> FunctionTool
-```
-
-Create a Tool from a function.
-
-
-#### `run`
-
-```python
-run(self, arguments: dict[str, Any]) -> ToolResult
-```
-
-Run the tool with arguments.
-
-
-#### `register_with_docket`
-
-```python
-register_with_docket(self, docket: Docket) -> None
-```
-
-Register this tool with docket for background execution.
-
-FunctionTool registers the underlying function, which has the user's
-Depends parameters for docket to resolve.
-
-
-#### `add_to_docket`
-
-```python
-add_to_docket(self, docket: Docket, arguments: dict[str, Any], **kwargs: Any) -> Execution
-```
-
-Schedule this tool for background execution via docket.
-
-FunctionTool splats the arguments dict since .fn expects **kwargs.
-
-**Args:**
-- `docket`: The Docket instance
-- `arguments`: Tool arguments
-- `fn_key`: Function lookup key in Docket registry (defaults to self.key)
-- `task_key`: Redis storage key for the result
-- `**kwargs`: Additional kwargs passed to docket.add()
-
-
-### `ParsedFunction`
-
-**Methods:**
-
-#### `from_function`
+#### `get_span_attributes`
```python
-from_function(cls, fn: Callable[..., Any], exclude_args: list[str] | None = None, validate: bool = True, wrap_non_object_output_schema: bool = True) -> ParsedFunction
+get_span_attributes(self) -> dict[str, Any]
```
diff --git a/docs/python-sdk/fastmcp-tools-tool_transform.mdx b/docs/python-sdk/fastmcp-tools-tool_transform.mdx
index 0288596ac2..052ab71921 100644
--- a/docs/python-sdk/fastmcp-tools-tool_transform.mdx
+++ b/docs/python-sdk/fastmcp-tools-tool_transform.mdx
@@ -7,7 +7,7 @@ sidebarTitle: tool_transform
## Functions
-### `forward`
+### `forward`
```python
forward(**kwargs: Any) -> ToolResult
@@ -36,7 +36,7 @@ tool has args `a` and `b`, and an `transform_args` was provided that maps `x` to
- `TypeError`: If provided arguments don't match the transformed schema.
-### `forward_raw`
+### `forward_raw`
```python
forward_raw(**kwargs: Any) -> ToolResult
@@ -62,7 +62,7 @@ y=2)` will call the parent tool with `x=1` and `y=2`.
- `RuntimeError`: If called outside a transformed tool context.
-### `apply_transformations_to_tools`
+### `apply_transformations_to_tools`
```python
apply_transformations_to_tools(tools: dict[str, Tool], transformations: dict[str, ToolTransformConfig]) -> dict[str, Tool]
@@ -78,7 +78,7 @@ but transformations are keyed by tool name (e.g., "my_tool").
## Classes
-### `ArgTransform`
+### `ArgTransform`
Configuration for transforming a parent tool's argument.
@@ -150,7 +150,7 @@ ArgTransform(name="new_name", description="New desc", default=None, type=int)
```
-### `ArgTransformConfig`
+### `ArgTransformConfig`
A model for requesting a single argument transform.
@@ -158,7 +158,7 @@ A model for requesting a single argument transform.
**Methods:**
-#### `to_arg_transform`
+#### `to_arg_transform`
```python
to_arg_transform(self) -> ArgTransform
@@ -167,7 +167,7 @@ to_arg_transform(self) -> ArgTransform
Convert the argument transform to a FastMCP argument transform.
-### `TransformedTool`
+### `TransformedTool`
A tool that is transformed from another tool.
@@ -191,7 +191,7 @@ validation when forward() is called from custom functions.
**Methods:**
-#### `run`
+#### `run`
```python
run(self, arguments: dict[str, Any]) -> ToolResult
@@ -210,10 +210,10 @@ functions.
- ToolResult object containing content and optional structured output.
-#### `from_tool`
+#### `from_tool`
```python
-from_tool(cls, tool: Tool, name: str | None = None, title: str | NotSetT | None = NotSet, description: str | NotSetT | None = NotSet, tags: set[str] | None = None, transform_fn: Callable[..., Any] | None = None, transform_args: dict[str, ArgTransform] | None = None, annotations: ToolAnnotations | NotSetT | None = NotSet, output_schema: dict[str, Any] | NotSetT | None = NotSet, serializer: Callable[[Any], str] | NotSetT | None = NotSet, meta: dict[str, Any] | NotSetT | None = NotSet) -> TransformedTool
+from_tool(cls, tool: Tool, name: str | None = None, version: str | NotSetT | None = NotSet, title: str | NotSetT | None = NotSet, description: str | NotSetT | None = NotSet, tags: set[str] | None = None, transform_fn: Callable[..., Any] | None = None, transform_args: dict[str, ArgTransform] | None = None, annotations: ToolAnnotations | NotSetT | None = NotSet, output_schema: dict[str, Any] | NotSetT | None = NotSet, serializer: Callable[[Any], str] | NotSetT | None = NotSet, meta: dict[str, Any] | NotSetT | None = NotSet) -> TransformedTool
```
Create a transformed tool from a parent tool.
@@ -224,6 +224,7 @@ Create a transformed tool from a parent tool.
to call the parent tool. Functions with **kwargs receive transformed
argument names.
- `name`: New name for the tool. Defaults to parent tool's name.
+- `version`: New version for the tool. Defaults to parent tool's version.
- `title`: New title for the tool. Defaults to parent tool's title.
- `transform_args`: Optional transformations for parent tool arguments.
Only specified arguments are transformed, others pass through unchanged\:
@@ -292,7 +293,7 @@ async def custom_output(**kwargs) -> ToolResult:
```
-### `ToolTransformConfig`
+### `ToolTransformConfig`
Provides a way to transform a tool.
@@ -300,7 +301,7 @@ Provides a way to transform a tool.
**Methods:**
-#### `apply`
+#### `apply`
```python
apply(self, tool: Tool) -> TransformedTool
diff --git a/docs/python-sdk/fastmcp-utilities-async_utils.mdx b/docs/python-sdk/fastmcp-utilities-async_utils.mdx
index 7a44351b66..f5f24019f1 100644
--- a/docs/python-sdk/fastmcp-utilities-async_utils.mdx
+++ b/docs/python-sdk/fastmcp-utilities-async_utils.mdx
@@ -10,7 +10,20 @@ Async utilities for FastMCP.
## Functions
-### `gather`
+### `call_sync_fn_in_threadpool`
+
+```python
+call_sync_fn_in_threadpool(fn: Callable[..., Any], *args: Any, **kwargs: Any) -> Any
+```
+
+
+Call a sync function in a threadpool to avoid blocking the event loop.
+
+Uses anyio.to_thread.run_sync which properly propagates contextvars,
+making this safe for functions that depend on context (like dependency injection).
+
+
+### `gather`
```python
gather(*awaitables: Awaitable[T]) -> list[T] | list[T | BaseException]
diff --git a/docs/python-sdk/fastmcp-utilities-cli.mdx b/docs/python-sdk/fastmcp-utilities-cli.mdx
index 2eb7922209..455655637e 100644
--- a/docs/python-sdk/fastmcp-utilities-cli.mdx
+++ b/docs/python-sdk/fastmcp-utilities-cli.mdx
@@ -7,7 +7,7 @@ sidebarTitle: cli
## Functions
-### `is_already_in_uv_subprocess`
+### `is_already_in_uv_subprocess`
```python
is_already_in_uv_subprocess() -> bool
@@ -17,7 +17,7 @@ is_already_in_uv_subprocess() -> bool
Check if we're already running in a FastMCP uv subprocess.
-### `load_and_merge_config`
+### `load_and_merge_config`
```python
load_and_merge_config(server_spec: str | None, **cli_overrides) -> tuple[MCPServerConfig, str]
@@ -37,7 +37,7 @@ run, inspect, and dev commands.
- Tuple of (MCPServerConfig, resolved_server_spec)
-### `log_server_banner`
+### `log_server_banner`
```python
log_server_banner(server: FastMCP[Any]) -> None
diff --git a/docs/python-sdk/fastmcp-utilities-components.mdx b/docs/python-sdk/fastmcp-utilities-components.mdx
index 08879acdf0..c1d9481b85 100644
--- a/docs/python-sdk/fastmcp-utilities-components.mdx
+++ b/docs/python-sdk/fastmcp-utilities-components.mdx
@@ -5,11 +5,26 @@ sidebarTitle: components
# `fastmcp.utilities.components`
+## Functions
+
+### `get_fastmcp_metadata`
+
+```python
+get_fastmcp_metadata(meta: dict[str, Any] | None) -> FastMCPMeta
+```
+
+
+Extract FastMCP metadata from a component's meta dict.
+
+Handles both the current `fastmcp` namespace and the legacy `_fastmcp`
+namespace for compatibility with older FastMCP servers.
+
+
## Classes
-### `FastMCPMeta`
+### `FastMCPMeta`
-### `FastMCPComponent`
+### `FastMCPComponent`
Base class for FastMCP tools, prompts, resources, and resource templates.
@@ -17,7 +32,7 @@ Base class for FastMCP tools, prompts, resources, and resource templates.
**Methods:**
-#### `make_key`
+#### `make_key`
```python
make_key(cls, identifier: str) -> str
@@ -32,7 +47,7 @@ Construct the lookup key for this component type.
- A prefixed key like "tool:name" or "resource:uri"
-#### `key`
+#### `key`
```python
key(self) -> str
@@ -40,25 +55,30 @@ key(self) -> str
The globally unique lookup key for this component.
-Format: "{key_prefix}:{identifier}" e.g. "tool:my_tool", "resource:file://x.txt"
+Format: "{key_prefix}:{identifier}@{version}" or "{key_prefix}:{identifier}@"
+e.g. "tool:my_tool@v2", "tool:my_tool@", "resource:file://x.txt@"
+
+The @ suffix is ALWAYS present to enable unambiguous parsing of keys
+(URIs may contain @ characters, so we always include the delimiter).
Subclasses should override this to use their specific identifier.
Base implementation uses name.
-#### `get_meta`
+#### `get_meta`
```python
-get_meta(self, include_fastmcp_meta: bool | None = None) -> dict[str, Any] | None
+get_meta(self) -> dict[str, Any]
```
Get the meta information about the component.
-If include_fastmcp_meta is True, a `_fastmcp` key will be added to the
-meta, containing a `tags` field with the tags of the component.
+Returns a dict that always includes a `fastmcp` key containing:
+- `tags`: sorted list of component tags
+- `version`: component version (only if set)
-#### `enable`
+#### `enable`
```python
enable(self) -> None
@@ -67,7 +87,7 @@ enable(self) -> None
Removed in 3.0. Use server.enable(keys=[...]) instead.
-#### `disable`
+#### `disable`
```python
disable(self) -> None
@@ -76,7 +96,7 @@ disable(self) -> None
Removed in 3.0. Use server.disable(keys=[...]) instead.
-#### `copy`
+#### `copy`
```python
copy(self) -> Self
@@ -85,7 +105,7 @@ copy(self) -> Self
Create a copy of the component.
-#### `register_with_docket`
+#### `register_with_docket`
```python
register_with_docket(self, docket: Docket) -> None
@@ -97,7 +117,7 @@ No-ops if task_config.mode is "forbidden". Subclasses override to
register their callable (self.run, self.read, self.render, or self.fn).
-#### `add_to_docket`
+#### `add_to_docket`
```python
add_to_docket(self, docket: Docket, *args: Any, **kwargs: Any) -> Execution
@@ -113,3 +133,14 @@ Subclasses override this to handle their specific calling conventions:
The **kwargs are passed through to docket.add() (e.g., key=task_key).
+
+#### `get_span_attributes`
+
+```python
+get_span_attributes(self) -> dict[str, Any]
+```
+
+Return span attributes for telemetry.
+
+Subclasses should call super() and merge their specific attributes.
+
diff --git a/docs/python-sdk/fastmcp-utilities-json_schema_type.mdx b/docs/python-sdk/fastmcp-utilities-json_schema_type.mdx
index 50fba76542..59b66f2ec1 100644
--- a/docs/python-sdk/fastmcp-utilities-json_schema_type.mdx
+++ b/docs/python-sdk/fastmcp-utilities-json_schema_type.mdx
@@ -42,7 +42,7 @@ Example:
## Functions
-### `json_schema_to_type`
+### `json_schema_to_type`
```python
json_schema_to_type(schema: Mapping[str, Any], name: str | None = None) -> type
@@ -107,4 +107,4 @@ class Name:
## Classes
-### `JSONSchema`
+### `JSONSchema`
diff --git a/docs/python-sdk/fastmcp-utilities-logging.mdx b/docs/python-sdk/fastmcp-utilities-logging.mdx
index ef3264dbb3..1fffe465c3 100644
--- a/docs/python-sdk/fastmcp-utilities-logging.mdx
+++ b/docs/python-sdk/fastmcp-utilities-logging.mdx
@@ -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-version_check.mdx b/docs/python-sdk/fastmcp-utilities-version_check.mdx
new file mode 100644
index 0000000000..a88805fb2d
--- /dev/null
+++ b/docs/python-sdk/fastmcp-utilities-version_check.mdx
@@ -0,0 +1,40 @@
+---
+title: version_check
+sidebarTitle: version_check
+---
+
+# `fastmcp.utilities.version_check`
+
+
+Version checking utilities for FastMCP.
+
+## Functions
+
+### `get_latest_version`
+
+```python
+get_latest_version(include_prereleases: bool = False) -> str | None
+```
+
+
+Get the latest version of FastMCP from PyPI, using cache when available.
+
+**Args:**
+- `include_prereleases`: If True, include pre-release versions.
+
+**Returns:**
+- The latest version string, or None if unavailable.
+
+
+### `check_for_newer_version`
+
+```python
+check_for_newer_version() -> str | None
+```
+
+
+Check if a newer version of FastMCP is available.
+
+**Returns:**
+- The latest version string if newer than current, None otherwise.
+
diff --git a/docs/python-sdk/fastmcp-utilities-versions.mdx b/docs/python-sdk/fastmcp-utilities-versions.mdx
new file mode 100644
index 0000000000..9adb00b50a
--- /dev/null
+++ b/docs/python-sdk/fastmcp-utilities-versions.mdx
@@ -0,0 +1,190 @@
+---
+title: versions
+sidebarTitle: versions
+---
+
+# `fastmcp.utilities.versions`
+
+
+Version comparison utilities for component versioning.
+
+This module provides utilities for comparing component versions. Versions are
+strings that are first attempted to be parsed as PEP 440 versions (using the
+`packaging` library), falling back to lexicographic string comparison.
+
+Examples:
+ - "1", "2", "10" → parsed as PEP 440, compared semantically (1 < 2 < 10)
+ - "1.0", "2.0" → parsed as PEP 440
+ - "v1.0" → 'v' prefix stripped, parsed as "1.0"
+ - "2025-01-15" → not valid PEP 440, compared as strings
+ - None → sorts lowest (unversioned components)
+
+
+## Functions
+
+### `parse_version_key`
+
+```python
+parse_version_key(version: str | None) -> VersionKey
+```
+
+
+Parse a version string into a sortable key.
+
+**Args:**
+- `version`: The version string, or None for unversioned.
+
+**Returns:**
+- A VersionKey suitable for sorting.
+
+
+### `version_sort_key`
+
+```python
+version_sort_key(component: FastMCPComponent) -> VersionKey
+```
+
+
+Get a sort key for a component based on its version.
+
+Use with sorted() or max() to order components by version.
+
+**Args:**
+- `component`: The component to get a sort key for.
+
+**Returns:**
+- A sortable VersionKey.
+
+
+### `compare_versions`
+
+```python
+compare_versions(a: str | None, b: str | None) -> int
+```
+
+
+Compare two version strings.
+
+**Args:**
+- `a`: First version string (or None).
+- `b`: Second version string (or None).
+
+**Returns:**
+- -1 if a < b, 0 if a == b, 1 if a > b.
+
+
+### `is_version_greater`
+
+```python
+is_version_greater(a: str | None, b: str | None) -> bool
+```
+
+
+Check if version a is greater than version b.
+
+**Args:**
+- `a`: First version string (or None).
+- `b`: Second version string (or None).
+
+**Returns:**
+- True if a > b, False otherwise.
+
+
+### `max_version`
+
+```python
+max_version(a: str | None, b: str | None) -> str | None
+```
+
+
+Return the greater of two versions.
+
+**Args:**
+- `a`: First version string (or None).
+- `b`: Second version string (or None).
+
+**Returns:**
+- The greater version, or None if both are None.
+
+
+### `min_version`
+
+```python
+min_version(a: str | None, b: str | None) -> str | None
+```
+
+
+Return the lesser of two versions.
+
+**Args:**
+- `a`: First version string (or None).
+- `b`: Second version string (or None).
+
+**Returns:**
+- The lesser version, or None if both are None.
+
+
+## Classes
+
+### `VersionSpec`
+
+
+Specification for filtering components by version.
+
+Used by transforms and providers to filter components to a specific
+version or version range. Unversioned components (version=None) always
+match any spec.
+
+**Args:**
+- `gte`: If set, only versions >= this value match.
+- `lt`: If set, only versions < this value match.
+- `eq`: If set, only this exact version matches (gte/lt ignored).
+
+
+**Methods:**
+
+#### `matches`
+
+```python
+matches(self, version: str | None) -> bool
+```
+
+Check if a version matches this spec.
+
+**Args:**
+- `version`: The version to check, or None for unversioned.
+
+**Returns:**
+- True if the version matches the spec.
+
+
+#### `intersect`
+
+```python
+intersect(self, other: VersionSpec | None) -> VersionSpec
+```
+
+Return a spec that satisfies both this spec and other.
+
+Used by transforms to combine caller constraints with filter constraints.
+For example, if a VersionFilter has lt="3.0" and caller requests eq="1.0",
+the intersection validates "1.0" is in range and returns the exact spec.
+
+**Args:**
+- `other`: Another spec to intersect with, or None.
+
+**Returns:**
+- A VersionSpec that matches only versions satisfying both specs.
+
+
+### `VersionKey`
+
+
+A comparable version key that handles None, PEP 440 versions, and strings.
+
+Comparison order:
+1. None (unversioned) sorts lowest
+2. PEP 440 versions sort by semantic version order
+3. Invalid versions (strings) sort lexicographically
+4. When comparing PEP 440 vs string, PEP 440 comes first
+
diff --git a/docs/python-sdk/fastmcp-utilities-visibility.mdx b/docs/python-sdk/fastmcp-utilities-visibility.mdx
deleted file mode 100644
index ade14110e9..0000000000
--- a/docs/python-sdk/fastmcp-utilities-visibility.mdx
+++ /dev/null
@@ -1,86 +0,0 @@
----
-title: visibility
-sidebarTitle: visibility
----
-
-# `fastmcp.utilities.visibility`
-
-
-Visibility filtering for FastMCP components.
-
-This module provides the VisibilityFilter class which handles blocklist and
-allowlist logic for controlling component visibility at both the provider
-and server levels.
-
-
-## Classes
-
-### `VisibilityFilter`
-
-
-Manages component visibility with blocklist and allowlist support.
-
-Both servers and providers use this class to control which components
-are visible. Visibility is hierarchical: if a component is hidden at
-any level (provider or server), it's hidden to the client.
-
-Filtering logic (blocklist wins over allowlist):
-1. If component key is in _disabled_keys → HIDDEN
-2. If any component tag is in _disabled_tags → HIDDEN
-3. If _default_enabled is False and component not in allowlist → HIDDEN
-4. Otherwise → VISIBLE
-
-The `only=True` flag on enable() switches to allowlist mode:
-- Sets _default_enabled = False
-- Clears existing allowlists
-- Adds specified keys/tags to allowlist
-
-
-**Methods:**
-
-#### `disable`
-
-```python
-disable(self) -> None
-```
-
-Add to blocklist (hide components).
-
-**Args:**
-- `keys`: Component keys to hide (e.g., "tool\:my_tool", "resource\:file\://x")
-- `tags`: Tags to hide - any component with these tags will be hidden
-
-
-#### `enable`
-
-```python
-enable(self) -> None
-```
-
-Remove from blocklist, or set allowlist with only=True.
-
-**Args:**
-- `keys`: Component keys to show
-- `tags`: Tags to show
-- `only`: If True, switches to allowlist mode - ONLY show these keys/tags.
-This sets default visibility to False, clears existing allowlists,
-and adds the specified keys/tags to the allowlist.
-
-
-#### `reset`
-
-```python
-reset(self) -> None
-```
-
-Reset to default state (everything enabled, no filters).
-
-
-#### `is_enabled`
-
-```python
-is_enabled(self, component: FastMCPComponent) -> bool
-```
-
-Check if component is enabled. Blocklist wins over allowlist.
-
diff --git a/src/fastmcp/server/providers/proxy.py b/src/fastmcp/server/providers/proxy.py
index a21faa27e3..56827ced21 100644
--- a/src/fastmcp/server/providers/proxy.py
+++ b/src/fastmcp/server/providers/proxy.py
@@ -44,7 +44,7 @@
from fastmcp.server.server import FastMCP
from fastmcp.server.tasks.config import TaskConfig
from fastmcp.tools.tool import Tool, ToolResult
-from fastmcp.utilities.components import FastMCPComponent
+from fastmcp.utilities.components import FastMCPComponent, get_fastmcp_metadata
from fastmcp.utilities.logging import get_logger
if TYPE_CHECKING:
@@ -104,7 +104,7 @@ def from_mcp_tool(
output_schema=mcp_tool.outputSchema,
icons=mcp_tool.icons,
meta=mcp_tool.meta,
- tags=(mcp_tool.meta or {}).get("fastmcp", {}).get("tags", []),
+ tags=get_fastmcp_metadata(mcp_tool.meta).get("tags", []),
)
async def run(
@@ -211,7 +211,7 @@ def from_mcp_resource(
mime_type=mcp_resource.mimeType or "text/plain",
icons=mcp_resource.icons,
meta=mcp_resource.meta,
- tags=(mcp_resource.meta or {}).get("fastmcp", {}).get("tags", []),
+ tags=get_fastmcp_metadata(mcp_resource.meta).get("tags", []),
task_config=TaskConfig(mode="forbidden"),
)
@@ -309,7 +309,7 @@ def from_mcp_template( # type: ignore[override]
icons=mcp_template.icons,
parameters={}, # Remote templates don't have local parameters
meta=mcp_template.meta,
- tags=(mcp_template.meta or {}).get("fastmcp", {}).get("tags", []),
+ tags=get_fastmcp_metadata(mcp_template.meta).get("tags", []),
task_config=TaskConfig(mode="forbidden"),
)
@@ -371,7 +371,7 @@ async def create_resource(
].mimeType, # Use first item's mimeType for backward compatibility
icons=self.icons,
meta=self.meta,
- tags=(self.meta or {}).get("fastmcp", {}).get("tags", []),
+ tags=get_fastmcp_metadata(self.meta).get("tags", []),
_cached_content=cached_content,
)
@@ -429,7 +429,7 @@ def from_mcp_prompt(
arguments=arguments,
icons=mcp_prompt.icons,
meta=mcp_prompt.meta,
- tags=(mcp_prompt.meta or {}).get("fastmcp", {}).get("tags", []),
+ tags=get_fastmcp_metadata(mcp_prompt.meta).get("tags", []),
task_config=TaskConfig(mode="forbidden"),
)
diff --git a/src/fastmcp/utilities/components.py b/src/fastmcp/utilities/components.py
index 067aafe10e..49109c1aa4 100644
--- a/src/fastmcp/utilities/components.py
+++ b/src/fastmcp/utilities/components.py
@@ -1,7 +1,7 @@
from __future__ import annotations
from collections.abc import Sequence
-from typing import TYPE_CHECKING, Annotated, Any, ClassVar, TypedDict
+from typing import TYPE_CHECKING, Annotated, Any, ClassVar, TypedDict, cast
from mcp.types import Icon
from pydantic import BeforeValidator, Field
@@ -22,6 +22,17 @@ class FastMCPMeta(TypedDict, total=False):
version: str
+def get_fastmcp_metadata(meta: dict[str, Any] | None) -> FastMCPMeta:
+ """Extract FastMCP metadata from a component's meta dict.
+
+ Handles both the current `fastmcp` namespace and the legacy `_fastmcp`
+ namespace for compatibility with older FastMCP servers.
+ """
+ if not meta:
+ return {}
+ return cast(FastMCPMeta, meta.get("fastmcp") or meta.get("_fastmcp") or {})
+
+
def _convert_set_default_none(maybe_set: set[T] | Sequence[T] | None) -> set[T]:
"""Convert a sequence to a set, defaulting to an empty set if None."""
if maybe_set is None:
@@ -126,13 +137,12 @@ def key(self) -> str:
base_key = self.make_key(self.name)
return f"{base_key}@{self.version or ''}"
- def get_meta(self) -> dict[str, Any] | None:
- """
- Get the meta information about the component.
+ def get_meta(self) -> dict[str, Any]:
+ """Get the meta information about the component.
- A `fastmcp` key will always be included in the meta, containing a `tags`
- field with the tags of the component, and optionally a `version` field
- if the component has a version.
+ Returns a dict that always includes a `fastmcp` key containing:
+ - `tags`: sorted list of component tags
+ - `version`: component version (only if set)
"""
meta = self.meta or {}
@@ -145,7 +155,7 @@ def get_meta(self) -> dict[str, Any] | None:
fastmcp_meta = upstream_meta | fastmcp_meta
meta["fastmcp"] = fastmcp_meta
- return meta or None
+ return meta
def __eq__(self, other: object) -> bool:
if type(self) is not type(other):
From 22e224c4f54f2baf85662c704f267dfd7a765efc Mon Sep 17 00:00:00 2001
From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
Date: Fri, 16 Jan 2026 21:23:21 -0500
Subject: [PATCH 3/5] Revert python-sdk docs regeneration
---
docs/docs.json | 50 +--
docs/python-sdk/fastmcp-cli-cli.mdx | 12 +-
docs/python-sdk/fastmcp-client-client.mdx | 88 +++---
docs/python-sdk/fastmcp-client-transports.mdx | 63 ++--
docs/python-sdk/fastmcp-dependencies.mdx | 4 -
docs/python-sdk/fastmcp-exceptions.mdx | 6 -
docs/python-sdk/fastmcp-fs-__init__.mdx | 43 +++
docs/python-sdk/fastmcp-fs-decorators.mdx | 156 ++++++++++
docs/python-sdk/fastmcp-fs-discovery.mdx | 103 +++++++
docs/python-sdk/fastmcp-fs-provider.mdx | 111 +++++++
docs/python-sdk/fastmcp-mcp_config.mdx | 32 +-
docs/python-sdk/fastmcp-prompts-prompt.mdx | 85 +++++-
.../python-sdk/fastmcp-resources-resource.mdx | 75 +++--
.../python-sdk/fastmcp-resources-template.mdx | 52 ++--
...cp-server-auth-providers-introspection.mdx | 14 +-
docs/python-sdk/fastmcp-server-context.mdx | 143 +++------
.../fastmcp-server-dependencies.mdx | 259 ++++------------
.../python-sdk/fastmcp-server-elicitation.mdx | 6 +-
docs/python-sdk/fastmcp-server-http.mdx | 18 +-
docs/python-sdk/fastmcp-server-low_level.mdx | 19 +-
.../fastmcp-server-providers-base.mdx | 135 ++++----
...tmcp-server-providers-fastmcp_provider.mdx | 118 +++----
...astmcp-server-providers-local_provider.mdx | 179 ++++++-----
...tmcp-server-providers-openapi-provider.mdx | 24 +-
.../fastmcp-server-providers-proxy.mdx | 88 ++----
.../fastmcp-server-providers-transforming.mdx | 117 +++++++
docs/python-sdk/fastmcp-server-server.mdx | 287 ++++++++----------
.../fastmcp-server-tasks-capabilities.mdx | 15 +-
.../fastmcp-server-tasks-config.mdx | 19 +-
.../fastmcp-server-tasks-requests.mdx | 10 +-
.../fastmcp-server-tasks-subscriptions.mdx | 4 +-
docs/python-sdk/fastmcp-tools-tool.mdx | 95 +++++-
.../fastmcp-tools-tool_transform.mdx | 25 +-
.../fastmcp-utilities-async_utils.mdx | 15 +-
docs/python-sdk/fastmcp-utilities-cli.mdx | 6 +-
.../fastmcp-utilities-components.mdx | 59 +---
.../fastmcp-utilities-json_schema_type.mdx | 4 +-
docs/python-sdk/fastmcp-utilities-logging.mdx | 2 +-
.../fastmcp-utilities-visibility.mdx | 86 ++++++
39 files changed, 1499 insertions(+), 1128 deletions(-)
create mode 100644 docs/python-sdk/fastmcp-fs-__init__.mdx
create mode 100644 docs/python-sdk/fastmcp-fs-decorators.mdx
create mode 100644 docs/python-sdk/fastmcp-fs-discovery.mdx
create mode 100644 docs/python-sdk/fastmcp-fs-provider.mdx
create mode 100644 docs/python-sdk/fastmcp-server-providers-transforming.mdx
create mode 100644 docs/python-sdk/fastmcp-utilities-visibility.mdx
diff --git a/docs/docs.json b/docs/docs.json
index f6b0649d14..5b1c59f23e 100644
--- a/docs/docs.json
+++ b/docs/docs.json
@@ -20,10 +20,7 @@
"primary": "#2d00f7"
},
"contextual": {
- "options": [
- "copy",
- "view"
- ]
+ "options": ["copy", "view"]
},
"description": "The fast, Pythonic way to build MCP servers and clients.",
"errors": {
@@ -166,10 +163,7 @@
{
"group": "Essentials",
"icon": "cube",
- "pages": [
- "clients/client",
- "clients/transports"
- ]
+ "pages": ["clients/client", "clients/transports"]
},
{
"group": "Core Operations",
@@ -196,10 +190,7 @@
{
"group": "Authentication",
"icon": "user-shield",
- "pages": [
- "clients/auth/oauth",
- "clients/auth/bearer"
- ]
+ "pages": ["clients/auth/oauth", "clients/auth/bearer"]
}
]
},
@@ -209,10 +200,7 @@
{
"group": "Providers",
"icon": "globe",
- "pages": [
- "integrations/fastapi",
- "integrations/openapi"
- ]
+ "pages": ["integrations/fastapi", "integrations/openapi"]
},
{
"group": "Authentication",
@@ -291,12 +279,10 @@
"anchor": "Python SDK",
"icon": "python",
"pages": [
- "python-sdk/fastmcp-decorators",
"python-sdk/fastmcp-dependencies",
"python-sdk/fastmcp-exceptions",
"python-sdk/fastmcp-mcp_config",
"python-sdk/fastmcp-settings",
- "python-sdk/fastmcp-telemetry",
{
"group": "fastmcp.cli",
"pages": [
@@ -352,7 +338,6 @@
]
},
"python-sdk/fastmcp-client-tasks",
- "python-sdk/fastmcp-client-telemetry",
"python-sdk/fastmcp-client-transports"
]
},
@@ -360,7 +345,6 @@
"group": "fastmcp.prompts",
"pages": [
"python-sdk/fastmcp-prompts-__init__",
- "python-sdk/fastmcp-prompts-function_prompt",
"python-sdk/fastmcp-prompts-prompt"
]
},
@@ -368,7 +352,6 @@
"group": "fastmcp.resources",
"pages": [
"python-sdk/fastmcp-resources-__init__",
- "python-sdk/fastmcp-resources-function_resource",
"python-sdk/fastmcp-resources-resource",
"python-sdk/fastmcp-resources-template",
"python-sdk/fastmcp-resources-types"
@@ -383,7 +366,6 @@
"pages": [
"python-sdk/fastmcp-server-auth-__init__",
"python-sdk/fastmcp-server-auth-auth",
- "python-sdk/fastmcp-server-auth-authorization",
"python-sdk/fastmcp-server-auth-jwt_issuer",
"python-sdk/fastmcp-server-auth-middleware",
"python-sdk/fastmcp-server-auth-oauth_proxy",
@@ -423,12 +405,10 @@
"group": "middleware",
"pages": [
"python-sdk/fastmcp-server-middleware-__init__",
- "python-sdk/fastmcp-server-middleware-authorization",
"python-sdk/fastmcp-server-middleware-caching",
"python-sdk/fastmcp-server-middleware-error_handling",
"python-sdk/fastmcp-server-middleware-logging",
"python-sdk/fastmcp-server-middleware-middleware",
- "python-sdk/fastmcp-server-middleware-ping",
"python-sdk/fastmcp-server-middleware-rate_limiting",
"python-sdk/fastmcp-server-middleware-timing",
"python-sdk/fastmcp-server-middleware-tool_injection"
@@ -447,11 +427,8 @@
"group": "providers",
"pages": [
"python-sdk/fastmcp-server-providers-__init__",
- "python-sdk/fastmcp-server-providers-aggregate",
"python-sdk/fastmcp-server-providers-base",
"python-sdk/fastmcp-server-providers-fastmcp_provider",
- "python-sdk/fastmcp-server-providers-filesystem",
- "python-sdk/fastmcp-server-providers-filesystem_discovery",
"python-sdk/fastmcp-server-providers-local_provider",
{
"group": "openapi",
@@ -462,7 +439,8 @@
"python-sdk/fastmcp-server-providers-openapi-routing"
]
},
- "python-sdk/fastmcp-server-providers-proxy"
+ "python-sdk/fastmcp-server-providers-proxy",
+ "python-sdk/fastmcp-server-providers-transforming"
]
},
"python-sdk/fastmcp-server-proxy",
@@ -487,17 +465,6 @@
"python-sdk/fastmcp-server-tasks-routing",
"python-sdk/fastmcp-server-tasks-subscriptions"
]
- },
- "python-sdk/fastmcp-server-telemetry",
- {
- "group": "transforms",
- "pages": [
- "python-sdk/fastmcp-server-transforms-__init__",
- "python-sdk/fastmcp-server-transforms-namespace",
- "python-sdk/fastmcp-server-transforms-tool_transform",
- "python-sdk/fastmcp-server-transforms-version_filter",
- "python-sdk/fastmcp-server-transforms-visibility"
- ]
}
]
},
@@ -505,8 +472,6 @@
"group": "fastmcp.tools",
"pages": [
"python-sdk/fastmcp-tools-__init__",
- "python-sdk/fastmcp-tools-function_parsing",
- "python-sdk/fastmcp-tools-function_tool",
"python-sdk/fastmcp-tools-tool",
"python-sdk/fastmcp-tools-tool_transform"
]
@@ -570,8 +535,7 @@
"python-sdk/fastmcp-utilities-tests",
"python-sdk/fastmcp-utilities-types",
"python-sdk/fastmcp-utilities-ui",
- "python-sdk/fastmcp-utilities-version_check",
- "python-sdk/fastmcp-utilities-versions"
+ "python-sdk/fastmcp-utilities-visibility"
]
}
]
diff --git a/docs/python-sdk/fastmcp-cli-cli.mdx b/docs/python-sdk/fastmcp-cli-cli.mdx
index 759a4324d9..cb0c4be1b4 100644
--- a/docs/python-sdk/fastmcp-cli-cli.mdx
+++ b/docs/python-sdk/fastmcp-cli-cli.mdx
@@ -10,7 +10,7 @@ FastMCP CLI tools using Cyclopts.
## Functions
-### `with_argv`
+### `with_argv`
```python
with_argv(args: list[str] | None)
@@ -27,7 +27,7 @@ Args are provided without the script name, so we preserve sys.argv[0]
and replace the rest.
-### `version`
+### `version`
```python
version()
@@ -37,7 +37,7 @@ version()
Display version information and platform details.
-### `dev`
+### `dev`
```python
dev(server_spec: str | None = None) -> None
@@ -50,7 +50,7 @@ Run an MCP server with the MCP Inspector for development.
- `server_spec`: Python file to run, optionally with \:object suffix, or None to auto-detect fastmcp.json
-### `run`
+### `run`
```python
run(server_spec: str | None = None, *server_args: str) -> None
@@ -74,7 +74,7 @@ fastmcp run server.py -- --config config.json --debug
- `server_spec`: Python file, object specification (file\:obj), config file, URL, or None to auto-detect
-### `inspect`
+### `inspect`
```python
inspect(server_spec: str | None = None) -> None
@@ -105,7 +105,7 @@ fastmcp inspect # auto-detect fastmcp.json
- `server_spec`: Python file to inspect, optionally with \:object suffix, or fastmcp.json
-### `prepare`
+### `prepare`
```python
prepare(config_path: Annotated[str | None, cyclopts.Parameter(help='Path to fastmcp.json configuration file')] = None, output_dir: Annotated[str | None, cyclopts.Parameter(help='Directory to create the persistent environment in')] = None, skip_source: Annotated[bool, cyclopts.Parameter(help='Skip source preparation (e.g., git clone)')] = False) -> None
diff --git a/docs/python-sdk/fastmcp-client-client.mdx b/docs/python-sdk/fastmcp-client-client.mdx
index 9bdf9108a9..a638d3940a 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.
-#### `list_resources_mcp`
+#### `list_resources_mcp`
```python
list_resources_mcp(self) -> mcp.types.ListResourcesResult
@@ -251,7 +251,7 @@ containing the list of resources and any additional metadata.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `list_resources`
+#### `list_resources`
```python
list_resources(self) -> list[mcp.types.Resource]
@@ -267,7 +267,7 @@ Retrieve a list of resources available on the server.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `list_resource_templates_mcp`
+#### `list_resource_templates_mcp`
```python
list_resource_templates_mcp(self) -> mcp.types.ListResourceTemplatesResult
@@ -284,7 +284,7 @@ containing the list of resource templates and any additional metadata.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `list_resource_templates`
+#### `list_resource_templates`
```python
list_resource_templates(self) -> list[mcp.types.ResourceTemplate]
@@ -300,7 +300,7 @@ Retrieve a list of resource templates available on the server.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `read_resource_mcp`
+#### `read_resource_mcp`
```python
read_resource_mcp(self, uri: AnyUrl | str, meta: dict[str, Any] | None = None) -> mcp.types.ReadResourceResult
@@ -321,19 +321,19 @@ containing the resource contents and any additional metadata.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `read_resource`
+#### `read_resource`
```python
read_resource(self, uri: AnyUrl | str) -> list[mcp.types.TextResourceContents | mcp.types.BlobResourceContents]
```
-#### `read_resource`
+#### `read_resource`
```python
read_resource(self, uri: AnyUrl | str) -> ResourceTask
```
-#### `read_resource`
+#### `read_resource`
```python
read_resource(self, uri: AnyUrl | str) -> list[mcp.types.TextResourceContents | mcp.types.BlobResourceContents] | ResourceTask
@@ -356,7 +356,7 @@ A list of content objects if task=False, or a ResourceTask object if task=True.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `list_prompts_mcp`
+#### `list_prompts_mcp`
```python
list_prompts_mcp(self) -> mcp.types.ListPromptsResult
@@ -373,7 +373,7 @@ containing the list of prompts and any additional metadata.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `list_prompts`
+#### `list_prompts`
```python
list_prompts(self) -> list[mcp.types.Prompt]
@@ -389,7 +389,7 @@ Retrieve a list of prompts available on the server.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `get_prompt_mcp`
+#### `get_prompt_mcp`
```python
get_prompt_mcp(self, name: str, arguments: dict[str, Any] | None = None, meta: dict[str, Any] | None = None) -> mcp.types.GetPromptResult
@@ -411,19 +411,19 @@ containing the prompt messages and any additional metadata.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `get_prompt`
+#### `get_prompt`
```python
get_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> mcp.types.GetPromptResult
```
-#### `get_prompt`
+#### `get_prompt`
```python
get_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> PromptTask
```
-#### `get_prompt`
+#### `get_prompt`
```python
get_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> mcp.types.GetPromptResult | PromptTask
@@ -447,7 +447,7 @@ or a PromptTask object if task=True.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `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
@@ -470,7 +470,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
@@ -492,7 +492,7 @@ include with the completion request. Defaults to None.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `list_tools_mcp`
+#### `list_tools_mcp`
```python
list_tools_mcp(self) -> mcp.types.ListToolsResult
@@ -509,7 +509,7 @@ containing the list of tools and any additional metadata.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `list_tools`
+#### `list_tools`
```python
list_tools(self) -> list[mcp.types.Tool]
@@ -525,7 +525,7 @@ Retrieve a list of tools available on the server.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `call_tool_mcp`
+#### `call_tool_mcp`
```python
call_tool_mcp(self, name: str, arguments: dict[str, Any], progress_handler: ProgressHandler | None = None, timeout: datetime.timedelta | float | int | None = None, meta: dict[str, Any] | None = None) -> mcp.types.CallToolResult
@@ -555,19 +555,19 @@ containing the tool result and any additional metadata.
- `McpError`: If the tool call requests results in a TimeoutError | JSONRPCError
-#### `call_tool`
+#### `call_tool`
```python
call_tool(self, name: str, arguments: dict[str, Any] | None = None) -> CallToolResult
```
-#### `call_tool`
+#### `call_tool`
```python
call_tool(self, name: str, arguments: dict[str, Any] | None = None) -> ToolTask
```
-#### `call_tool`
+#### `call_tool`
```python
call_tool(self, name: str, arguments: dict[str, Any] | None = None) -> CallToolResult | ToolTask
@@ -606,7 +606,7 @@ raw result object.
- `RuntimeError`: If called while the client is not connected.
-#### `get_task_status`
+#### `get_task_status`
```python
get_task_status(self, task_id: str) -> GetTaskResult
@@ -627,7 +627,7 @@ Sends a 'tasks/get' MCP protocol request over the existing transport.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `get_task_result`
+#### `get_task_result`
```python
get_task_result(self, task_id: str) -> Any
@@ -649,7 +649,7 @@ Returns the raw result - callers should parse it appropriately.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `list_tasks`
+#### `list_tasks`
```python
list_tasks(self, cursor: str | None = None, limit: int = 50) -> dict[str, Any]
@@ -675,7 +675,7 @@ querying status for locally tracked task IDs.
- `McpError`: If the request results in a TimeoutError | JSONRPCError
-#### `cancel_task`
+#### `cancel_task`
```python
cancel_task(self, task_id: str) -> mcp.types.CancelTaskResult
@@ -697,7 +697,7 @@ and transition to cancelled state.
- `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-transports.mdx b/docs/python-sdk/fastmcp-client-transports.mdx
index bdf965c952..c9f748a322 100644
--- a/docs/python-sdk/fastmcp-client-transports.mdx
+++ b/docs/python-sdk/fastmcp-client-transports.mdx
@@ -7,7 +7,7 @@ sidebarTitle: transports
## Functions
-### `infer_transport`
+### `infer_transport`
```python
infer_transport(transport: ClientTransport | FastMCP | FastMCP1Server | AnyUrl | Path | MCPConfig | dict[str, Any] | str) -> ClientTransport
@@ -57,13 +57,13 @@ transport = infer_transport(config)
## Classes
-### `SessionKwargs`
+### `SessionKwargs`
Keyword arguments for the MCP ClientSession constructor.
-### `ClientTransport`
+### `ClientTransport`
Abstract base class for different MCP client transport mechanisms.
@@ -74,7 +74,7 @@ to an MCP server, and providing a ClientSession within an async context.
**Methods:**
-#### `connect_session`
+#### `connect_session`
```python
connect_session(self, **session_kwargs: Unpack[SessionKwargs]) -> AsyncIterator[ClientSession]
@@ -93,7 +93,7 @@ within this context.
constructor (e.g., callbacks, timeouts).
-#### `close`
+#### `close`
```python
close(self)
@@ -102,16 +102,7 @@ close(self)
Close the transport.
-#### `get_session_id`
-
-```python
-get_session_id(self) -> str | None
-```
-
-Get the session ID for this transport, if available.
-
-
-### `SSETransport`
+### `SSETransport`
Transport implementation that connects to an MCP server via Server-Sent Events.
@@ -119,13 +110,13 @@ Transport implementation that connects to an MCP server via Server-Sent Events.
**Methods:**
-#### `connect_session`
+#### `connect_session`
```python
connect_session(self, **session_kwargs: Unpack[SessionKwargs]) -> AsyncIterator[ClientSession]
```
-### `StreamableHttpTransport`
+### `StreamableHttpTransport`
Transport implementation that connects to an MCP server via Streamable HTTP Requests.
@@ -133,25 +124,25 @@ Transport implementation that connects to an MCP server via Streamable HTTP Requ
**Methods:**
-#### `connect_session`
+#### `connect_session`
```python
connect_session(self, **session_kwargs: Unpack[SessionKwargs]) -> AsyncIterator[ClientSession]
```
-#### `get_session_id`
+#### `get_session_id`
```python
get_session_id(self) -> str | None
```
-#### `close`
+#### `close`
```python
close(self)
```
-### `StdioTransport`
+### `StdioTransport`
Base transport for connecting to an MCP server via subprocess with stdio.
@@ -162,67 +153,67 @@ transports like Python, Node, Uvx, etc.
**Methods:**
-#### `connect_session`
+#### `connect_session`
```python
connect_session(self, **session_kwargs: Unpack[SessionKwargs]) -> AsyncIterator[ClientSession]
```
-#### `connect`
+#### `connect`
```python
connect(self, **session_kwargs: Unpack[SessionKwargs]) -> ClientSession | None
```
-#### `disconnect`
+#### `disconnect`
```python
disconnect(self)
```
-#### `close`
+#### `close`
```python
close(self)
```
-### `PythonStdioTransport`
+### `PythonStdioTransport`
Transport for running Python scripts.
-### `FastMCPStdioTransport`
+### `FastMCPStdioTransport`
Transport for running FastMCP servers using the FastMCP CLI.
-### `NodeStdioTransport`
+### `NodeStdioTransport`
Transport for running Node.js scripts.
-### `UvStdioTransport`
+### `UvStdioTransport`
Transport for running commands via the uv tool.
-### `UvxStdioTransport`
+### `UvxStdioTransport`
Transport for running commands via the uvx tool.
-### `NpxStdioTransport`
+### `NpxStdioTransport`
Transport for running commands via the npx tool.
-### `FastMCPTransport`
+### `FastMCPTransport`
In-memory transport for FastMCP servers.
@@ -235,13 +226,13 @@ tests or scenarios where client and server run in the same runtime.
**Methods:**
-#### `connect_session`
+#### `connect_session`
```python
connect_session(self, **session_kwargs: Unpack[SessionKwargs]) -> AsyncIterator[ClientSession]
```
-### `MCPConfigTransport`
+### `MCPConfigTransport`
Transport for connecting to one or more MCP servers defined in an MCPConfig.
@@ -293,13 +284,13 @@ async with client:
**Methods:**
-#### `connect_session`
+#### `connect_session`
```python
connect_session(self, **session_kwargs: Unpack[SessionKwargs]) -> AsyncIterator[ClientSession]
```
-#### `close`
+#### `close`
```python
close(self)
diff --git a/docs/python-sdk/fastmcp-dependencies.mdx b/docs/python-sdk/fastmcp-dependencies.mdx
index e803029c3f..d53c370276 100644
--- a/docs/python-sdk/fastmcp-dependencies.mdx
+++ b/docs/python-sdk/fastmcp-dependencies.mdx
@@ -12,7 +12,3 @@ This module re-exports dependency injection symbols from Docket and FastMCP
to provide a clean, centralized import location for all dependency-related
functionality.
-DI features (Depends, CurrentContext, CurrentFastMCP) work without pydocket
-using a vendored DI engine. Only task-related dependencies (CurrentDocket,
-CurrentWorker) and background task execution require fastmcp[tasks].
-
diff --git a/docs/python-sdk/fastmcp-exceptions.mdx b/docs/python-sdk/fastmcp-exceptions.mdx
index 78d2e0110a..26e62012ab 100644
--- a/docs/python-sdk/fastmcp-exceptions.mdx
+++ b/docs/python-sdk/fastmcp-exceptions.mdx
@@ -63,9 +63,3 @@ Object not found.
Object is disabled.
-
-### `AuthorizationError`
-
-
-Error when authorization check fails.
-
diff --git a/docs/python-sdk/fastmcp-fs-__init__.mdx b/docs/python-sdk/fastmcp-fs-__init__.mdx
new file mode 100644
index 0000000000..d49a61f5bc
--- /dev/null
+++ b/docs/python-sdk/fastmcp-fs-__init__.mdx
@@ -0,0 +1,43 @@
+---
+title: __init__
+sidebarTitle: __init__
+---
+
+# `fastmcp.fs`
+
+
+Filesystem-based component discovery for FastMCP.
+
+This module provides decorators and a provider for discovering MCP components
+from the filesystem. Files are scanned for functions decorated with @tool,
+@resource, or @prompt, and automatically registered with the server.
+
+Example:
+ ```python
+ # server.py
+ from fastmcp import FastMCP
+ from fastmcp.fs import FileSystemProvider
+
+ mcp = FastMCP("MyServer", providers=[FileSystemProvider("mcp/")])
+ ```
+
+ ```python
+ # mcp/tools/greet.py
+ from fastmcp.fs import tool
+
+ @tool
+ def greet(name: str) -> str:
+ '''Greet someone by name.'''
+ return f"Hello, {name}!"
+ ```
+
+ ```python
+ # mcp/resources/config.py
+ from fastmcp.fs import resource
+
+ @resource("config://app")
+ def get_config() -> dict:
+ '''Get application configuration.'''
+ return {"version": "1.0"}
+ ```
+
diff --git a/docs/python-sdk/fastmcp-fs-decorators.mdx b/docs/python-sdk/fastmcp-fs-decorators.mdx
new file mode 100644
index 0000000000..45ade09812
--- /dev/null
+++ b/docs/python-sdk/fastmcp-fs-decorators.mdx
@@ -0,0 +1,156 @@
+---
+title: decorators
+sidebarTitle: decorators
+---
+
+# `fastmcp.fs.decorators`
+
+
+Decorators for marking functions in filesystem-based discovery.
+
+These decorators mark functions with metadata so that FileSystemProvider
+can discover and register them. Unlike LocalProvider's decorators, these
+do NOT register components immediately - they just store metadata on the
+function for later discovery.
+
+Example:
+ ```python
+ # mcp/tools/greet.py
+ from fastmcp.fs import tool
+
+ @tool
+ def greet(name: str) -> str:
+ '''Greet someone by name.'''
+ return f"Hello, {name}!"
+
+ @tool(name="custom-greet", tags={"greeting"})
+ def my_greet(name: str) -> str:
+ return f"Hi, {name}!"
+ ```
+
+
+## Functions
+
+### `get_fs_meta`
+
+```python
+get_fs_meta(fn: Any) -> FSMeta | None
+```
+
+
+Get filesystem metadata from a function if it has been decorated.
+
+
+### `has_fs_meta`
+
+```python
+has_fs_meta(fn: Any) -> bool
+```
+
+
+Check if a function has filesystem metadata.
+
+
+### `tool`
+
+```python
+tool(fn: AnyFunction | str | None = None) -> Any
+```
+
+
+Mark a function as a tool for filesystem-based discovery.
+
+This decorator stores metadata on the function but does NOT register it.
+FileSystemProvider discovers marked functions when scanning directories.
+
+Supports multiple calling patterns:
+- @tool (without parentheses)
+- @tool() (with empty parentheses)
+- @tool("custom_name") (with name as first argument)
+- @tool(name="custom_name") (with keyword arguments)
+
+**Args:**
+- `fn`: The function to decorate, or a name string, or None
+- `name`: Optional name for the tool (defaults to function name)
+- `title`: Optional title for display
+- `description`: Optional description (defaults to docstring)
+- `icons`: Optional icons for the tool
+- `tags`: Optional tags for categorization
+- `output_schema`: Optional JSON schema for output
+- `annotations`: Optional tool annotations
+- `meta`: Optional metadata dict
+
+
+### `resource`
+
+```python
+resource(uri: str) -> Any
+```
+
+
+Mark a function as a resource for filesystem-based discovery.
+
+This decorator stores metadata on the function but does NOT register it.
+FileSystemProvider discovers marked functions when scanning directories.
+
+Unlike @tool and @prompt, @resource REQUIRES a URI argument.
+
+**Args:**
+- `uri`: URI for the resource (e.g., "config\://app" or "users\://{user_id}")
+- `name`: Optional name for the resource
+- `title`: Optional title for display
+- `description`: Optional description (defaults to docstring)
+- `icons`: Optional icons for the resource
+- `mime_type`: Optional MIME type
+- `tags`: Optional tags for categorization
+- `annotations`: Optional resource annotations
+- `meta`: Optional metadata dict
+
+
+### `prompt`
+
+```python
+prompt(fn: AnyFunction | str | None = None) -> Any
+```
+
+
+Mark a function as a prompt for filesystem-based discovery.
+
+This decorator stores metadata on the function but does NOT register it.
+FileSystemProvider discovers marked functions when scanning directories.
+
+Supports multiple calling patterns:
+- @prompt (without parentheses)
+- @prompt() (with empty parentheses)
+- @prompt("custom_name") (with name as first argument)
+- @prompt(name="custom_name") (with keyword arguments)
+
+**Args:**
+- `fn`: The function to decorate, or a name string, or None
+- `name`: Optional name for the prompt (defaults to function name)
+- `title`: Optional title for display
+- `description`: Optional description (defaults to docstring)
+- `icons`: Optional icons for the prompt
+- `tags`: Optional tags for categorization
+- `meta`: Optional metadata dict
+
+
+## Classes
+
+### `ToolMeta`
+
+
+Metadata stored on functions decorated with @tool.
+
+
+### `ResourceMeta`
+
+
+Metadata stored on functions decorated with @resource.
+
+
+### `PromptMeta`
+
+
+Metadata stored on functions decorated with @prompt.
+
diff --git a/docs/python-sdk/fastmcp-fs-discovery.mdx b/docs/python-sdk/fastmcp-fs-discovery.mdx
new file mode 100644
index 0000000000..4d6720be43
--- /dev/null
+++ b/docs/python-sdk/fastmcp-fs-discovery.mdx
@@ -0,0 +1,103 @@
+---
+title: discovery
+sidebarTitle: discovery
+---
+
+# `fastmcp.fs.discovery`
+
+
+File discovery and module import utilities for filesystem-based routing.
+
+This module provides functions to:
+1. Discover Python files in a directory tree
+2. Import modules (as packages if __init__.py exists, else directly)
+3. Extract decorated functions from imported modules
+
+
+## Functions
+
+### `discover_files`
+
+```python
+discover_files(root: Path) -> list[Path]
+```
+
+
+Recursively discover all Python files under a directory.
+
+Excludes __init__.py files (they're for package structure, not components).
+
+**Args:**
+- `root`: Root directory to scan.
+
+**Returns:**
+- List of .py file paths, sorted for deterministic order.
+
+
+### `import_module_from_file`
+
+```python
+import_module_from_file(file_path: Path) -> ModuleType
+```
+
+
+Import a Python file as a module.
+
+If the file is part of a package (directory has __init__.py), imports
+it as a proper package member (relative imports work). Otherwise,
+imports directly using spec_from_file_location.
+
+**Args:**
+- `file_path`: Path to the Python file.
+
+**Returns:**
+- The imported module.
+
+**Raises:**
+- `ImportError`: If the module cannot be imported.
+
+
+### `extract_components`
+
+```python
+extract_components(module: ModuleType) -> list[tuple[Any, FSMeta]]
+```
+
+
+Extract all decorated functions from a module.
+
+Scans all module attributes for functions that have been decorated
+with @tool, @resource, or @prompt.
+
+**Args:**
+- `module`: The imported module to scan.
+
+**Returns:**
+- List of (function, metadata) tuples for each decorated function.
+
+
+### `discover_and_import`
+
+```python
+discover_and_import(root: Path) -> DiscoveryResult
+```
+
+
+Discover files, import modules, and extract components.
+
+This is the main entry point for filesystem-based discovery.
+
+**Args:**
+- `root`: Root directory to scan.
+
+**Returns:**
+- DiscoveryResult with components and any failed files.
+
+
+## Classes
+
+### `DiscoveryResult`
+
+
+Result of filesystem discovery.
+
diff --git a/docs/python-sdk/fastmcp-fs-provider.mdx b/docs/python-sdk/fastmcp-fs-provider.mdx
new file mode 100644
index 0000000000..84bb30a4cb
--- /dev/null
+++ b/docs/python-sdk/fastmcp-fs-provider.mdx
@@ -0,0 +1,111 @@
+---
+title: provider
+sidebarTitle: provider
+---
+
+# `fastmcp.fs.provider`
+
+
+FileSystemProvider for filesystem-based component discovery.
+
+FileSystemProvider scans a directory for Python files, imports them, and
+registers any functions decorated with @tool, @resource, or @prompt.
+
+Example:
+ ```python
+ from fastmcp import FastMCP
+ from fastmcp.fs import FileSystemProvider
+
+ mcp = FastMCP("MyServer", providers=[FileSystemProvider("mcp/")])
+ ```
+
+
+## Classes
+
+### `FileSystemProvider`
+
+
+Provider that discovers components from the filesystem.
+
+Scans a directory for Python files and registers functions decorated
+with @tool, @resource, or @prompt from fastmcp.fs.
+
+**Args:**
+- `root`: Root directory to scan. Defaults to current directory.
+- `reload`: If True, re-scan files on every request (dev mode).
+Defaults to False (scan once at init, cache results).
+
+
+**Methods:**
+
+#### `list_tools`
+
+```python
+list_tools(self) -> Sequence[Tool]
+```
+
+Return all tools, reloading if in reload mode.
+
+
+#### `get_tool`
+
+```python
+get_tool(self, name: str) -> Tool | None
+```
+
+Get a tool by name, reloading if in reload mode.
+
+
+#### `list_resources`
+
+```python
+list_resources(self) -> Sequence[Resource]
+```
+
+Return all resources, reloading if in reload mode.
+
+
+#### `get_resource`
+
+```python
+get_resource(self, uri: str) -> Resource | None
+```
+
+Get a resource by URI, reloading if in reload mode.
+
+
+#### `list_resource_templates`
+
+```python
+list_resource_templates(self) -> Sequence[ResourceTemplate]
+```
+
+Return all resource templates, reloading if in reload mode.
+
+
+#### `get_resource_template`
+
+```python
+get_resource_template(self, uri: str) -> ResourceTemplate | None
+```
+
+Get a resource template, reloading if in reload mode.
+
+
+#### `list_prompts`
+
+```python
+list_prompts(self) -> Sequence[Prompt]
+```
+
+Return all prompts, reloading if in reload mode.
+
+
+#### `get_prompt`
+
+```python
+get_prompt(self, name: str) -> Prompt | None
+```
+
+Get a prompt by name, reloading if in reload mode.
+
diff --git a/docs/python-sdk/fastmcp-mcp_config.mdx b/docs/python-sdk/fastmcp-mcp_config.mdx
index 87ed568a0e..9b30dad856 100644
--- a/docs/python-sdk/fastmcp-mcp_config.mdx
+++ b/docs/python-sdk/fastmcp-mcp_config.mdx
@@ -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
```
-### `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
```
-### `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-prompts-prompt.mdx b/docs/python-sdk/fastmcp-prompts-prompt.mdx
index 1541e9c580..8516742dd0 100644
--- a/docs/python-sdk/fastmcp-prompts-prompt.mdx
+++ b/docs/python-sdk/fastmcp-prompts-prompt.mdx
@@ -10,7 +10,7 @@ Base classes for FastMCP prompts.
## Classes
-### `Message`
+### `Message`
Wrapper for prompt message with auto-serialization.
@@ -21,7 +21,7 @@ Accepts any content - strings pass through, other types
**Methods:**
-#### `to_mcp_prompt_message`
+#### `to_mcp_prompt_message`
```python
to_mcp_prompt_message(self) -> PromptMessage
@@ -30,13 +30,13 @@ to_mcp_prompt_message(self) -> PromptMessage
Convert to MCP PromptMessage.
-### `PromptArgument`
+### `PromptArgument`
An argument that can be passed to a prompt.
-### `PromptResult`
+### `PromptResult`
Canonical result type for prompt rendering.
@@ -47,7 +47,7 @@ roles, and metadata at both the message and result level.
**Methods:**
-#### `to_mcp_prompt_result`
+#### `to_mcp_prompt_result`
```python
to_mcp_prompt_result(self) -> GetPromptResult
@@ -56,7 +56,7 @@ to_mcp_prompt_result(self) -> GetPromptResult
Convert to MCP GetPromptResult.
-### `Prompt`
+### `Prompt`
A prompt template that can be rendered with parameters.
@@ -64,7 +64,7 @@ A prompt template that can be rendered with parameters.
**Methods:**
-#### `to_mcp_prompt`
+#### `to_mcp_prompt`
```python
to_mcp_prompt(self, **overrides: Any) -> SDKPrompt
@@ -73,10 +73,10 @@ to_mcp_prompt(self, **overrides: Any) -> SDKPrompt
Convert the prompt to an MCP prompt.
-#### `from_function`
+#### `from_function`
```python
-from_function(cls, fn: Callable[..., Any]) -> FunctionPrompt
+from_function(fn: Callable[..., Any], name: str | None = None, title: str | None = None, description: str | None = None, icons: list[Icon] | None = None, tags: set[str] | None = None, meta: dict[str, Any] | None = None, task: bool | TaskConfig | None = None) -> FunctionPrompt
```
Create a Prompt from a function.
@@ -87,7 +87,7 @@ The function can return:
- PromptResult: used directly
-#### `render`
+#### `render`
```python
render(self, arguments: dict[str, Any] | None = None) -> str | list[Message | str] | PromptResult
@@ -101,7 +101,7 @@ Subclasses must implement this method. Return one of:
- PromptResult: Used directly
-#### `convert_result`
+#### `convert_result`
```python
convert_result(self, raw_value: Any) -> PromptResult
@@ -113,7 +113,7 @@ Convert a raw return value to PromptResult.
- `TypeError`: for unsupported types
-#### `register_with_docket`
+#### `register_with_docket`
```python
register_with_docket(self, docket: Docket) -> None
@@ -122,7 +122,7 @@ register_with_docket(self, docket: Docket) -> None
Register this prompt with docket for background execution.
-#### `add_to_docket`
+#### `add_to_docket`
```python
add_to_docket(self, docket: Docket, arguments: dict[str, Any] | None, **kwargs: Any) -> Execution
@@ -138,8 +138,63 @@ Schedule this prompt for background execution via docket.
- `**kwargs`: Additional kwargs passed to docket.add()
-#### `get_span_attributes`
+### `FunctionPrompt`
+
+
+A prompt that is a function.
+
+
+**Methods:**
+
+#### `from_function`
+
+```python
+from_function(cls, fn: Callable[..., Any], name: str | None = None, title: str | None = None, description: str | None = None, icons: list[Icon] | None = None, tags: set[str] | None = None, meta: dict[str, Any] | None = None, task: bool | TaskConfig | None = None) -> FunctionPrompt
+```
+
+Create a Prompt from a function.
+
+The function can return:
+- str: wrapped as single user Message
+- list\[Message | str]: converted to list\[Message]
+- PromptResult: used directly
+
+
+#### `render`
+
+```python
+render(self, arguments: dict[str, Any] | None = None) -> PromptResult
+```
+
+Render the prompt with arguments.
+
+
+#### `register_with_docket`
+
+```python
+register_with_docket(self, docket: Docket) -> None
+```
+
+Register this prompt with docket for background execution.
+
+FunctionPrompt registers the underlying function, which has the user's
+Depends parameters for docket to resolve.
+
+
+#### `add_to_docket`
```python
-get_span_attributes(self) -> dict[str, Any]
+add_to_docket(self, docket: Docket, arguments: dict[str, Any] | None, **kwargs: Any) -> Execution
```
+
+Schedule this prompt for background execution via docket.
+
+FunctionPrompt splats the arguments dict since .fn expects **kwargs.
+
+**Args:**
+- `docket`: The Docket instance
+- `arguments`: Prompt arguments
+- `fn_key`: Function lookup key in Docket registry (defaults to self.key)
+- `task_key`: Redis storage key for the result
+- `**kwargs`: Additional kwargs passed to docket.add()
+
diff --git a/docs/python-sdk/fastmcp-resources-resource.mdx b/docs/python-sdk/fastmcp-resources-resource.mdx
index b064ac47b3..bbd17a04fa 100644
--- a/docs/python-sdk/fastmcp-resources-resource.mdx
+++ b/docs/python-sdk/fastmcp-resources-resource.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
+from_function(fn: Callable[..., Any], uri: str | AnyUrl, name: str | 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) -> 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
@@ -124,7 +124,7 @@ Handles ResourceResult passthrough and converts raw values using
ResourceResult's normalization.
-#### `to_mcp_resource`
+#### `to_mcp_resource`
```python
to_mcp_resource(self, **overrides: Any) -> SDKResource
@@ -133,7 +133,7 @@ to_mcp_resource(self, **overrides: Any) -> SDKResource
Convert the resource to an SDKResource.
-#### `key`
+#### `key`
```python
key(self) -> str
@@ -142,7 +142,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
@@ -151,7 +151,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
@@ -166,8 +166,49 @@ Schedule this resource for background execution via docket.
- `**kwargs`: Additional kwargs passed to docket.add()
-#### `get_span_attributes`
+### `FunctionResource`
+
+
+A resource that defers data loading by wrapping a function.
+
+The function is only called when the resource is read, allowing for lazy loading
+of potentially expensive data. This is particularly useful when listing resources,
+as the function won't be called until the resource is actually accessed.
+
+The function can return:
+- str for text content (default)
+- bytes for binary content
+- other types will be converted to JSON
+
+
+**Methods:**
+
+#### `from_function`
+
+```python
+from_function(cls, fn: Callable[..., Any], uri: str | AnyUrl, name: str | 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) -> FunctionResource
+```
+
+Create a FunctionResource from a function.
+
+
+#### `read`
```python
-get_span_attributes(self) -> dict[str, Any]
+read(self) -> str | bytes | ResourceResult
```
+
+Read the resource by calling the wrapped function.
+
+
+#### `register_with_docket`
+
+```python
+register_with_docket(self, docket: Docket) -> None
+```
+
+Register this resource with docket for background execution.
+
+FunctionResource registers the underlying function, which has the user's
+Depends parameters for docket to resolve.
+
diff --git a/docs/python-sdk/fastmcp-resources-template.mdx b/docs/python-sdk/fastmcp-resources-template.mdx
index e1b932d889..e93d9f4be4 100644
--- a/docs/python-sdk/fastmcp-resources-template.mdx
+++ b/docs/python-sdk/fastmcp-resources-template.mdx
@@ -10,7 +10,7 @@ Resource template functionality.
## Functions
-### `extract_query_params`
+### `extract_query_params`
```python
extract_query_params(uri_template: str) -> set[str]
@@ -20,7 +20,7 @@ extract_query_params(uri_template: str) -> set[str]
Extract query parameter names from RFC 6570 `{?param1,param2}` syntax.
-### `build_regex`
+### `build_regex`
```python
build_regex(template: str) -> re.Pattern
@@ -35,7 +35,7 @@ Supports:
- `{?var1,var2}` - query parameters (ignored in path matching)
-### `match_uri_template`
+### `match_uri_template`
```python
match_uri_template(uri: str, uri_template: str) -> dict[str, str] | None
@@ -51,7 +51,7 @@ Supports RFC 6570 URI templates:
## Classes
-### `ResourceTemplate`
+### `ResourceTemplate`
A template for dynamically creating resources.
@@ -59,13 +59,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: AuthCheckCallable | list[AuthCheckCallable] | None = None) -> FunctionResourceTemplate
+from_function(fn: Callable[..., Any], uri_template: str, name: str | 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) -> FunctionResourceTemplate
```
-#### `set_default_mime_type`
+#### `set_default_mime_type`
```python
set_default_mime_type(cls, mime_type: str | None) -> str
@@ -74,7 +74,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
@@ -83,7 +83,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
@@ -92,7 +92,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
@@ -108,7 +108,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
@@ -120,7 +120,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
@@ -129,7 +129,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
@@ -138,7 +138,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
@@ -147,7 +147,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
@@ -156,7 +156,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
@@ -172,13 +172,7 @@ Schedule this template for background execution via docket.
- `**kwargs`: Additional kwargs passed to docket.add()
-#### `get_span_attributes`
-
-```python
-get_span_attributes(self) -> dict[str, Any]
-```
-
-### `FunctionResourceTemplate`
+### `FunctionResourceTemplate`
A template for dynamically creating resources.
@@ -186,7 +180,7 @@ A template for dynamically creating resources.
**Methods:**
-#### `create_resource`
+#### `create_resource`
```python
create_resource(self, uri: str, params: dict[str, Any]) -> Resource
@@ -195,7 +189,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
@@ -204,7 +198,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 +210,7 @@ FunctionResourceTemplate registers the underlying function, which has the
user's Depends parameters for docket to resolve.
-#### `add_to_docket`
+#### `add_to_docket`
```python
add_to_docket(self, docket: Docket, params: dict[str, Any], **kwargs: Any) -> Execution
@@ -234,10 +228,10 @@ 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: AuthCheckCallable | list[AuthCheckCallable] | None = None) -> FunctionResourceTemplate
+from_function(cls, fn: Callable[..., Any], uri_template: str, name: str | 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) -> FunctionResourceTemplate
```
Create a template from a function.
diff --git a/docs/python-sdk/fastmcp-server-auth-providers-introspection.mdx b/docs/python-sdk/fastmcp-server-auth-providers-introspection.mdx
index 32943d6b21..2a0d2e22d9 100644
--- a/docs/python-sdk/fastmcp-server-auth-providers-introspection.mdx
+++ b/docs/python-sdk/fastmcp-server-auth-providers-introspection.mdx
@@ -31,7 +31,7 @@ Example:
## Classes
-### `IntrospectionTokenVerifier`
+### `IntrospectionTokenVerifier`
OAuth 2.0 Token Introspection verifier (RFC 7662).
@@ -40,11 +40,8 @@ This verifier validates opaque tokens by calling an OAuth 2.0 token introspectio
endpoint. Unlike JWT verification which is stateless, token introspection requires
a network call to the authorization server for each token validation.
-The verifier authenticates to the introspection endpoint using either:
-- HTTP Basic Auth (client_secret_basic, default): credentials in Authorization header
-- POST body authentication (client_secret_post): credentials in request body
-
-Both methods are specified in RFC 6749 (OAuth 2.0) and RFC 7662 (Token Introspection).
+The verifier authenticates to the introspection endpoint using HTTP Basic Auth
+with the provided client_id and client_secret, as specified in RFC 7662.
Use this when:
- Your authorization server issues opaque (non-JWT) tokens
@@ -55,7 +52,7 @@ Use this when:
**Methods:**
-#### `verify_token`
+#### `verify_token`
```python
verify_token(self, token: str) -> AccessToken | None
@@ -64,8 +61,7 @@ verify_token(self, token: str) -> AccessToken | None
Verify a bearer token using OAuth 2.0 Token Introspection (RFC 7662).
This method makes a POST request to the introspection endpoint with the token,
-authenticated using the configured client authentication method (client_secret_basic
-or client_secret_post).
+authenticated using HTTP Basic Auth with the client credentials.
**Args:**
- `token`: The opaque token string to validate
diff --git a/docs/python-sdk/fastmcp-server-context.mdx b/docs/python-sdk/fastmcp-server-context.mdx
index 822efb8c6a..91e4c1195c 100644
--- a/docs/python-sdk/fastmcp-server-context.mdx
+++ b/docs/python-sdk/fastmcp-server-context.mdx
@@ -7,27 +7,7 @@ sidebarTitle: 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`
+### `set_context`
```python
set_context(context: Context) -> Generator[Context, None, None]
@@ -35,7 +15,7 @@ set_context(context: Context) -> Generator[Context, None, None]
## Classes
-### `LogData`
+### `LogData`
Data object for passing log arguments to client-side handlers.
@@ -44,7 +24,7 @@ This provides an interface to match the Python standard library logging,
for compatibility with structured logging.
-### `Context`
+### `Context`
Context object providing access to MCP capabilities.
@@ -73,22 +53,18 @@ async def my_tool(x: int, ctx: Context) -> str:
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")
+ # Manage state across the request
+ ctx.set_state("key", "value")
+ value = ctx.get_state("key")
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.
+Context objects maintain a state dictionary that can be used to store and share
+data across middleware and tool calls within a request. When a new context
+is created (nested contexts), it inherits a copy of its parent's state, ensuring
+that modifications in child contexts don't affect parent contexts.
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.
@@ -96,7 +72,7 @@ The context is optional - tools that don't need it can omit the parameter.
**Methods:**
-#### `fastmcp`
+#### `fastmcp`
```python
fastmcp(self) -> FastMCP
@@ -105,7 +81,7 @@ fastmcp(self) -> FastMCP
Get the FastMCP instance.
-#### `request_context`
+#### `request_context`
```python
request_context(self) -> RequestContext[ServerSession, Any, Request] | None
@@ -134,7 +110,7 @@ async def on_request(self, context, call_next):
```
-#### `lifespan_context`
+#### `lifespan_context`
```python
lifespan_context(self) -> dict[str, Any]
@@ -157,7 +133,7 @@ def my_tool(ctx: Context) -> str:
```
-#### `report_progress`
+#### `report_progress`
```python
report_progress(self, progress: float, total: float | None = None, message: str | None = None) -> None
@@ -170,7 +146,7 @@ Report progress for the current operation.
- `total`: Optional total value e.g. 100
-#### `list_resources`
+#### `list_resources`
```python
list_resources(self) -> list[SDKResource]
@@ -182,7 +158,7 @@ List all available resources from the server.
- List of Resource objects available on the server
-#### `list_prompts`
+#### `list_prompts`
```python
list_prompts(self) -> list[SDKPrompt]
@@ -194,7 +170,7 @@ List all available prompts from the server.
- List of Prompt objects available on the server
-#### `get_prompt`
+#### `get_prompt`
```python
get_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> GetPromptResult
@@ -210,7 +186,7 @@ Get a prompt by name with optional arguments.
- The prompt result
-#### `read_resource`
+#### `read_resource`
```python
read_resource(self, uri: str | AnyUrl) -> ResourceResult
@@ -225,7 +201,7 @@ Read a resource by URI.
- ResourceResult with contents
-#### `log`
+#### `log`
```python
log(self, message: str, level: LoggingLevel | None = None, logger_name: str | None = None, extra: Mapping[str, Any] | None = None) -> None
@@ -243,19 +219,7 @@ Messages sent to Clients are also logged to the `fastmcp.server.context.to_clien
- `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_id`
+#### `client_id`
```python
client_id(self) -> str | None
@@ -264,7 +228,7 @@ client_id(self) -> str | None
Get the client ID if available.
-#### `request_id`
+#### `request_id`
```python
request_id(self) -> str
@@ -275,7 +239,7 @@ Get the unique ID for this request.
Raises RuntimeError if MCP request context is not available.
-#### `session_id`
+#### `session_id`
```python
session_id(self) -> str
@@ -292,7 +256,7 @@ the same client session.
- for other transports.
-#### `session`
+#### `session`
```python
session(self) -> ServerSession
@@ -303,7 +267,7 @@ Access to the underlying session for advanced usage.
Raises RuntimeError if MCP request context is not available.
-#### `debug`
+#### `debug`
```python
debug(self, message: str, logger_name: str | None = None, extra: Mapping[str, Any] | None = None) -> None
@@ -314,7 +278,7 @@ 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`
+#### `info`
```python
info(self, message: str, logger_name: str | None = None, extra: Mapping[str, Any] | None = None) -> None
@@ -325,7 +289,7 @@ 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`
+#### `warning`
```python
warning(self, message: str, logger_name: str | None = None, extra: Mapping[str, Any] | None = None) -> None
@@ -336,7 +300,7 @@ 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`
+#### `error`
```python
error(self, message: str, logger_name: str | None = None, extra: Mapping[str, Any] | None = None) -> None
@@ -347,7 +311,7 @@ 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`.
-#### `list_roots`
+#### `list_roots`
```python
list_roots(self) -> list[Root]
@@ -356,7 +320,7 @@ list_roots(self) -> list[Root]
List the roots available to the server, as indicated by the client.
-#### `send_notification`
+#### `send_notification`
```python
send_notification(self, notification: mcp.types.ServerNotificationType) -> None
@@ -372,7 +336,7 @@ for the background flusher.
- `notification`: An MCP notification instance (e.g., ToolListChangedNotification())
-#### `send_notification_sync`
+#### `send_notification_sync`
```python
send_notification_sync(self, notification: mcp.types.ServerNotificationType) -> None
@@ -387,7 +351,7 @@ sent within ~1 second by the background flusher.
- `notification`: An MCP notification instance (e.g., ToolListChangedNotification())
-#### `close_sse_stream`
+#### `close_sse_stream`
```python
close_sse_stream(self) -> None
@@ -405,7 +369,7 @@ Instead of holding a connection open for minutes, you can periodically close
and let the client reconnect.
-#### `sample_step`
+#### `sample_step`
```python
sample_step(self, messages: str | Sequence[str | SamplingMessage]) -> SampleStep
@@ -442,7 +406,7 @@ Tools can raise ToolError to bypass masking.
- - .text: The text content (if any)
-#### `sample`
+#### `sample`
```python
sample(self, messages: str | Sequence[str | SamplingMessage]) -> SamplingResult[ResultT]
@@ -451,7 +415,7 @@ sample(self, messages: str | Sequence[str | SamplingMessage]) -> SamplingResult[
Overload: With result_type, returns SamplingResult[ResultT].
-#### `sample`
+#### `sample`
```python
sample(self, messages: str | Sequence[str | SamplingMessage]) -> SamplingResult[str]
@@ -460,7 +424,7 @@ sample(self, messages: str | Sequence[str | SamplingMessage]) -> SamplingResult[
Overload: Without result_type, returns SamplingResult[str].
-#### `sample`
+#### `sample`
```python
sample(self, messages: str | Sequence[str | SamplingMessage]) -> SamplingResult[ResultT] | SamplingResult[str]
@@ -502,43 +466,43 @@ Tools can raise ToolError to bypass masking.
- - .history: All messages exchanged during sampling
-#### `elicit`
+#### `elicit`
```python
elicit(self, message: str, response_type: None) -> AcceptedElicitation[dict[str, Any]] | DeclinedElicitation | CancelledElicitation
```
-#### `elicit`
+#### `elicit`
```python
elicit(self, message: str, response_type: type[T]) -> AcceptedElicitation[T] | DeclinedElicitation | CancelledElicitation
```
-#### `elicit`
+#### `elicit`
```python
elicit(self, message: str, response_type: list[str]) -> AcceptedElicitation[str] | DeclinedElicitation | CancelledElicitation
```
-#### `elicit`
+#### `elicit`
```python
elicit(self, message: str, response_type: dict[str, dict[str, str]]) -> AcceptedElicitation[str] | DeclinedElicitation | CancelledElicitation
```
-#### `elicit`
+#### `elicit`
```python
elicit(self, message: str, response_type: list[list[str]]) -> AcceptedElicitation[list[str]] | DeclinedElicitation | CancelledElicitation
```
-#### `elicit`
+#### `elicit`
```python
elicit(self, message: str, response_type: list[dict[str, dict[str, str]]]) -> AcceptedElicitation[list[str]] | DeclinedElicitation | CancelledElicitation
```
-#### `elicit`
+#### `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]]] | None = None) -> AcceptedElicitation[T] | AcceptedElicitation[dict[str, Any]] | AcceptedElicitation[str] | AcceptedElicitation[list[str]] | DeclinedElicitation | CancelledElicitation
@@ -567,35 +531,20 @@ type or dataclass or BaseModel. If it is a primitive type, an
object schema with a single "value" field will be generated.
-#### `set_state`
+#### `set_state`
```python
set_state(self, key: str, value: Any) -> None
```
-Set a value in the session-scoped state store.
-
-Values persist across requests within the same MCP session.
-The key is automatically prefixed with the session identifier.
-State expires after 1 day to prevent unbounded memory growth.
+Set a value in the context state.
-#### `get_state`
+#### `get_state`
```python
get_state(self, key: str) -> Any
```
-Get a value from 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 session-scoped state store.
+Get a value from the context state. Returns None if the key is not found.
diff --git a/docs/python-sdk/fastmcp-server-dependencies.mdx b/docs/python-sdk/fastmcp-server-dependencies.mdx
index 2eebf8f5dd..125ba2ecb3 100644
--- a/docs/python-sdk/fastmcp-server-dependencies.mdx
+++ b/docs/python-sdk/fastmcp-server-dependencies.mdx
@@ -5,139 +5,9 @@ sidebarTitle: dependencies
# `fastmcp.server.dependencies`
-
-Dependency injection for FastMCP.
-
-DI features (Depends, CurrentContext, CurrentFastMCP) work without pydocket
-using a vendored DI engine. Only task-related dependencies (CurrentDocket,
-CurrentWorker) and background task execution require fastmcp[tasks].
-
-
## Functions
-### `is_docket_available`
-
-```python
-is_docket_available() -> bool
-```
-
-
-Check if pydocket is installed.
-
-
-### `require_docket`
-
-```python
-require_docket(feature: str) -> None
-```
-
-
-Raise ImportError with install instructions if docket not available.
-
-**Args:**
-- `feature`: Description of what requires docket (e.g., "`task=True`",
- "CurrentDocket()"). Will be included in the error message.
-
-
-### `transform_context_annotations`
-
-```python
-transform_context_annotations(fn: Callable[..., Any]) -> Callable[..., Any]
-```
-
-
-Transform ctx: Context into ctx: Context = CurrentContext().
-
-Transforms ALL params typed as Context to use Docket's DI system,
-unless they already have a Dependency-based default (like CurrentContext()).
-
-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.
-
-**Returns:**
-- The active FastMCP server
-
-**Raises:**
-- `RuntimeError`: If no server in context
-
-
-### `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) -> 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` that cause issues
-if forwarded to downstream clients. If `include_all` is True, all headers are returned.
-
-
-### `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`
+### `without_injected_parameters`
```python
without_injected_parameters(fn: Callable[..., Any]) -> Callable[..., Any]
@@ -151,10 +21,6 @@ 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
@@ -162,33 +28,37 @@ 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]
```
-Resolve dependencies for a FastMCP function.
+Resolve dependencies and inject Context 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
+2. Resolves Docket dependencies
+3. Injects Context if needed
+4. Merges everything together
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`
+### `get_context`
+
+```python
+get_context() -> Context
+```
+
+### `CurrentContext`
```python
CurrentContext() -> Context
@@ -207,7 +77,7 @@ current MCP operation (tool/resource/prompt call).
- `RuntimeError`: If no active context found (during resolution)
-### `CurrentDocket`
+### `CurrentDocket`
```python
CurrentDocket() -> Docket
@@ -224,10 +94,9 @@ automatically creates for background task scheduling.
**Raises:**
- `RuntimeError`: If not within a FastMCP server context
-- `ImportError`: If fastmcp[tasks] not installed
-### `CurrentWorker`
+### `CurrentWorker`
```python
CurrentWorker() -> Worker
@@ -244,13 +113,12 @@ automatically creates for background task processing.
**Raises:**
- `RuntimeError`: If not within a FastMCP server context
-- `ImportError`: If fastmcp[tasks] not installed
-### `CurrentFastMCP`
+### `CurrentFastMCP`
```python
-CurrentFastMCP() -> FastMCP
+CurrentFastMCP()
```
@@ -265,104 +133,95 @@ This dependency provides access to the active FastMCP server.
- `RuntimeError`: If no server in context (during resolution)
-## Classes
-
-### `ProgressLike`
-
-
-Protocol for progress tracking interface.
-
-Defines the common interface between InMemoryProgress (server context)
-and Docket's Progress (worker context).
+### `get_server`
+```python
+get_server()
+```
-**Methods:**
-#### `current`
+Get the current FastMCP server instance directly.
-```python
-current(self) -> int | None
-```
+**Returns:**
+- The active FastMCP server
-Current progress value.
+**Raises:**
+- `RuntimeError`: If no server in context
-#### `total`
+### `get_http_request`
```python
-total(self) -> int
+get_http_request() -> Request
```
-Total/target progress value.
-
-
-#### `message`
+### `get_http_headers`
```python
-message(self) -> str | None
+get_http_headers(include_all: bool = False) -> dict[str, str]
```
-Current progress message.
-
-#### `set_total`
+Extract headers from the current HTTP request if available.
-```python
-set_total(self, total: int) -> None
-```
+Never raises an exception, even if there is no active HTTP request (in which case
+an empty dict is returned).
-Set the total/target value for progress tracking.
+By default, strips problematic headers like `content-length` that cause issues if forwarded to downstream clients.
+If `include_all` is True, all headers are returned.
-#### `increment`
+### `get_access_token`
```python
-increment(self, amount: int = 1) -> None
+get_access_token() -> AccessToken | None
```
-Atomically increment the current progress value.
+Get the FastMCP access token from the current context.
-#### `set_message`
+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.
-```python
-set_message(self, message: str | None) -> None
-```
+**Returns:**
+- The access token if an authenticated user is available, None otherwise.
-Update the progress status message.
+## Classes
-### `InMemoryProgress`
+### `InMemoryProgress`
In-memory progress tracker for immediate tool execution.
-Provides the same interface as Docket's Progress but stores state in memory
+Provides the same interface as 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`
+#### `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
@@ -371,7 +230,7 @@ set_total(self, total: int) -> None
Set the total/target value for progress tracking.
-#### `increment`
+#### `increment`
```python
increment(self, amount: int = 1) -> None
@@ -380,7 +239,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
@@ -389,17 +248,15 @@ set_message(self, message: str | None) -> None
Update the progress status message.
-### `Progress`
+### `Progress`
FastMCP Progress dependency that works in both server and worker contexts.
-Handles three execution modes:
-- In Docket worker: Uses the execution's progress (observable via Redis)
-- In FastMCP server with Docket: Falls back to in-memory progress
-- In FastMCP server without Docket: Uses in-memory progress
+Extends Docket's Progress to handle two execution modes:
+- In Docket worker: Uses the execution's progress (standard Docket behavior)
+- In FastMCP server: Uses in-memory progress (not observable remotely)
This allows tools to use Progress() regardless of whether they're called
-immediately or as background tasks, and regardless of whether pydocket
-is installed.
+immediately or as background tasks.
diff --git a/docs/python-sdk/fastmcp-server-elicitation.mdx b/docs/python-sdk/fastmcp-server-elicitation.mdx
index 47b1d0c4c2..c8c3267d00 100644
--- a/docs/python-sdk/fastmcp-server-elicitation.mdx
+++ b/docs/python-sdk/fastmcp-server-elicitation.mdx
@@ -28,7 +28,7 @@ Supports multiple syntaxes:
- Other types (dataclass, BaseModel): use directly
-### `handle_elicit_accept`
+### `handle_elicit_accept`
```python
handle_elicit_accept(config: ElicitConfig, content: Any) -> AcceptedElicitation[Any]
@@ -45,7 +45,7 @@ Handle an accepted elicitation response.
- AcceptedElicitation with the extracted/validated data
-### `get_elicitation_schema`
+### `get_elicitation_schema`
```python
get_elicitation_schema(response_type: type[T]) -> dict[str, Any]
@@ -58,7 +58,7 @@ Get the schema for an elicitation response.
- `response_type`: The type of the response
-### `validate_elicitation_json_schema`
+### `validate_elicitation_json_schema`
```python
validate_elicitation_json_schema(schema: dict[str, Any]) -> None
diff --git a/docs/python-sdk/fastmcp-server-http.mdx b/docs/python-sdk/fastmcp-server-http.mdx
index 64e82d57d4..8aaf2c9343 100644
--- a/docs/python-sdk/fastmcp-server-http.mdx
+++ b/docs/python-sdk/fastmcp-server-http.mdx
@@ -7,13 +7,13 @@ sidebarTitle: http
## Functions
-### `set_http_request`
+### `set_http_request`
```python
set_http_request(request: Request) -> Generator[Request, None, None]
```
-### `create_base_app`
+### `create_base_app`
```python
create_base_app(routes: list[BaseRoute], middleware: list[Middleware], debug: bool = False, lifespan: Callable | None = None) -> StarletteWithLifespan
@@ -32,7 +32,7 @@ Create a base Starlette app with common middleware and routes.
- A Starlette application
-### `create_sse_app`
+### `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
@@ -54,7 +54,7 @@ Returns:
A Starlette application with RequestContextMiddleware
-### `create_streamable_http_app`
+### `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) -> StarletteWithLifespan
@@ -83,24 +83,24 @@ disconnections. Requires event_store to be set. Defaults to SDK default.
## Classes
-### `StreamableHTTPASGIApp`
+### `StreamableHTTPASGIApp`
ASGI application wrapper for Streamable HTTP server transport.
-### `StarletteWithLifespan`
+### `StarletteWithLifespan`
**Methods:**
-#### `lifespan`
+#### `lifespan`
```python
lifespan(self) -> Lifespan[Starlette]
```
-### `RequestContextMiddleware`
+### `RequestContextMiddleware`
-Middleware that stores each request in a ContextVar and sets transport type.
+Middleware that stores each request in a ContextVar
diff --git a/docs/python-sdk/fastmcp-server-low_level.mdx b/docs/python-sdk/fastmcp-server-low_level.mdx
index 4a2212305b..40ef65ff11 100644
--- a/docs/python-sdk/fastmcp-server-low_level.mdx
+++ b/docs/python-sdk/fastmcp-server-low_level.mdx
@@ -43,20 +43,7 @@ Get the FastMCP instance.
create_initialization_options(self, notification_options: NotificationOptions | None = None, experimental_capabilities: dict[str, dict[str, Any]] | None = None, **kwargs: Any) -> InitializationOptions
```
-#### `get_capabilities`
-
-```python
-get_capabilities(self, notification_options: NotificationOptions, experimental_capabilities: dict[str, dict[str, Any]]) -> mcp.types.ServerCapabilities
-```
-
-Override to set capabilities.tasks as a first-class field per SEP-1686.
-
-This ensures task capabilities appear in capabilities.tasks instead of
-capabilities.experimental.tasks, which is required by the MCP spec and
-enables proper task detection by clients like VS Code Copilot 1.107+.
-
-
-#### `run`
+#### `run`
```python
run(self, read_stream: MemoryObjectReceiveStream[SessionMessage | Exception], write_stream: MemoryObjectSendStream[SessionMessage], initialization_options: InitializationOptions, raise_exceptions: bool = False, stateless: bool = False)
@@ -65,7 +52,7 @@ run(self, read_stream: MemoryObjectReceiveStream[SessionMessage | Exception], wr
Overrides the run method to use the MiddlewareServerSession.
-#### `read_resource`
+#### `read_resource`
```python
read_resource(self) -> Callable[[Callable[[AnyUrl], Awaitable[mcp.types.ReadResourceResult | mcp.types.CreateTaskResult]]], Callable[[AnyUrl], Awaitable[mcp.types.ReadResourceResult | mcp.types.CreateTaskResult]]]
@@ -80,7 +67,7 @@ This decorator can be removed once the MCP SDK adds native CreateTaskResult supp
for resources.
-#### `get_prompt`
+#### `get_prompt`
```python
get_prompt(self) -> Callable[[Callable[[str, dict[str, Any] | None], Awaitable[mcp.types.GetPromptResult | mcp.types.CreateTaskResult]]], Callable[[str, dict[str, Any] | None], Awaitable[mcp.types.GetPromptResult | mcp.types.CreateTaskResult]]]
diff --git a/docs/python-sdk/fastmcp-server-providers-base.mdx b/docs/python-sdk/fastmcp-server-providers-base.mdx
index 623c24e21b..12c036a084 100644
--- a/docs/python-sdk/fastmcp-server-providers-base.mdx
+++ b/docs/python-sdk/fastmcp-server-providers-base.mdx
@@ -36,7 +36,7 @@ Example:
## Classes
-### `Provider`
+### `Provider`
Base class for dynamic component providers.
@@ -48,22 +48,44 @@ supports.
**Methods:**
-#### `add_transform`
+#### `with_transforms`
```python
-add_transform(self, transform: Transform) -> None
+with_transforms(self) -> Provider
```
-Add a transform to this provider.
+Apply transformations to this provider's components.
-Transforms modify components (tools, resources, prompts) as they flow
-through the provider. They're applied in order - first added is innermost.
+Returns a TransformingProvider that wraps this provider and applies
+the specified transformations. Can be chained - each call creates a
+new wrapper that composes with the previous.
**Args:**
-- `transform`: The transform to add.
+- `namespace`: Prefix for tools/prompts ("namespace_name"), path segment
+for resources ("protocol\://namespace/path").
+- `tool_renames`: Map of original_name → final_name. Tools in this map
+use the specified name instead of namespace prefixing.
+**Returns:**
+- A TransformingProvider wrapping this provider.
+
+
+#### `with_namespace`
+
+```python
+with_namespace(self, namespace: str) -> Provider
+```
+
+Shorthand for with_transforms(namespace=...).
+
+**Args:**
+- `namespace`: The namespace to apply.
+
+**Returns:**
+- A TransformingProvider wrapping this provider.
-#### `list_tools`
+
+#### `list_tools`
```python
list_tools(self) -> Sequence[Tool]
@@ -71,31 +93,25 @@ list_tools(self) -> Sequence[Tool]
Return all available tools.
-Override to provide tools dynamically. Returns ALL versions of all tools.
-The server handles deduplication to show one tool per name.
+Override to provide tools dynamically.
-#### `get_tool`
+#### `get_tool`
```python
-get_tool(self, name: str, version: VersionSpec | None = None) -> Tool | None
+get_tool(self, name: str) -> Tool | None
```
Get a specific tool by name.
-Default implementation filters list_tools() and picks the highest version
-that matches the spec.
-
-**Args:**
-- `name`: The tool name.
-- `version`: Optional version filter. If None, returns highest version.
- If specified, returns highest version matching the spec.
+Default implementation lists all tools and finds by name.
+Override for more efficient single-tool lookup.
**Returns:**
- The Tool if found, or None to continue searching other providers.
-#### `list_resources`
+#### `list_resources`
```python
list_resources(self) -> Sequence[Resource]
@@ -103,30 +119,25 @@ list_resources(self) -> Sequence[Resource]
Return all available resources.
-Override to provide resources dynamically. Returns ALL versions of all resources.
-The server handles deduplication to show one resource per URI.
+Override to provide resources dynamically.
-#### `get_resource`
+#### `get_resource`
```python
-get_resource(self, uri: str, version: VersionSpec | None = None) -> Resource | None
+get_resource(self, uri: str) -> Resource | None
```
Get a specific resource by URI.
-Default implementation filters list_resources() and returns highest
-version matching the spec.
-
-**Args:**
-- `uri`: The resource URI.
-- `version`: Optional version filter. If None, returns highest version.
+Default implementation lists all resources and finds by URI.
+Override for more efficient single-resource lookup.
**Returns:**
- The Resource if found, or None to continue searching other providers.
-#### `list_resource_templates`
+#### `list_resource_templates`
```python
list_resource_templates(self) -> Sequence[ResourceTemplate]
@@ -134,30 +145,26 @@ list_resource_templates(self) -> Sequence[ResourceTemplate]
Return all available resource templates.
-Override to provide resource templates dynamically. Returns ALL versions.
-The server handles deduplication.
+Override to provide resource templates dynamically.
-#### `get_resource_template`
+#### `get_resource_template`
```python
-get_resource_template(self, uri: str, version: VersionSpec | None = None) -> ResourceTemplate | None
+get_resource_template(self, uri: str) -> ResourceTemplate | None
```
Get a resource template that matches the given URI.
-Default implementation lists all templates, finds those whose pattern
-matches the URI, and returns the highest version matching the spec.
-
-**Args:**
-- `uri`: The URI to match against templates.
-- `version`: Optional version filter. If None, returns highest version.
+Default implementation lists all templates and finds one whose pattern
+matches the URI.
+Override for more efficient lookup.
**Returns:**
- The ResourceTemplate if a matching one is found, or None to continue searching.
-#### `list_prompts`
+#### `list_prompts`
```python
list_prompts(self) -> Sequence[Prompt]
@@ -165,30 +172,40 @@ list_prompts(self) -> Sequence[Prompt]
Return all available prompts.
-Override to provide prompts dynamically. Returns ALL versions of all prompts.
-The server handles deduplication to show one prompt per name.
+Override to provide prompts dynamically.
-#### `get_prompt`
+#### `get_prompt`
```python
-get_prompt(self, name: str, version: VersionSpec | None = None) -> Prompt | None
+get_prompt(self, name: str) -> Prompt | None
```
Get a specific prompt by name.
-Default implementation filters list_prompts() and picks the highest version
-matching the spec.
+Default implementation lists all prompts and finds by name.
+Override for more efficient single-prompt lookup.
+
+**Returns:**
+- The Prompt if found, or None to continue searching other providers.
+
+
+#### `get_component`
+
+```python
+get_component(self, key: str) -> Tool | Resource | ResourceTemplate | Prompt | None
+```
+
+Get a component by its prefixed key.
**Args:**
-- `name`: The prompt name.
-- `version`: Optional version filter. If None, returns highest version.
+- `key`: The prefixed key (e.g., "tool\:name", "resource\:uri", "template\:uri").
**Returns:**
-- The Prompt if found, or None to continue searching other providers.
+- The component if found, or None to continue searching other providers.
-#### `get_tasks`
+#### `get_tasks`
```python
get_tasks(self) -> Sequence[FastMCPComponent]
@@ -197,13 +214,13 @@ get_tasks(self) -> Sequence[FastMCPComponent]
Return components that should be registered as background tasks.
Override to customize which components are task-eligible.
-Default calls list_* methods, applies provider transforms, and filters
-for components with task_config.mode != 'forbidden'.
+Default calls list_* methods and filters for components
+with task_config.mode != 'forbidden'.
Used by the server during startup to register functions with Docket.
-#### `lifespan`
+#### `lifespan`
```python
lifespan(self) -> AsyncIterator[None]
@@ -219,7 +236,7 @@ The lifespan scope matches the server's lifespan - code before yield
runs at startup, code after yield runs at shutdown.
-#### `enable`
+#### `enable`
```python
enable(self) -> None
@@ -228,12 +245,12 @@ enable(self) -> None
Enable components by removing from blocklist, or set allowlist with only=True.
**Args:**
-- `keys`: Keys to enable (e.g., "tool\:my_tool@" for unversioned, "tool\:my_tool@1.0" for versioned).
+- `keys`: Keys to enable (e.g., "tool\:my_tool").
- `tags`: Tags to enable - components with these tags will be enabled.
- `only`: If True, switches to allowlist mode - ONLY show these keys/tags.
-#### `disable`
+#### `disable`
```python
disable(self) -> None
@@ -242,6 +259,6 @@ disable(self) -> None
Disable components by adding to the blocklist.
**Args:**
-- `keys`: Keys to disable (e.g., "tool\:my_tool@" for unversioned, "tool\:my_tool@1.0" for versioned).
+- `keys`: Keys to disable (e.g., "tool\:my_tool").
- `tags`: Tags to disable - components with these tags will be disabled.
diff --git a/docs/python-sdk/fastmcp-server-providers-fastmcp_provider.mdx b/docs/python-sdk/fastmcp-server-providers-fastmcp_provider.mdx
index b12db1ca1b..32f940c040 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,25 +39,19 @@ 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
+run(self, arguments: dict[str, Any]) -> ToolResult | mcp.types.CreateTaskResult
```
-Delegate to child server's call_tool() without task_meta.
+Not implemented - use _run() which delegates to child server.
-This is called when the tool is used within a TransformedTool
-forwarding function or other contexts where task_meta is not available.
+FastMCPProviderTool._run() handles all execution by delegating
+to the child server's call_tool() with task_meta.
-#### `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 +62,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 +71,7 @@ wrap(cls, server: Any, resource: Resource) -> FastMCPProviderResource
Wrap a Resource to delegate reading to the server's middleware.
-#### `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 +82,7 @@ When `render()` is called, this prompt invokes the wrapped server's
**Methods:**
-#### `wrap`
+#### `wrap`
```python
wrap(cls, server: Any, prompt: Prompt) -> FastMCPProviderPrompt
@@ -103,25 +91,19 @@ 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
+render(self, arguments: dict[str, Any] | None = None) -> PromptResult | mcp.types.CreateTaskResult
```
-Delegate to child server's render_prompt() without task_meta.
-
-This is called when the prompt is used within a transformed context
-or other contexts where task_meta is not available.
+Not implemented - use _render() which delegates to child server.
+FastMCPProviderPrompt._render() handles all execution by delegating
+to the child server's render_prompt() with task_meta.
-#### `get_span_attributes`
-```python
-get_span_attributes(self) -> dict[str, Any]
-```
-
-### `FastMCPProviderResourceTemplate`
+### `FastMCPProviderResourceTemplate`
Resource template that creates FastMCPProviderResources.
@@ -133,7 +115,7 @@ when read.
**Methods:**
-#### `wrap`
+#### `wrap`
```python
wrap(cls, server: Any, template: ResourceTemplate) -> FastMCPProviderResourceTemplate
@@ -142,7 +124,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 +137,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 +149,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 +158,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 +170,7 @@ The child's FunctionResourceTemplate.fn is registered (via get_tasks),
and it expects splatted **kwargs, so we splat params here.
-#### `get_span_attributes`
-
-```python
-get_span_attributes(self) -> dict[str, Any]
-```
-
-### `FastMCPProvider`
+### `FastMCPProvider`
Provider that wraps a FastMCP server.
@@ -210,7 +186,7 @@ This ensures middleware runs when components are executed.
**Methods:**
-#### `list_tools`
+#### `list_tools`
```python
list_tools(self) -> Sequence[Tool]
@@ -223,19 +199,16 @@ each tool as a FastMCPProviderTool that delegates execution to the
nested server's middleware.
-#### `get_tool`
+#### `get_tool`
```python
-get_tool(self, name: str, version: VersionSpec | None = None) -> Tool | None
+get_tool(self, name: str) -> Tool | None
```
Get a tool by name as a FastMCPProviderTool.
-Passes the full VersionSpec to the nested server, which handles both
-exact version matching and range filtering.
-
-#### `list_resources`
+#### `list_resources`
```python
list_resources(self) -> Sequence[Resource]
@@ -248,19 +221,16 @@ each resource as a FastMCPProviderResource that delegates reading to the
nested server's middleware.
-#### `get_resource`
+#### `get_resource`
```python
-get_resource(self, uri: str, version: VersionSpec | None = None) -> Resource | None
+get_resource(self, uri: str) -> Resource | None
```
Get a concrete resource by URI as a FastMCPProviderResource.
-Passes the full VersionSpec to the nested server, which handles both
-exact version matching and range filtering.
-
-#### `list_resource_templates`
+#### `list_resource_templates`
```python
list_resource_templates(self) -> Sequence[ResourceTemplate]
@@ -272,19 +242,16 @@ Returns FastMCPProviderResourceTemplate instances that create
FastMCPProviderResources when materialized.
-#### `get_resource_template`
+#### `get_resource_template`
```python
-get_resource_template(self, uri: str, version: VersionSpec | None = None) -> ResourceTemplate | None
+get_resource_template(self, uri: str) -> ResourceTemplate | None
```
Get a resource template that matches the given URI.
-Passes the full VersionSpec to the nested server, which handles both
-exact version matching and range filtering.
-
-#### `list_prompts`
+#### `list_prompts`
```python
list_prompts(self) -> Sequence[Prompt]
@@ -296,19 +263,16 @@ Returns FastMCPProviderPrompt instances that delegate rendering to the
wrapped server's middleware.
-#### `get_prompt`
+#### `get_prompt`
```python
-get_prompt(self, name: str, version: VersionSpec | None = None) -> Prompt | None
+get_prompt(self, name: str) -> Prompt | None
```
Get a prompt by name as a FastMCPProviderPrompt.
-Passes the full VersionSpec to the nested server, which handles both
-exact version matching and range filtering.
-
-#### `get_tasks`
+#### `get_tasks`
```python
get_tasks(self) -> Sequence[FastMCPComponent]
@@ -317,12 +281,14 @@ get_tasks(self) -> Sequence[FastMCPComponent]
Return task-eligible components from the mounted server.
Returns the child's ACTUAL components (not wrapped) so their actual
-functions get registered with Docket. Uses _source_get_tasks() to get
-components with child server's transforms applied, then applies this
-provider's transforms for correct registration keys.
+functions get registered with Docket. TransformingProvider.get_tasks()
+handles namespace transformation of keys.
+
+Iterates through all providers in the wrapped server (including its
+LocalProvider) to collect task-eligible components.
-#### `lifespan`
+#### `lifespan`
```python
lifespan(self) -> AsyncIterator[None]
diff --git a/docs/python-sdk/fastmcp-server-providers-local_provider.mdx b/docs/python-sdk/fastmcp-server-providers-local_provider.mdx
index 247d9e1ba7..f002b48b1d 100644
--- a/docs/python-sdk/fastmcp-server-providers-local_provider.mdx
+++ b/docs/python-sdk/fastmcp-server-providers-local_provider.mdx
@@ -47,135 +47,137 @@ like `_tool_serializer` and `_support_tasks_by_default` are injected.
**Methods:**
-#### `add_tool`
+#### `add_tool`
```python
-add_tool(self, tool: Tool | Callable[..., Any]) -> Tool
+add_tool(self, tool: Tool) -> Tool
```
Add a tool to this provider's storage.
-Accepts either a Tool object or a decorated function with __fastmcp__ metadata.
-
-#### `remove_tool`
+#### `remove_tool`
```python
-remove_tool(self, name: str, version: str | None = None) -> None
+remove_tool(self, name: str) -> None
```
-Remove tool(s) from this provider's storage.
+Remove a tool from this provider's storage.
-**Args:**
-- `name`: The tool name.
-- `version`: If None, removes ALL versions. If specified, removes only that version.
-**Raises:**
-- `KeyError`: If no matching tool is found.
+#### `add_resource`
+
+```python
+add_resource(self, resource: Resource) -> Resource
+```
+Add a resource to this provider's storage.
-#### `add_resource`
+
+#### `remove_resource`
```python
-add_resource(self, resource: Resource | ResourceTemplate | Callable[..., Any]) -> Resource | ResourceTemplate
+remove_resource(self, uri: str) -> None
```
-Add a resource to this provider's storage.
+Remove a resource from this provider's storage.
-Accepts either a Resource/ResourceTemplate object or a decorated function with __fastmcp__ metadata.
+#### `add_template`
-#### `remove_resource`
+```python
+add_template(self, template: ResourceTemplate) -> ResourceTemplate
+```
+
+Add a resource template to this provider's storage.
+
+
+#### `remove_template`
```python
-remove_resource(self, uri: str, version: str | None = None) -> None
+remove_template(self, uri_template: str) -> None
```
-Remove resource(s) from this provider's storage.
+Remove a resource template from this provider's storage.
-**Args:**
-- `uri`: The resource URI.
-- `version`: If None, removes ALL versions. If specified, removes only that version.
-**Raises:**
-- `KeyError`: If no matching resource is found.
+#### `add_prompt`
+
+```python
+add_prompt(self, prompt: Prompt) -> Prompt
+```
+
+Add a prompt to this provider's storage.
-#### `add_template`
+#### `remove_prompt`
```python
-add_template(self, template: ResourceTemplate) -> ResourceTemplate
+remove_prompt(self, name: str) -> None
```
-Add a resource template to this provider's storage.
+Remove a prompt from this provider's storage.
-#### `remove_template`
+#### `add_tool_transformation`
```python
-remove_template(self, uri_template: str, version: str | None = None) -> None
+add_tool_transformation(self, tool_name: str, transformation: ToolTransformConfig) -> None
```
-Remove resource template(s) from this provider's storage.
+Add a tool transformation.
**Args:**
-- `uri_template`: The template URI pattern.
-- `version`: If None, removes ALL versions. If specified, removes only that version.
-
-**Raises:**
-- `KeyError`: If no matching template is found.
+- `tool_name`: The name of the tool to transform.
+- `transformation`: The transformation configuration.
-#### `add_prompt`
+#### `get_tool_transformation`
```python
-add_prompt(self, prompt: Prompt | Callable[..., Any]) -> Prompt
+get_tool_transformation(self, tool_name: str) -> ToolTransformConfig | None
```
-Add a prompt to this provider's storage.
+Get a tool transformation.
-Accepts either a Prompt object or a decorated function with __fastmcp__ metadata.
+**Args:**
+- `tool_name`: The name of the tool.
+**Returns:**
+- The transformation config, or None if not found.
-#### `remove_prompt`
+
+#### `remove_tool_transformation`
```python
-remove_prompt(self, name: str, version: str | None = None) -> None
+remove_tool_transformation(self, tool_name: str) -> None
```
-Remove prompt(s) from this provider's storage.
+Remove a tool transformation.
**Args:**
-- `name`: The prompt name.
-- `version`: If None, removes ALL versions. If specified, removes only that version.
-
-**Raises:**
-- `KeyError`: If no matching prompt is found.
+- `tool_name`: The name of the tool.
-#### `list_tools`
+#### `list_tools`
```python
list_tools(self) -> Sequence[Tool]
```
-Return all visible tools.
+Return all visible tools with transformations applied.
-#### `get_tool`
+#### `get_tool`
```python
-get_tool(self, name: str, version: VersionSpec | None = None) -> Tool | None
+get_tool(self, name: str) -> Tool | None
```
-Get a tool by name.
+Get a tool by name, with transformations applied.
-**Args:**
-- `name`: The tool name.
-- `version`: Optional version filter. If None, returns highest version.
-
-#### `list_resources`
+#### `list_resources`
```python
list_resources(self) -> Sequence[Resource]
@@ -184,20 +186,16 @@ list_resources(self) -> Sequence[Resource]
Return all visible resources.
-#### `get_resource`
+#### `get_resource`
```python
-get_resource(self, uri: str, version: VersionSpec | None = None) -> Resource | None
+get_resource(self, uri: str) -> Resource | None
```
-Get a resource by URI.
+Get a resource by URI if visible.
-**Args:**
-- `uri`: The resource URI.
-- `version`: Optional version filter. If None, returns highest version.
-
-#### `list_resource_templates`
+#### `list_resource_templates`
```python
list_resource_templates(self) -> Sequence[ResourceTemplate]
@@ -206,20 +204,16 @@ list_resource_templates(self) -> Sequence[ResourceTemplate]
Return all visible resource templates.
-#### `get_resource_template`
+#### `get_resource_template`
```python
-get_resource_template(self, uri: str, version: VersionSpec | None = None) -> ResourceTemplate | None
+get_resource_template(self, uri: str) -> ResourceTemplate | None
```
-Get a resource template that matches the given URI.
-
-**Args:**
-- `uri`: The URI to match against templates.
-- `version`: Optional version filter. If None, returns highest version.
+Get a resource template that matches the given URI if visible.
-#### `list_prompts`
+#### `list_prompts`
```python
list_prompts(self) -> Sequence[Prompt]
@@ -228,20 +222,27 @@ list_prompts(self) -> Sequence[Prompt]
Return all visible prompts.
-#### `get_prompt`
+#### `get_prompt`
```python
-get_prompt(self, name: str, version: VersionSpec | None = None) -> Prompt | None
+get_prompt(self, name: str) -> Prompt | None
```
-Get a prompt by name.
+Get a prompt by name if visible.
-**Args:**
-- `name`: The prompt name.
-- `version`: Optional version filter. If None, returns highest version.
+
+#### `get_component`
+
+```python
+get_component(self, key: str) -> Tool | Resource | ResourceTemplate | Prompt | None
+```
+
+Get a component by its prefixed key.
+
+Efficient O(1) lookup in the unified components dict.
-#### `get_tasks`
+#### `get_tasks`
```python
get_tasks(self) -> Sequence[FastMCPComponent]
@@ -254,19 +255,19 @@ This includes both FunctionTool/Resource/Prompt instances created via
decorators and custom Tool/Resource/Prompt subclasses.
-#### `tool`
+#### `tool`
```python
tool(self, name_or_fn: AnyFunction) -> FunctionTool
```
-#### `tool`
+#### `tool`
```python
tool(self, name_or_fn: str | None = None) -> Callable[[AnyFunction], FunctionTool]
```
-#### `tool`
+#### `tool`
```python
tool(self, name_or_fn: str | AnyFunction | None = None) -> Callable[[AnyFunction], FunctionTool] | FunctionTool | partial[Callable[[AnyFunction], FunctionTool] | FunctionTool]
@@ -300,10 +301,10 @@ This decorator supports multiple calling patterns:
- The registered FunctionTool or a decorator function.
-#### `resource`
+#### `resource`
```python
-resource(self, uri: str) -> Callable[[AnyFunction], Resource | ResourceTemplate | AnyFunction]
+resource(self, uri: str) -> Callable[[AnyFunction], Resource | ResourceTemplate]
```
Decorator to register a function as a resource.
@@ -323,25 +324,24 @@ has parameters, it will be registered as a template resource.
- `annotations`: Optional annotations about the resource's behavior
- `meta`: Optional meta information about the resource
- `task`: Optional task configuration for background execution
-- `auth`: Optional authorization checks for the resource
**Returns:**
- A decorator function.
-#### `prompt`
+#### `prompt`
```python
prompt(self, name_or_fn: AnyFunction) -> FunctionPrompt
```
-#### `prompt`
+#### `prompt`
```python
prompt(self, name_or_fn: str | None = None) -> Callable[[AnyFunction], FunctionPrompt]
```
-#### `prompt`
+#### `prompt`
```python
prompt(self, name_or_fn: str | AnyFunction | None = None) -> Callable[[AnyFunction], FunctionPrompt] | FunctionPrompt | partial[Callable[[AnyFunction], FunctionPrompt] | FunctionPrompt]
@@ -366,7 +366,6 @@ This decorator supports multiple calling patterns:
- `enabled`: Whether the prompt is enabled (default True). If False, adds to blocklist.
- `meta`: Optional meta information about the prompt
- `task`: Optional task configuration for background execution
-- `auth`: Optional authorization checks for the prompt
**Returns:**
- The registered FunctionPrompt or a decorator function.
diff --git a/docs/python-sdk/fastmcp-server-providers-openapi-provider.mdx b/docs/python-sdk/fastmcp-server-providers-openapi-provider.mdx
index 2e262c5258..2df5a64491 100644
--- a/docs/python-sdk/fastmcp-server-providers-openapi-provider.mdx
+++ b/docs/python-sdk/fastmcp-server-providers-openapi-provider.mdx
@@ -10,7 +10,7 @@ OpenAPIProvider for creating MCP components from OpenAPI specifications.
## Classes
-### `OpenAPIProvider`
+### `OpenAPIProvider`
Provider that creates MCP components from an OpenAPI specification.
@@ -21,7 +21,7 @@ spec. Each component makes HTTP calls to the described API endpoints.
**Methods:**
-#### `list_tools`
+#### `list_tools`
```python
list_tools(self) -> Sequence[Tool]
@@ -30,16 +30,16 @@ list_tools(self) -> Sequence[Tool]
Return all tools created from the OpenAPI spec.
-#### `get_tool`
+#### `get_tool`
```python
-get_tool(self, name: str, version: VersionSpec | None = None) -> Tool | None
+get_tool(self, name: str) -> Tool | None
```
Get a tool by name.
-#### `list_resources`
+#### `list_resources`
```python
list_resources(self) -> Sequence[Resource]
@@ -48,16 +48,16 @@ list_resources(self) -> Sequence[Resource]
Return all resources created from the OpenAPI spec.
-#### `get_resource`
+#### `get_resource`
```python
-get_resource(self, uri: str, version: VersionSpec | None = None) -> Resource | None
+get_resource(self, uri: str) -> Resource | None
```
Get a resource by URI.
-#### `list_resource_templates`
+#### `list_resource_templates`
```python
list_resource_templates(self) -> Sequence[ResourceTemplate]
@@ -66,16 +66,16 @@ list_resource_templates(self) -> Sequence[ResourceTemplate]
Return all resource templates created from the OpenAPI spec.
-#### `get_resource_template`
+#### `get_resource_template`
```python
-get_resource_template(self, uri: str, version: VersionSpec | None = None) -> ResourceTemplate | None
+get_resource_template(self, uri: str) -> ResourceTemplate | None
```
Get a resource template that matches the given URI.
-#### `list_prompts`
+#### `list_prompts`
```python
list_prompts(self) -> Sequence[Prompt]
@@ -84,7 +84,7 @@ list_prompts(self) -> Sequence[Prompt]
Return empty list - OpenAPI doesn't create prompts.
-#### `get_tasks`
+#### `get_tasks`
```python
get_tasks(self) -> Sequence[FastMCPComponent]
diff --git a/docs/python-sdk/fastmcp-server-providers-proxy.mdx b/docs/python-sdk/fastmcp-server-providers-proxy.mdx
index 55aca8243f..90e7796470 100644
--- a/docs/python-sdk/fastmcp-server-providers-proxy.mdx
+++ b/docs/python-sdk/fastmcp-server-providers-proxy.mdx
@@ -15,7 +15,7 @@ classes that forward execution to remote servers.
## Functions
-### `default_proxy_roots_handler`
+### `default_proxy_roots_handler`
```python
default_proxy_roots_handler(context: RequestContext[ClientSession, LifespanContextT]) -> RootsList
@@ -25,7 +25,7 @@ default_proxy_roots_handler(context: RequestContext[ClientSession, LifespanConte
Forward list roots request from remote server to proxy's connected clients.
-### `default_proxy_sampling_handler`
+### `default_proxy_sampling_handler`
```python
default_proxy_sampling_handler(messages: list[mcp.types.SamplingMessage], params: mcp.types.CreateMessageRequestParams, context: RequestContext[ClientSession, LifespanContextT]) -> mcp.types.CreateMessageResult
@@ -35,7 +35,7 @@ default_proxy_sampling_handler(messages: list[mcp.types.SamplingMessage], params
Forward sampling request from remote server to proxy's connected clients.
-### `default_proxy_elicitation_handler`
+### `default_proxy_elicitation_handler`
```python
default_proxy_elicitation_handler(message: str, response_type: type, params: mcp.types.ElicitRequestParams, context: RequestContext[ClientSession, LifespanContextT]) -> ElicitResult
@@ -45,7 +45,7 @@ default_proxy_elicitation_handler(message: str, response_type: type, params: mcp
Forward elicitation request from remote server to proxy's connected clients.
-### `default_proxy_log_handler`
+### `default_proxy_log_handler`
```python
default_proxy_log_handler(message: LogMessage) -> None
@@ -55,7 +55,7 @@ default_proxy_log_handler(message: LogMessage) -> None
Forward log notification from remote server to proxy's connected clients.
-### `default_proxy_progress_handler`
+### `default_proxy_progress_handler`
```python
default_proxy_progress_handler(progress: float, total: float | None, message: str | None) -> None
@@ -67,7 +67,7 @@ Forward progress notification from remote server to proxy's connected clients.
## Classes
-### `ProxyTool`
+### `ProxyTool`
A Tool that represents and executes a tool on a remote server.
@@ -75,7 +75,7 @@ A Tool that represents and executes a tool on a remote server.
**Methods:**
-#### `model_copy`
+#### `model_copy`
```python
model_copy(self, **kwargs: Any) -> ProxyTool
@@ -84,7 +84,7 @@ model_copy(self, **kwargs: Any) -> ProxyTool
Override to preserve _backend_name when name changes.
-#### `from_mcp_tool`
+#### `from_mcp_tool`
```python
from_mcp_tool(cls, client_factory: ClientFactoryT, mcp_tool: mcp.types.Tool) -> ProxyTool
@@ -93,7 +93,7 @@ from_mcp_tool(cls, client_factory: ClientFactoryT, mcp_tool: mcp.types.Tool) ->
Factory method to create a ProxyTool from a raw MCP tool schema.
-#### `run`
+#### `run`
```python
run(self, arguments: dict[str, Any], context: Context | None = None) -> ToolResult
@@ -102,13 +102,7 @@ run(self, arguments: dict[str, Any], context: Context | None = None) -> ToolResu
Executes the tool by making a call through the client.
-#### `get_span_attributes`
-
-```python
-get_span_attributes(self) -> dict[str, Any]
-```
-
-### `ProxyResource`
+### `ProxyResource`
A Resource that represents and reads a resource from a remote server.
@@ -116,7 +110,7 @@ A Resource that represents and reads a resource from a remote server.
**Methods:**
-#### `model_copy`
+#### `model_copy`
```python
model_copy(self, **kwargs: Any) -> ProxyResource
@@ -125,7 +119,7 @@ model_copy(self, **kwargs: Any) -> ProxyResource
Override to preserve _backend_uri when uri changes.
-#### `from_mcp_resource`
+#### `from_mcp_resource`
```python
from_mcp_resource(cls, client_factory: ClientFactoryT, mcp_resource: mcp.types.Resource) -> ProxyResource
@@ -134,7 +128,7 @@ from_mcp_resource(cls, client_factory: ClientFactoryT, mcp_resource: mcp.types.R
Factory method to create a ProxyResource from a raw MCP resource schema.
-#### `read`
+#### `read`
```python
read(self) -> ResourceResult
@@ -143,13 +137,7 @@ read(self) -> ResourceResult
Read the resource content from the remote server.
-#### `get_span_attributes`
-
-```python
-get_span_attributes(self) -> dict[str, Any]
-```
-
-### `ProxyTemplate`
+### `ProxyTemplate`
A ResourceTemplate that represents and creates resources from a remote server template.
@@ -157,7 +145,7 @@ A ResourceTemplate that represents and creates resources from a remote server te
**Methods:**
-#### `model_copy`
+#### `model_copy`
```python
model_copy(self, **kwargs: Any) -> ProxyTemplate
@@ -166,7 +154,7 @@ model_copy(self, **kwargs: Any) -> ProxyTemplate
Override to preserve _backend_uri_template when uri_template changes.
-#### `from_mcp_template`
+#### `from_mcp_template`
```python
from_mcp_template(cls, client_factory: ClientFactoryT, mcp_template: mcp.types.ResourceTemplate) -> ProxyTemplate
@@ -175,7 +163,7 @@ from_mcp_template(cls, client_factory: ClientFactoryT, mcp_template: mcp.types.R
Factory method to create a ProxyTemplate from a raw MCP template schema.
-#### `create_resource`
+#### `create_resource`
```python
create_resource(self, uri: str, params: dict[str, Any], context: Context | None = None) -> ProxyResource
@@ -184,13 +172,7 @@ create_resource(self, uri: str, params: dict[str, Any], context: Context | None
Create a resource from the template by calling the remote server.
-#### `get_span_attributes`
-
-```python
-get_span_attributes(self) -> dict[str, Any]
-```
-
-### `ProxyPrompt`
+### `ProxyPrompt`
A Prompt that represents and renders a prompt from a remote server.
@@ -198,7 +180,7 @@ A Prompt that represents and renders a prompt from a remote server.
**Methods:**
-#### `model_copy`
+#### `model_copy`
```python
model_copy(self, **kwargs: Any) -> ProxyPrompt
@@ -207,7 +189,7 @@ model_copy(self, **kwargs: Any) -> ProxyPrompt
Override to preserve _backend_name when name changes.
-#### `from_mcp_prompt`
+#### `from_mcp_prompt`
```python
from_mcp_prompt(cls, client_factory: ClientFactoryT, mcp_prompt: mcp.types.Prompt) -> ProxyPrompt
@@ -216,7 +198,7 @@ from_mcp_prompt(cls, client_factory: ClientFactoryT, mcp_prompt: mcp.types.Promp
Factory method to create a ProxyPrompt from a raw MCP prompt schema.
-#### `render`
+#### `render`
```python
render(self, arguments: dict[str, Any]) -> PromptResult
@@ -225,13 +207,7 @@ render(self, arguments: dict[str, Any]) -> PromptResult
Render the prompt by making a call through the client.
-#### `get_span_attributes`
-
-```python
-get_span_attributes(self) -> dict[str, Any]
-```
-
-### `ProxyProvider`
+### `ProxyProvider`
Provider that proxies to a remote MCP server via a client factory.
@@ -245,7 +221,7 @@ because tasks cannot be executed through a proxy.
**Methods:**
-#### `list_tools`
+#### `list_tools`
```python
list_tools(self) -> Sequence[Tool]
@@ -254,7 +230,7 @@ list_tools(self) -> Sequence[Tool]
List all tools from the remote server.
-#### `list_resources`
+#### `list_resources`
```python
list_resources(self) -> Sequence[Resource]
@@ -263,7 +239,7 @@ list_resources(self) -> Sequence[Resource]
List all resources from the remote server.
-#### `list_resource_templates`
+#### `list_resource_templates`
```python
list_resource_templates(self) -> Sequence[ResourceTemplate]
@@ -272,7 +248,7 @@ list_resource_templates(self) -> Sequence[ResourceTemplate]
List all resource templates from the remote server.
-#### `list_prompts`
+#### `list_prompts`
```python
list_prompts(self) -> Sequence[Prompt]
@@ -281,7 +257,7 @@ list_prompts(self) -> Sequence[Prompt]
List all prompts from the remote server.
-#### `get_tasks`
+#### `get_tasks`
```python
get_tasks(self) -> Sequence[FastMCPComponent]
@@ -294,7 +270,7 @@ server lifespan initialization, which would open the client before any
context is set. All Proxy* components have task_config.mode="forbidden".
-### `FastMCPProxy`
+### `FastMCPProxy`
A FastMCP server that acts as a proxy to a remote MCP-compliant server.
@@ -303,7 +279,7 @@ This is a convenience wrapper that creates a FastMCP server with a
ProxyProvider. For more control, use FastMCP with add_provider(ProxyProvider(...)).
-### `ProxyClient`
+### `ProxyClient`
A proxy client that forwards advanced interactions between a remote MCP server and the proxy's connected clients.
@@ -311,7 +287,7 @@ A proxy client that forwards advanced interactions between a remote MCP server a
Supports forwarding roots, sampling, elicitation, logging, and progress.
-### `StatefulProxyClient`
+### `StatefulProxyClient`
A proxy client that provides a stateful client factory for the proxy server.
@@ -325,7 +301,7 @@ Note that it is essential to ensure that the proxy server itself is also statefu
**Methods:**
-#### `clear`
+#### `clear`
```python
clear(self)
@@ -334,7 +310,7 @@ clear(self)
Clear all cached clients and force disconnect them.
-#### `new_stateful`
+#### `new_stateful`
```python
new_stateful(self) -> Client[ClientTransportT]
diff --git a/docs/python-sdk/fastmcp-server-providers-transforming.mdx b/docs/python-sdk/fastmcp-server-providers-transforming.mdx
new file mode 100644
index 0000000000..94952eac2a
--- /dev/null
+++ b/docs/python-sdk/fastmcp-server-providers-transforming.mdx
@@ -0,0 +1,117 @@
+---
+title: transforming
+sidebarTitle: transforming
+---
+
+# `fastmcp.server.providers.transforming`
+
+
+TransformingProvider for applying component transformations.
+
+This module provides the `TransformingProvider` class that wraps any Provider
+and applies transformations like namespace prefixes and tool renames.
+
+
+## Classes
+
+### `TransformingProvider`
+
+
+Wraps any provider and applies component transformations.
+
+Users typically use `provider.with_transforms()` rather than instantiating
+this class directly. Multiple `.with_transforms()` calls stack - each
+creates a new wrapper that composes with the previous.
+
+
+**Methods:**
+
+#### `list_tools`
+
+```python
+list_tools(self) -> Sequence[Tool]
+```
+
+List tools with transformations applied.
+
+
+#### `get_tool`
+
+```python
+get_tool(self, name: str) -> Tool | None
+```
+
+Get tool by transformed name.
+
+
+#### `list_resources`
+
+```python
+list_resources(self) -> Sequence[Resource]
+```
+
+List resources with URI transformations applied.
+
+
+#### `get_resource`
+
+```python
+get_resource(self, uri: str) -> Resource | None
+```
+
+Get resource by transformed URI.
+
+
+#### `list_resource_templates`
+
+```python
+list_resource_templates(self) -> Sequence[ResourceTemplate]
+```
+
+List resource templates with URI transformations applied.
+
+
+#### `get_resource_template`
+
+```python
+get_resource_template(self, uri: str) -> ResourceTemplate | None
+```
+
+Get resource template by transformed URI.
+
+
+#### `list_prompts`
+
+```python
+list_prompts(self) -> Sequence[Prompt]
+```
+
+List prompts with transformations applied.
+
+
+#### `get_prompt`
+
+```python
+get_prompt(self, name: str) -> Prompt | None
+```
+
+Get prompt by transformed name.
+
+
+#### `get_tasks`
+
+```python
+get_tasks(self) -> Sequence[FastMCPComponent]
+```
+
+Get tasks with transformations applied to all components.
+
+
+#### `lifespan`
+
+```python
+lifespan(self) -> AsyncIterator[None]
+```
+
+Delegate lifespan to wrapped provider.
+
diff --git a/docs/python-sdk/fastmcp-server-server.mdx b/docs/python-sdk/fastmcp-server-server.mdx
index b627ea0bb4..da73702c32 100644
--- a/docs/python-sdk/fastmcp-server-server.mdx
+++ b/docs/python-sdk/fastmcp-server-server.mdx
@@ -10,7 +10,7 @@ FastMCP - A more ergonomic interface for MCP servers.
## Functions
-### `default_lifespan`
+### `default_lifespan`
```python
default_lifespan(server: FastMCP[LifespanResultT]) -> AsyncIterator[Any]
@@ -26,7 +26,7 @@ Default lifespan context manager that does nothing.
- An empty dictionary as the lifespan result.
-### `create_proxy`
+### `create_proxy`
```python
create_proxy(target: Client[ClientTransportT] | ClientTransport | FastMCP[Any] | FastMCP1Server | AnyUrl | Path | MCPConfig | dict[str, Any] | str, **settings: Any) -> FastMCPProxy
@@ -54,59 +54,53 @@ use `FastMCPProxy` or `ProxyProvider` directly from `fastmcp.server.providers.pr
## Classes
-### `StateValue`
-
-
-Wrapper for stored context state values.
-
-
-### `FastMCP`
+### `FastMCP`
**Methods:**
-#### `settings`
+#### `settings`
```python
settings(self) -> Settings
```
-#### `name`
+#### `name`
```python
name(self) -> str
```
-#### `instructions`
+#### `instructions`
```python
instructions(self) -> str | None
```
-#### `instructions`
+#### `instructions`
```python
instructions(self, value: str | None) -> None
```
-#### `version`
+#### `version`
```python
version(self) -> str | None
```
-#### `website_url`
+#### `website_url`
```python
website_url(self) -> str | None
```
-#### `icons`
+#### `icons`
```python
icons(self) -> list[mcp.types.Icon]
```
-#### `docket`
+#### `docket`
```python
docket(self) -> Docket | None
@@ -117,7 +111,7 @@ Get the Docket instance if Docket support is enabled.
Returns None if Docket is not enabled or server hasn't been started yet.
-#### `run_async`
+#### `run_async`
```python
run_async(self, transport: Transport | None = None, show_banner: bool | None = None, **transport_kwargs: Any) -> None
@@ -131,7 +125,7 @@ Run the FastMCP server asynchronously.
FASTMCP_SHOW_SERVER_BANNER setting (default\: True).
-#### `run`
+#### `run`
```python
run(self, transport: Transport | None = None, show_banner: bool | None = None, **transport_kwargs: Any) -> None
@@ -145,13 +139,13 @@ Run the FastMCP server. Note this is a synchronous function.
FASTMCP_SHOW_SERVER_BANNER setting (default\: True).
-#### `add_middleware`
+#### `add_middleware`
```python
add_middleware(self, middleware: Middleware) -> None
```
-#### `add_provider`
+#### `add_provider`
```python
add_provider(self, provider: Provider) -> None
@@ -167,46 +161,7 @@ always take precedence over providers.
- `provider`: A Provider instance that will provide components dynamically.
-#### `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.
-
-
-#### `add_tool_transformation`
-
-```python
-add_tool_transformation(self, tool_name: str, transformation: ToolTransformConfig) -> None
-```
-
-Add a tool transformation.
-
-.. deprecated::
- Use ``add_transform(ToolTransform({...}))`` instead.
-
-
-#### `remove_tool_transformation`
-
-```python
-remove_tool_transformation(self, _tool_name: str) -> None
-```
-
-Remove a tool transformation.
-
-.. deprecated::
- Tool transformations are now immutable. Use visibility controls instead.
-
-
-#### `enable`
+#### `enable`
```python
enable(self) -> None
@@ -215,13 +170,13 @@ enable(self) -> None
Enable components by removing from blocklist, or set allowlist with only=True.
**Args:**
-- `keys`: Keys to enable (e.g., ``"tool\:my_tool@"`` for unversioned, ``"tool\:my_tool@1.0"`` for versioned).
+- `keys`: Keys to enable (e.g., ``"tool\:my_tool"``).
- `tags`: Tags to enable - components with these tags will be enabled.
- `only`: If True, switches to allowlist mode - ONLY show these keys/tags.
This clears existing allowlists and sets default visibility to False.
-#### `disable`
+#### `disable`
```python
disable(self) -> None
@@ -230,11 +185,11 @@ disable(self) -> None
Disable components by adding to the blocklist.
**Args:**
-- `keys`: Keys to disable (e.g., ``"tool\:my_tool@"`` for unversioned, ``"tool\:my_tool@1.0"`` for versioned).
+- `keys`: Keys to disable (e.g., ``"tool\:my_tool"``).
- `tags`: Tags to disable - components with these tags will be disabled.
-#### `get_tools`
+#### `get_tools`
```python
get_tools(self) -> list[Tool]
@@ -242,34 +197,27 @@ get_tools(self) -> list[Tool]
Get all enabled tools from providers.
-Queries all providers via the root provider (which applies provider transforms,
-server transforms, and visibility filtering). First provider wins for duplicate keys.
+Queries all providers in parallel and collects tools.
+First provider wins for duplicate keys. Filters by server blocklist.
**Args:**
- `run_middleware`: If True, apply the middleware chain before
returning results. Used by MCP handlers and mounted servers.
-#### `get_tool`
+#### `get_tool`
```python
-get_tool(self, name: str, version: VersionSpec | str | None = None) -> Tool
+get_tool(self, name: str) -> Tool
```
Get an enabled tool by name.
-Queries providers with full transform chain (provider transforms + server transforms + visibility).
-Returns only if enabled and authorized.
-
-**Args:**
-- `name`: The tool name.
-- `version`: Version filter. Can be\:
-- None\: returns highest version
-- str\: returns exact version match
-- VersionSpec\: returns best match within spec (highest matching)
+Queries all providers in parallel to find the tool.
+First provider wins. Returns only if enabled.
-#### `get_resources`
+#### `get_resources`
```python
get_resources(self) -> list[Resource]
@@ -277,34 +225,27 @@ get_resources(self) -> list[Resource]
Get all enabled resources from providers.
-Queries all providers via the root provider (which applies provider transforms,
-server transforms, and visibility filtering). First provider wins for duplicate keys.
+Queries all providers in parallel and collects resources.
+First provider wins for duplicate keys. Filters by server blocklist.
**Args:**
- `run_middleware`: If True, apply the middleware chain before
returning results. Used by MCP handlers and mounted servers.
-#### `get_resource`
+#### `get_resource`
```python
-get_resource(self, uri: str, version: VersionSpec | str | None = None) -> Resource
+get_resource(self, uri: str) -> Resource
```
Get an enabled resource by URI.
-Queries providers with full transform chain (provider transforms + server transforms + visibility).
-Returns only if enabled and authorized.
-
-**Args:**
-- `uri`: The resource URI.
-- `version`: Version filter. Can be\:
-- None\: returns highest version
-- str\: returns exact version match
-- VersionSpec\: returns best match within spec (highest matching)
+Queries all providers in parallel to find the resource.
+First provider wins. Returns only if enabled.
-#### `get_resource_templates`
+#### `get_resource_templates`
```python
get_resource_templates(self) -> list[ResourceTemplate]
@@ -312,34 +253,27 @@ get_resource_templates(self) -> list[ResourceTemplate]
Get all enabled resource templates from providers.
-Queries all providers via the root provider (which applies provider transforms,
-server transforms, and visibility filtering). First provider wins for duplicate keys.
+Queries all providers in parallel and collects templates.
+First provider wins for duplicate keys. Filters by server blocklist.
**Args:**
- `run_middleware`: If True, apply the middleware chain before
returning results. Used by MCP handlers and mounted servers.
-#### `get_resource_template`
+#### `get_resource_template`
```python
-get_resource_template(self, uri: str, version: VersionSpec | str | None = None) -> ResourceTemplate
+get_resource_template(self, uri: str) -> ResourceTemplate
```
Get an enabled resource template that matches the given URI.
-Queries providers with full transform chain (provider transforms + server transforms + visibility).
-Returns only if enabled and authorized.
-
-**Args:**
-- `uri`: The template URI to match.
-- `version`: Version filter. Can be\:
-- None\: returns highest version
-- str\: returns exact version match
-- VersionSpec\: returns best match within spec (highest matching)
+Queries all providers in parallel to find the template.
+First provider wins. Returns only if enabled.
-#### `get_prompts`
+#### `get_prompts`
```python
get_prompts(self) -> list[Prompt]
@@ -347,46 +281,60 @@ get_prompts(self) -> list[Prompt]
Get all enabled prompts from providers.
-Queries all providers via the root provider (which applies provider transforms,
-server transforms, and visibility filtering). First provider wins for duplicate keys.
+Queries all providers in parallel and collects prompts.
+First provider wins for duplicate keys. Filters by server blocklist.
**Args:**
- `run_middleware`: If True, apply the middleware chain before
returning results. Used by MCP handlers and mounted servers.
-#### `get_prompt`
+#### `get_prompt`
```python
-get_prompt(self, name: str, version: VersionSpec | str | None = None) -> Prompt
+get_prompt(self, name: str) -> Prompt
```
Get an enabled prompt by name.
-Queries providers with full transform chain (provider transforms + server transforms + visibility).
-Returns only if enabled and authorized.
+Queries all providers in parallel to find the prompt.
+First provider wins. Returns only if enabled.
+
+
+#### `get_component`
+
+```python
+get_component(self, key: str) -> Tool | Resource | ResourceTemplate | Prompt
+```
+
+Get a component by its prefixed key.
+
+Queries all providers in parallel to find the component.
+First provider wins.
**Args:**
-- `name`: The prompt name.
-- `version`: Version filter. Can be\:
-- None\: returns highest version
-- str\: returns exact version match
-- VersionSpec\: returns best match within spec (highest matching)
+- `key`: The prefixed key (e.g., "tool\:name", "resource\:uri", "template\:uri").
+
+**Returns:**
+- The component if found.
+
+**Raises:**
+- `NotFoundError`: If no component is found with the given key.
-#### `call_tool`
+#### `call_tool`
```python
call_tool(self, name: str, arguments: dict[str, Any] | None = None) -> ToolResult
```
-#### `call_tool`
+#### `call_tool`
```python
call_tool(self, name: str, arguments: dict[str, Any] | None = None) -> mcp.types.CreateTaskResult
```
-#### `call_tool`
+#### `call_tool`
```python
call_tool(self, name: str, arguments: dict[str, Any] | None = None) -> ToolResult | mcp.types.CreateTaskResult
@@ -415,19 +363,19 @@ return ToolResult.
- `ValidationError`: If arguments fail validation
-#### `read_resource`
+#### `read_resource`
```python
read_resource(self, uri: str) -> ResourceResult
```
-#### `read_resource`
+#### `read_resource`
```python
read_resource(self, uri: str) -> mcp.types.CreateTaskResult
```
-#### `read_resource`
+#### `read_resource`
```python
read_resource(self, uri: str) -> ResourceResult | mcp.types.CreateTaskResult
@@ -455,19 +403,19 @@ return ResourceResult.
- `ResourceError`: If resource read fails
-#### `render_prompt`
+#### `render_prompt`
```python
render_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> PromptResult
```
-#### `render_prompt`
+#### `render_prompt`
```python
render_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> mcp.types.CreateTaskResult
```
-#### `render_prompt`
+#### `render_prompt`
```python
render_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> PromptResult | mcp.types.CreateTaskResult
@@ -496,7 +444,7 @@ return PromptResult.
- `PromptError`: If prompt rendering fails
-#### `custom_route`
+#### `custom_route`
```python
custom_route(self, path: str, methods: list[str], name: str | None = None, include_in_schema: bool = True) -> Callable[[Callable[[Request], Awaitable[Response]]], Callable[[Request], Awaitable[Response]]]
@@ -517,10 +465,10 @@ Starlette's reverse URL lookup feature)
- `include_in_schema`: Whether to include in OpenAPI schema, defaults to True
-#### `add_tool`
+#### `add_tool`
```python
-add_tool(self, tool: Tool | Callable[..., Any]) -> Tool
+add_tool(self, tool: Tool) -> Tool
```
Add a tool to the server.
@@ -529,41 +477,58 @@ 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
+- `tool`: The Tool instance to register
**Returns:**
- The tool instance that was added to the server.
-#### `remove_tool`
+#### `remove_tool`
```python
-remove_tool(self, name: str, version: str | None = None) -> None
+remove_tool(self, name: str) -> None
```
-Remove tool(s) from the server.
+Remove a tool from the server.
**Args:**
-- `name`: The name of the tool to remove.
-- `version`: If None, removes ALL versions. If specified, removes only that version.
+- `name`: The name of the tool to remove
**Raises:**
-- `NotFoundError`: If no matching tool is found.
+- `NotFoundError`: If the tool is not found
+
+
+#### `add_tool_transformation`
+
+```python
+add_tool_transformation(self, tool_name: str, transformation: ToolTransformConfig) -> None
+```
+
+Add a tool transformation.
+
+
+#### `remove_tool_transformation`
+
+```python
+remove_tool_transformation(self, tool_name: str) -> None
+```
+
+Remove a tool transformation.
-#### `tool`
+#### `tool`
```python
tool(self, name_or_fn: AnyFunction) -> FunctionTool
```
-#### `tool`
+#### `tool`
```python
tool(self, name_or_fn: str | None = None) -> Callable[[AnyFunction], FunctionTool]
```
-#### `tool`
+#### `tool`
```python
tool(self, name_or_fn: str | AnyFunction | None = None) -> Callable[[AnyFunction], FunctionTool] | FunctionTool | partial[Callable[[AnyFunction], FunctionTool] | FunctionTool]
@@ -619,22 +584,22 @@ server.tool(my_function, name="custom_name")
```
-#### `add_resource`
+#### `add_resource`
```python
-add_resource(self, resource: Resource | Callable[..., Any]) -> Resource | ResourceTemplate
+add_resource(self, resource: Resource) -> Resource
```
Add a resource to the server.
**Args:**
-- `resource`: A Resource instance or @resource-decorated function to add
+- `resource`: A Resource instance to add
**Returns:**
- The resource instance that was added to the server.
-#### `add_template`
+#### `add_template`
```python
add_template(self, template: ResourceTemplate) -> ResourceTemplate
@@ -649,10 +614,10 @@ Add a resource template to the server.
- The template instance that was added to the server.
-#### `resource`
+#### `resource`
```python
-resource(self, uri: str) -> Callable[[AnyFunction], Resource | ResourceTemplate | AnyFunction]
+resource(self, uri: str) -> Callable[[AnyFunction], Resource | ResourceTemplate]
```
Decorator to register a function as a resource.
@@ -708,34 +673,34 @@ async def get_weather(city: str) -> str:
```
-#### `add_prompt`
+#### `add_prompt`
```python
-add_prompt(self, prompt: Prompt | Callable[..., Any]) -> Prompt
+add_prompt(self, prompt: Prompt) -> Prompt
```
Add a prompt to the server.
**Args:**
-- `prompt`: A Prompt instance or @prompt-decorated function to add
+- `prompt`: A Prompt instance to add
**Returns:**
- The prompt instance that was added to the server.
-#### `prompt`
+#### `prompt`
```python
prompt(self, name_or_fn: AnyFunction) -> FunctionPrompt
```
-#### `prompt`
+#### `prompt`
```python
prompt(self, name_or_fn: str | None = None) -> Callable[[AnyFunction], FunctionPrompt]
```
-#### `prompt`
+#### `prompt`
```python
prompt(self, name_or_fn: str | AnyFunction | None = None) -> Callable[[AnyFunction], FunctionPrompt] | FunctionPrompt | partial[Callable[[AnyFunction], FunctionPrompt] | FunctionPrompt]
@@ -812,7 +777,7 @@ Decorator to register a prompt.
```
-#### `run_stdio_async`
+#### `run_stdio_async`
```python
run_stdio_async(self, show_banner: bool = True, log_level: str | None = None, stateless: bool = False) -> None
@@ -826,7 +791,7 @@ Run the server using stdio transport.
- `stateless`: Whether to run in stateless mode (no session initialization)
-#### `run_http_async`
+#### `run_http_async`
```python
run_http_async(self, show_banner: bool = True, transport: Literal['http', 'streamable-http', 'sse'] = 'http', host: str | None = None, port: int | None = None, log_level: str | None = None, path: str | None = None, uvicorn_config: dict[str, Any] | None = None, middleware: list[ASGIMiddleware] | None = None, json_response: bool | None = None, stateless_http: bool | None = None, stateless: bool | None = None) -> None
@@ -847,7 +812,7 @@ Run the server using HTTP transport.
- `stateless`: Alias for stateless_http for CLI consistency
-#### `http_app`
+#### `http_app`
```python
http_app(self, path: str | None = None, middleware: list[ASGIMiddleware] | None = None, json_response: bool | None = None, stateless_http: bool | None = None, transport: Literal['http', 'streamable-http', 'sse'] = 'http', event_store: EventStore | None = None, retry_interval: int | None = None) -> StarletteWithLifespan
@@ -873,7 +838,7 @@ streamable-http transport.
- A Starlette application configured with the specified transport
-#### `mount`
+#### `mount`
```python
mount(self, server: FastMCP[LifespanResultT], namespace: str | None = None, as_proxy: bool | None = None, tool_names: dict[str, str] | None = None, prefix: str | None = None) -> None
@@ -920,7 +885,7 @@ mounted server.
- `prefix`: Deprecated. Use namespace instead.
-#### `import_server`
+#### `import_server`
```python
import_server(self, server: FastMCP[LifespanResultT], prefix: str | None = None) -> None
@@ -961,7 +926,7 @@ templates, and prompts are imported with their original names.
objects are imported with their original names.
-#### `from_openapi`
+#### `from_openapi`
```python
from_openapi(cls, openapi_spec: dict[str, Any], client: httpx.AsyncClient, 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, timeout: float | None = None, **settings: Any) -> Self
@@ -985,7 +950,7 @@ Create a FastMCP server from an OpenAPI specification.
- A FastMCP server with an OpenAPIProvider attached.
-#### `from_fastapi`
+#### `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, timeout: float | None = None, **settings: Any) -> Self
@@ -1009,7 +974,7 @@ Create a FastMCP server from a FastAPI application.
- A FastMCP server with an OpenAPIProvider attached.
-#### `as_proxy`
+#### `as_proxy`
```python
as_proxy(cls, backend: Client[ClientTransportT] | ClientTransport | FastMCP[Any] | FastMCP1Server | AnyUrl | Path | MCPConfig | dict[str, Any] | str, **settings: Any) -> FastMCPProxy
@@ -1027,7 +992,7 @@ instance or any value accepted as the `transport` argument of
`fastmcp.client.Client` constructor.
-#### `generate_name`
+#### `generate_name`
```python
generate_name(cls, name: str | None = None) -> str
diff --git a/docs/python-sdk/fastmcp-server-tasks-capabilities.mdx b/docs/python-sdk/fastmcp-server-tasks-capabilities.mdx
index 77c1467d37..6b8c78e3e1 100644
--- a/docs/python-sdk/fastmcp-server-tasks-capabilities.mdx
+++ b/docs/python-sdk/fastmcp-server-tasks-capabilities.mdx
@@ -10,20 +10,15 @@ SEP-1686 task capabilities declaration.
## Functions
-### `get_task_capabilities`
+### `get_task_capabilities`
```python
-get_task_capabilities() -> ServerTasksCapability | None
+get_task_capabilities() -> dict[str, Any]
```
-Return the SEP-1686 task capabilities.
+Return the SEP-1686 task capabilities structure.
-Returns task capabilities as a first-class ServerCapabilities field,
-declaring support for list, cancel, and request operations per SEP-1686.
-
-Returns None if pydocket is not installed (no task support).
-
-Note: prompts/resources are passed via extra_data since the SDK types
-don't include them yet (FastMCP supports them ahead of the spec).
+This is the standard capabilities map advertised to clients,
+declaring support for list, cancel, and request operations.
diff --git a/docs/python-sdk/fastmcp-server-tasks-config.mdx b/docs/python-sdk/fastmcp-server-tasks-config.mdx
index 2dbbc63dd0..129fe896c2 100644
--- a/docs/python-sdk/fastmcp-server-tasks-config.mdx
+++ b/docs/python-sdk/fastmcp-server-tasks-config.mdx
@@ -14,7 +14,7 @@ handle task-augmented execution as specified in SEP-1686.
## Classes
-### `TaskMeta`
+### `TaskMeta`
Metadata for task-augmented execution requests.
@@ -27,7 +27,7 @@ the operation should be submitted as a background task.
- `fn_key`: Docket routing key. Auto-derived from component name if None.
-### `TaskConfig`
+### `TaskConfig`
Configuration for MCP background task execution (SEP-1686).
@@ -44,7 +44,7 @@ Controls how a component handles task-augmented requests:
**Methods:**
-#### `from_bool`
+#### `from_bool`
```python
from_bool(cls, value: bool) -> TaskConfig
@@ -59,7 +59,7 @@ Convert boolean task flag to TaskConfig.
- TaskConfig with appropriate mode.
-#### `supports_tasks`
+#### `supports_tasks`
```python
supports_tasks(self) -> bool
@@ -71,7 +71,7 @@ Check if this component supports task execution.
- True if mode is "optional" or "required", False if "forbidden".
-#### `validate_function`
+#### `validate_function`
```python
validate_function(self, fn: Callable[..., Any], name: str) -> None
@@ -79,18 +79,13 @@ validate_function(self, fn: Callable[..., Any], name: str) -> None
Validate that function is compatible with this task config.
-Task execution requires:
-1. fastmcp[tasks] to be installed (pydocket)
-2. Async functions
-
-Raises ImportError if mode is "optional" or "required" but pydocket
-is not installed. Raises ValueError if function is synchronous.
+Task execution requires async functions. Raises ValueError if mode
+is "optional" or "required" but function is synchronous.
**Args:**
- `fn`: The function to validate (handles callable classes and staticmethods).
- `name`: Name for error messages.
**Raises:**
-- `ImportError`: If task execution is enabled but pydocket not installed.
- `ValueError`: If task execution is enabled but function is sync.
diff --git a/docs/python-sdk/fastmcp-server-tasks-requests.mdx b/docs/python-sdk/fastmcp-server-tasks-requests.mdx
index 50f77596ac..75fe1ca676 100644
--- a/docs/python-sdk/fastmcp-server-tasks-requests.mdx
+++ b/docs/python-sdk/fastmcp-server-tasks-requests.mdx
@@ -11,12 +11,10 @@ SEP-1686 task request handlers.
Handles MCP task protocol requests: tasks/get, tasks/result, tasks/list, tasks/cancel.
These handlers query and manage existing tasks (contrast with handlers.py which creates tasks).
-This module requires fastmcp[tasks] (pydocket). It is only imported when docket is available.
-
## Functions
-### `tasks_get_handler`
+### `tasks_get_handler`
```python
tasks_get_handler(server: FastMCP, params: dict[str, Any]) -> GetTaskResult
@@ -33,7 +31,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 +50,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 +69,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
diff --git a/docs/python-sdk/fastmcp-server-tasks-subscriptions.mdx b/docs/python-sdk/fastmcp-server-tasks-subscriptions.mdx
index 1b611ea9c7..1b4331212f 100644
--- a/docs/python-sdk/fastmcp-server-tasks-subscriptions.mdx
+++ b/docs/python-sdk/fastmcp-server-tasks-subscriptions.mdx
@@ -11,12 +11,10 @@ Task subscription helpers for sending MCP notifications (SEP-1686).
Subscribes to Docket execution state changes and sends notifications/tasks/status
to clients when their tasks change state.
-This module requires fastmcp[tasks] (pydocket). It is only imported when docket is available.
-
## Functions
-### `subscribe_to_task_updates`
+### `subscribe_to_task_updates`
```python
subscribe_to_task_updates(task_id: str, task_key: str, session: ServerSession, docket: Docket, poll_interval_ms: int = 5000) -> None
diff --git a/docs/python-sdk/fastmcp-tools-tool.mdx b/docs/python-sdk/fastmcp-tools-tool.mdx
index 9acb156951..c5e5e1c3a3 100644
--- a/docs/python-sdk/fastmcp-tools-tool.mdx
+++ b/docs/python-sdk/fastmcp-tools-tool.mdx
@@ -7,7 +7,7 @@ sidebarTitle: tool
## Functions
-### `default_serializer`
+### `default_serializer`
```python
default_serializer(data: Any) -> str
@@ -15,17 +15,17 @@ default_serializer(data: Any) -> str
## Classes
-### `ToolResult`
+### `ToolResult`
**Methods:**
-#### `to_mcp_result`
+#### `to_mcp_result`
```python
to_mcp_result(self) -> list[ContentBlock] | tuple[list[ContentBlock], dict[str, Any]] | CallToolResult
```
-### `Tool`
+### `Tool`
Internal tool registration info.
@@ -33,7 +33,7 @@ Internal tool registration info.
**Methods:**
-#### `to_mcp_tool`
+#### `to_mcp_tool`
```python
to_mcp_tool(self, **overrides: Any) -> MCPTool
@@ -42,16 +42,16 @@ to_mcp_tool(self, **overrides: Any) -> MCPTool
Convert the FastMCP tool to an MCP tool.
-#### `from_function`
+#### `from_function`
```python
-from_function(cls, fn: Callable[..., Any]) -> FunctionTool
+from_function(fn: Callable[..., Any], name: str | None = None, title: str | None = None, description: str | None = None, icons: list[Icon] | None = None, tags: set[str] | None = None, annotations: ToolAnnotations | None = None, exclude_args: list[str] | None = None, output_schema: dict[str, Any] | NotSetT | None = NotSet, serializer: ToolResultSerializerType | None = None, meta: dict[str, Any] | None = None, task: bool | TaskConfig | None = None) -> FunctionTool
```
Create a Tool from a function.
-#### `run`
+#### `run`
```python
run(self, arguments: dict[str, Any]) -> ToolResult
@@ -66,7 +66,7 @@ implemented by subclasses.
(list of ContentBlocks, dict of structured output).
-#### `convert_result`
+#### `convert_result`
```python
convert_result(self, raw_value: Any) -> ToolResult
@@ -78,7 +78,7 @@ Handles ToolResult passthrough and converts raw values using the tool's
attributes (serializer, output_schema) for proper conversion.
-#### `register_with_docket`
+#### `register_with_docket`
```python
register_with_docket(self, docket: Docket) -> None
@@ -87,7 +87,7 @@ register_with_docket(self, docket: Docket) -> None
Register this tool with docket for background execution.
-#### `add_to_docket`
+#### `add_to_docket`
```python
add_to_docket(self, docket: Docket, arguments: dict[str, Any], **kwargs: Any) -> Execution
@@ -103,14 +103,81 @@ Schedule this tool for background execution via docket.
- `**kwargs`: Additional kwargs passed to docket.add()
-#### `from_tool`
+#### `from_tool`
```python
from_tool(cls, tool: Tool) -> TransformedTool
```
-#### `get_span_attributes`
+### `FunctionTool`
+
+**Methods:**
+
+#### `to_mcp_tool`
+
+```python
+to_mcp_tool(self, **overrides: Any) -> MCPTool
+```
+
+Convert the FastMCP tool to an MCP tool.
+
+Extends the base implementation to add task execution mode if enabled.
+
+
+#### `from_function`
+
+```python
+from_function(cls, fn: Callable[..., Any], name: str | None = None, title: str | None = None, description: str | None = None, icons: list[Icon] | None = None, tags: set[str] | None = None, annotations: ToolAnnotations | None = None, exclude_args: list[str] | None = None, output_schema: dict[str, Any] | NotSetT | None = NotSet, serializer: ToolResultSerializerType | None = None, meta: dict[str, Any] | None = None, task: bool | TaskConfig | None = None) -> FunctionTool
+```
+
+Create a Tool from a function.
+
+
+#### `run`
+
+```python
+run(self, arguments: dict[str, Any]) -> ToolResult
+```
+
+Run the tool with arguments.
+
+
+#### `register_with_docket`
+
+```python
+register_with_docket(self, docket: Docket) -> None
+```
+
+Register this tool with docket for background execution.
+
+FunctionTool registers the underlying function, which has the user's
+Depends parameters for docket to resolve.
+
+
+#### `add_to_docket`
+
+```python
+add_to_docket(self, docket: Docket, arguments: dict[str, Any], **kwargs: Any) -> Execution
+```
+
+Schedule this tool for background execution via docket.
+
+FunctionTool splats the arguments dict since .fn expects **kwargs.
+
+**Args:**
+- `docket`: The Docket instance
+- `arguments`: Tool arguments
+- `fn_key`: Function lookup key in Docket registry (defaults to self.key)
+- `task_key`: Redis storage key for the result
+- `**kwargs`: Additional kwargs passed to docket.add()
+
+
+### `ParsedFunction`
+
+**Methods:**
+
+#### `from_function`
```python
-get_span_attributes(self) -> dict[str, Any]
+from_function(cls, fn: Callable[..., Any], exclude_args: list[str] | None = None, validate: bool = True, wrap_non_object_output_schema: bool = True) -> ParsedFunction
```
diff --git a/docs/python-sdk/fastmcp-tools-tool_transform.mdx b/docs/python-sdk/fastmcp-tools-tool_transform.mdx
index 052ab71921..0288596ac2 100644
--- a/docs/python-sdk/fastmcp-tools-tool_transform.mdx
+++ b/docs/python-sdk/fastmcp-tools-tool_transform.mdx
@@ -7,7 +7,7 @@ sidebarTitle: tool_transform
## Functions
-### `forward`
+### `forward`
```python
forward(**kwargs: Any) -> ToolResult
@@ -36,7 +36,7 @@ tool has args `a` and `b`, and an `transform_args` was provided that maps `x` to
- `TypeError`: If provided arguments don't match the transformed schema.
-### `forward_raw`
+### `forward_raw`
```python
forward_raw(**kwargs: Any) -> ToolResult
@@ -62,7 +62,7 @@ y=2)` will call the parent tool with `x=1` and `y=2`.
- `RuntimeError`: If called outside a transformed tool context.
-### `apply_transformations_to_tools`
+### `apply_transformations_to_tools`
```python
apply_transformations_to_tools(tools: dict[str, Tool], transformations: dict[str, ToolTransformConfig]) -> dict[str, Tool]
@@ -78,7 +78,7 @@ but transformations are keyed by tool name (e.g., "my_tool").
## Classes
-### `ArgTransform`
+### `ArgTransform`
Configuration for transforming a parent tool's argument.
@@ -150,7 +150,7 @@ ArgTransform(name="new_name", description="New desc", default=None, type=int)
```
-### `ArgTransformConfig`
+### `ArgTransformConfig`
A model for requesting a single argument transform.
@@ -158,7 +158,7 @@ A model for requesting a single argument transform.
**Methods:**
-#### `to_arg_transform`
+#### `to_arg_transform`
```python
to_arg_transform(self) -> ArgTransform
@@ -167,7 +167,7 @@ to_arg_transform(self) -> ArgTransform
Convert the argument transform to a FastMCP argument transform.
-### `TransformedTool`
+### `TransformedTool`
A tool that is transformed from another tool.
@@ -191,7 +191,7 @@ validation when forward() is called from custom functions.
**Methods:**
-#### `run`
+#### `run`
```python
run(self, arguments: dict[str, Any]) -> ToolResult
@@ -210,10 +210,10 @@ functions.
- ToolResult object containing content and optional structured output.
-#### `from_tool`
+#### `from_tool`
```python
-from_tool(cls, tool: Tool, name: str | None = None, version: str | NotSetT | None = NotSet, title: str | NotSetT | None = NotSet, description: str | NotSetT | None = NotSet, tags: set[str] | None = None, transform_fn: Callable[..., Any] | None = None, transform_args: dict[str, ArgTransform] | None = None, annotations: ToolAnnotations | NotSetT | None = NotSet, output_schema: dict[str, Any] | NotSetT | None = NotSet, serializer: Callable[[Any], str] | NotSetT | None = NotSet, meta: dict[str, Any] | NotSetT | None = NotSet) -> TransformedTool
+from_tool(cls, tool: Tool, name: str | None = None, title: str | NotSetT | None = NotSet, description: str | NotSetT | None = NotSet, tags: set[str] | None = None, transform_fn: Callable[..., Any] | None = None, transform_args: dict[str, ArgTransform] | None = None, annotations: ToolAnnotations | NotSetT | None = NotSet, output_schema: dict[str, Any] | NotSetT | None = NotSet, serializer: Callable[[Any], str] | NotSetT | None = NotSet, meta: dict[str, Any] | NotSetT | None = NotSet) -> TransformedTool
```
Create a transformed tool from a parent tool.
@@ -224,7 +224,6 @@ Create a transformed tool from a parent tool.
to call the parent tool. Functions with **kwargs receive transformed
argument names.
- `name`: New name for the tool. Defaults to parent tool's name.
-- `version`: New version for the tool. Defaults to parent tool's version.
- `title`: New title for the tool. Defaults to parent tool's title.
- `transform_args`: Optional transformations for parent tool arguments.
Only specified arguments are transformed, others pass through unchanged\:
@@ -293,7 +292,7 @@ async def custom_output(**kwargs) -> ToolResult:
```
-### `ToolTransformConfig`
+### `ToolTransformConfig`
Provides a way to transform a tool.
@@ -301,7 +300,7 @@ Provides a way to transform a tool.
**Methods:**
-#### `apply`
+#### `apply`
```python
apply(self, tool: Tool) -> TransformedTool
diff --git a/docs/python-sdk/fastmcp-utilities-async_utils.mdx b/docs/python-sdk/fastmcp-utilities-async_utils.mdx
index f5f24019f1..7a44351b66 100644
--- a/docs/python-sdk/fastmcp-utilities-async_utils.mdx
+++ b/docs/python-sdk/fastmcp-utilities-async_utils.mdx
@@ -10,20 +10,7 @@ Async utilities for FastMCP.
## Functions
-### `call_sync_fn_in_threadpool`
-
-```python
-call_sync_fn_in_threadpool(fn: Callable[..., Any], *args: Any, **kwargs: Any) -> Any
-```
-
-
-Call a sync function in a threadpool to avoid blocking the event loop.
-
-Uses anyio.to_thread.run_sync which properly propagates contextvars,
-making this safe for functions that depend on context (like dependency injection).
-
-
-### `gather`
+### `gather`
```python
gather(*awaitables: Awaitable[T]) -> list[T] | list[T | BaseException]
diff --git a/docs/python-sdk/fastmcp-utilities-cli.mdx b/docs/python-sdk/fastmcp-utilities-cli.mdx
index 455655637e..2eb7922209 100644
--- a/docs/python-sdk/fastmcp-utilities-cli.mdx
+++ b/docs/python-sdk/fastmcp-utilities-cli.mdx
@@ -7,7 +7,7 @@ sidebarTitle: cli
## Functions
-### `is_already_in_uv_subprocess`
+### `is_already_in_uv_subprocess`
```python
is_already_in_uv_subprocess() -> bool
@@ -17,7 +17,7 @@ is_already_in_uv_subprocess() -> bool
Check if we're already running in a FastMCP uv subprocess.
-### `load_and_merge_config`
+### `load_and_merge_config`
```python
load_and_merge_config(server_spec: str | None, **cli_overrides) -> tuple[MCPServerConfig, str]
@@ -37,7 +37,7 @@ run, inspect, and dev commands.
- Tuple of (MCPServerConfig, resolved_server_spec)
-### `log_server_banner`
+### `log_server_banner`
```python
log_server_banner(server: FastMCP[Any]) -> None
diff --git a/docs/python-sdk/fastmcp-utilities-components.mdx b/docs/python-sdk/fastmcp-utilities-components.mdx
index c1d9481b85..08879acdf0 100644
--- a/docs/python-sdk/fastmcp-utilities-components.mdx
+++ b/docs/python-sdk/fastmcp-utilities-components.mdx
@@ -5,26 +5,11 @@ sidebarTitle: components
# `fastmcp.utilities.components`
-## Functions
-
-### `get_fastmcp_metadata`
-
-```python
-get_fastmcp_metadata(meta: dict[str, Any] | None) -> FastMCPMeta
-```
-
-
-Extract FastMCP metadata from a component's meta dict.
-
-Handles both the current `fastmcp` namespace and the legacy `_fastmcp`
-namespace for compatibility with older FastMCP servers.
-
-
## Classes
-### `FastMCPMeta`
+### `FastMCPMeta`
-### `FastMCPComponent`
+### `FastMCPComponent`
Base class for FastMCP tools, prompts, resources, and resource templates.
@@ -32,7 +17,7 @@ Base class for FastMCP tools, prompts, resources, and resource templates.
**Methods:**
-#### `make_key`
+#### `make_key`
```python
make_key(cls, identifier: str) -> str
@@ -47,7 +32,7 @@ Construct the lookup key for this component type.
- A prefixed key like "tool:name" or "resource:uri"
-#### `key`
+#### `key`
```python
key(self) -> str
@@ -55,30 +40,25 @@ key(self) -> str
The globally unique lookup key for this component.
-Format: "{key_prefix}:{identifier}@{version}" or "{key_prefix}:{identifier}@"
-e.g. "tool:my_tool@v2", "tool:my_tool@", "resource:file://x.txt@"
-
-The @ suffix is ALWAYS present to enable unambiguous parsing of keys
-(URIs may contain @ characters, so we always include the delimiter).
+Format: "{key_prefix}:{identifier}" e.g. "tool:my_tool", "resource:file://x.txt"
Subclasses should override this to use their specific identifier.
Base implementation uses name.
-#### `get_meta`
+#### `get_meta`
```python
-get_meta(self) -> dict[str, Any]
+get_meta(self, include_fastmcp_meta: bool | None = None) -> dict[str, Any] | None
```
Get the meta information about the component.
-Returns a dict that always includes a `fastmcp` key containing:
-- `tags`: sorted list of component tags
-- `version`: component version (only if set)
+If include_fastmcp_meta is True, a `_fastmcp` key will be added to the
+meta, containing a `tags` field with the tags of the component.
-#### `enable`
+#### `enable`
```python
enable(self) -> None
@@ -87,7 +67,7 @@ enable(self) -> None
Removed in 3.0. Use server.enable(keys=[...]) instead.
-#### `disable`
+#### `disable`
```python
disable(self) -> None
@@ -96,7 +76,7 @@ disable(self) -> None
Removed in 3.0. Use server.disable(keys=[...]) instead.
-#### `copy`
+#### `copy`
```python
copy(self) -> Self
@@ -105,7 +85,7 @@ copy(self) -> Self
Create a copy of the component.
-#### `register_with_docket`
+#### `register_with_docket`
```python
register_with_docket(self, docket: Docket) -> None
@@ -117,7 +97,7 @@ No-ops if task_config.mode is "forbidden". Subclasses override to
register their callable (self.run, self.read, self.render, or self.fn).
-#### `add_to_docket`
+#### `add_to_docket`
```python
add_to_docket(self, docket: Docket, *args: Any, **kwargs: Any) -> Execution
@@ -133,14 +113,3 @@ Subclasses override this to handle their specific calling conventions:
The **kwargs are passed through to docket.add() (e.g., key=task_key).
-
-#### `get_span_attributes`
-
-```python
-get_span_attributes(self) -> dict[str, Any]
-```
-
-Return span attributes for telemetry.
-
-Subclasses should call super() and merge their specific attributes.
-
diff --git a/docs/python-sdk/fastmcp-utilities-json_schema_type.mdx b/docs/python-sdk/fastmcp-utilities-json_schema_type.mdx
index 59b66f2ec1..50fba76542 100644
--- a/docs/python-sdk/fastmcp-utilities-json_schema_type.mdx
+++ b/docs/python-sdk/fastmcp-utilities-json_schema_type.mdx
@@ -42,7 +42,7 @@ Example:
## Functions
-### `json_schema_to_type`
+### `json_schema_to_type`
```python
json_schema_to_type(schema: Mapping[str, Any], name: str | None = None) -> type
@@ -107,4 +107,4 @@ class Name:
## Classes
-### `JSONSchema`
+### `JSONSchema`
diff --git a/docs/python-sdk/fastmcp-utilities-logging.mdx b/docs/python-sdk/fastmcp-utilities-logging.mdx
index 1fffe465c3..ef3264dbb3 100644
--- a/docs/python-sdk/fastmcp-utilities-logging.mdx
+++ b/docs/python-sdk/fastmcp-utilities-logging.mdx
@@ -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-visibility.mdx b/docs/python-sdk/fastmcp-utilities-visibility.mdx
new file mode 100644
index 0000000000..ade14110e9
--- /dev/null
+++ b/docs/python-sdk/fastmcp-utilities-visibility.mdx
@@ -0,0 +1,86 @@
+---
+title: visibility
+sidebarTitle: visibility
+---
+
+# `fastmcp.utilities.visibility`
+
+
+Visibility filtering for FastMCP components.
+
+This module provides the VisibilityFilter class which handles blocklist and
+allowlist logic for controlling component visibility at both the provider
+and server levels.
+
+
+## Classes
+
+### `VisibilityFilter`
+
+
+Manages component visibility with blocklist and allowlist support.
+
+Both servers and providers use this class to control which components
+are visible. Visibility is hierarchical: if a component is hidden at
+any level (provider or server), it's hidden to the client.
+
+Filtering logic (blocklist wins over allowlist):
+1. If component key is in _disabled_keys → HIDDEN
+2. If any component tag is in _disabled_tags → HIDDEN
+3. If _default_enabled is False and component not in allowlist → HIDDEN
+4. Otherwise → VISIBLE
+
+The `only=True` flag on enable() switches to allowlist mode:
+- Sets _default_enabled = False
+- Clears existing allowlists
+- Adds specified keys/tags to allowlist
+
+
+**Methods:**
+
+#### `disable`
+
+```python
+disable(self) -> None
+```
+
+Add to blocklist (hide components).
+
+**Args:**
+- `keys`: Component keys to hide (e.g., "tool\:my_tool", "resource\:file\://x")
+- `tags`: Tags to hide - any component with these tags will be hidden
+
+
+#### `enable`
+
+```python
+enable(self) -> None
+```
+
+Remove from blocklist, or set allowlist with only=True.
+
+**Args:**
+- `keys`: Component keys to show
+- `tags`: Tags to show
+- `only`: If True, switches to allowlist mode - ONLY show these keys/tags.
+This sets default visibility to False, clears existing allowlists,
+and adds the specified keys/tags to the allowlist.
+
+
+#### `reset`
+
+```python
+reset(self) -> None
+```
+
+Reset to default state (everything enabled, no filters).
+
+
+#### `is_enabled`
+
+```python
+is_enabled(self, component: FastMCPComponent) -> bool
+```
+
+Check if component is enabled. Blocklist wins over allowlist.
+
From acb124eb08e0885a49c980d6f84de7d7f96646ff Mon Sep 17 00:00:00 2001
From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
Date: Fri, 16 Jan 2026 21:24:23 -0500
Subject: [PATCH 4/5] Remove regenerated python-sdk docs (not part of this PR)
---
docs/python-sdk/fastmcp-client-telemetry.mdx | 23 --
docs/python-sdk/fastmcp-decorators.mdx | 39 ----
.../fastmcp-prompts-function_prompt.mdx | 106 ----------
.../fastmcp-resources-function_resource.mdx | 93 ---------
.../fastmcp-server-auth-authorization.mdx | 139 -------------
...astmcp-server-middleware-authorization.mdx | 116 -----------
.../fastmcp-server-middleware-ping.mdx | 32 ---
.../fastmcp-server-providers-aggregate.mdx | 139 -------------
.../fastmcp-server-providers-filesystem.mdx | 128 ------------
...-server-providers-filesystem_discovery.mdx | 104 ----------
docs/python-sdk/fastmcp-server-telemetry.mdx | 56 -----
.../fastmcp-server-transforms-__init__.mdx | 196 ------------------
.../fastmcp-server-transforms-namespace.mdx | 96 ---------
...stmcp-server-transforms-tool_transform.mdx | 40 ----
...stmcp-server-transforms-version_filter.mdx | 85 --------
.../fastmcp-server-transforms-visibility.mdx | 158 --------------
docs/python-sdk/fastmcp-telemetry.mdx | 95 ---------
.../fastmcp-tools-function_parsing.mdx | 21 --
.../fastmcp-tools-function_tool.mdx | 108 ----------
.../fastmcp-utilities-version_check.mdx | 40 ----
.../python-sdk/fastmcp-utilities-versions.mdx | 190 -----------------
21 files changed, 2004 deletions(-)
delete mode 100644 docs/python-sdk/fastmcp-client-telemetry.mdx
delete mode 100644 docs/python-sdk/fastmcp-decorators.mdx
delete mode 100644 docs/python-sdk/fastmcp-prompts-function_prompt.mdx
delete mode 100644 docs/python-sdk/fastmcp-resources-function_resource.mdx
delete mode 100644 docs/python-sdk/fastmcp-server-auth-authorization.mdx
delete mode 100644 docs/python-sdk/fastmcp-server-middleware-authorization.mdx
delete mode 100644 docs/python-sdk/fastmcp-server-middleware-ping.mdx
delete mode 100644 docs/python-sdk/fastmcp-server-providers-aggregate.mdx
delete mode 100644 docs/python-sdk/fastmcp-server-providers-filesystem.mdx
delete mode 100644 docs/python-sdk/fastmcp-server-providers-filesystem_discovery.mdx
delete mode 100644 docs/python-sdk/fastmcp-server-telemetry.mdx
delete mode 100644 docs/python-sdk/fastmcp-server-transforms-__init__.mdx
delete mode 100644 docs/python-sdk/fastmcp-server-transforms-namespace.mdx
delete mode 100644 docs/python-sdk/fastmcp-server-transforms-tool_transform.mdx
delete mode 100644 docs/python-sdk/fastmcp-server-transforms-version_filter.mdx
delete mode 100644 docs/python-sdk/fastmcp-server-transforms-visibility.mdx
delete mode 100644 docs/python-sdk/fastmcp-telemetry.mdx
delete mode 100644 docs/python-sdk/fastmcp-tools-function_parsing.mdx
delete mode 100644 docs/python-sdk/fastmcp-tools-function_tool.mdx
delete mode 100644 docs/python-sdk/fastmcp-utilities-version_check.mdx
delete mode 100644 docs/python-sdk/fastmcp-utilities-versions.mdx
diff --git a/docs/python-sdk/fastmcp-client-telemetry.mdx b/docs/python-sdk/fastmcp-client-telemetry.mdx
deleted file mode 100644
index 42ec72e933..0000000000
--- a/docs/python-sdk/fastmcp-client-telemetry.mdx
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: telemetry
-sidebarTitle: telemetry
----
-
-# `fastmcp.client.telemetry`
-
-
-Client-side telemetry helpers.
-
-## Functions
-
-### `client_span`
-
-```python
-client_span(name: str, method: str, component_key: str, session_id: str | None = None, resource_uri: str | None = None) -> Generator[Span, None, None]
-```
-
-
-Create a CLIENT span with standard MCP attributes.
-
-Automatically records any exception on the span and sets error status.
-
diff --git a/docs/python-sdk/fastmcp-decorators.mdx b/docs/python-sdk/fastmcp-decorators.mdx
deleted file mode 100644
index b57712ad68..0000000000
--- a/docs/python-sdk/fastmcp-decorators.mdx
+++ /dev/null
@@ -1,39 +0,0 @@
----
-title: decorators
-sidebarTitle: decorators
----
-
-# `fastmcp.decorators`
-
-
-Shared decorator utilities for FastMCP.
-
-## Functions
-
-### `resolve_task_config`
-
-```python
-resolve_task_config(task: bool | TaskConfig | None) -> bool | TaskConfig
-```
-
-
-Resolve task config, defaulting None to False.
-
-
-### `get_fastmcp_meta`
-
-```python
-get_fastmcp_meta(fn: Any) -> Any | None
-```
-
-
-Extract FastMCP metadata from a function, handling bound methods and wrappers.
-
-
-## Classes
-
-### `HasFastMCPMeta`
-
-
-Protocol for callables decorated with FastMCP metadata.
-
diff --git a/docs/python-sdk/fastmcp-prompts-function_prompt.mdx b/docs/python-sdk/fastmcp-prompts-function_prompt.mdx
deleted file mode 100644
index c8e48ef9cd..0000000000
--- a/docs/python-sdk/fastmcp-prompts-function_prompt.mdx
+++ /dev/null
@@ -1,106 +0,0 @@
----
-title: function_prompt
-sidebarTitle: function_prompt
----
-
-# `fastmcp.prompts.function_prompt`
-
-
-Standalone @prompt decorator for FastMCP.
-
-## Functions
-
-### `prompt`
-
-```python
-prompt(name_or_fn: str | Callable[..., Any] | None = None) -> Any
-```
-
-
-Standalone decorator to mark a function as an MCP prompt.
-
-Returns the original function with metadata attached. Register with a server
-using mcp.add_prompt().
-
-
-## Classes
-
-### `DecoratedPrompt`
-
-
-Protocol for functions decorated with @prompt.
-
-
-### `PromptMeta`
-
-
-Metadata attached to functions by the @prompt decorator.
-
-
-### `FunctionPrompt`
-
-
-A prompt that is a function.
-
-
-**Methods:**
-
-#### `from_function`
-
-```python
-from_function(cls, fn: Callable[..., Any]) -> FunctionPrompt
-```
-
-Create a Prompt from a function.
-
-**Args:**
-- `fn`: The function to wrap
-- `metadata`: PromptMeta object with all configuration. If provided,
-individual parameters must not be passed.
-- `name, title, etc.`: Individual parameters for backwards compatibility.
-Cannot be used together with metadata parameter.
-
-The function can return:
-- str: wrapped as single user Message
-- list\[Message | str]: converted to list\[Message]
-- PromptResult: used directly
-
-
-#### `render`
-
-```python
-render(self, arguments: dict[str, Any] | None = None) -> PromptResult
-```
-
-Render the prompt with arguments.
-
-
-#### `register_with_docket`
-
-```python
-register_with_docket(self, docket: Docket) -> None
-```
-
-Register this prompt with docket for background execution.
-
-FunctionPrompt registers the underlying function, which has the user's
-Depends parameters for docket to resolve.
-
-
-#### `add_to_docket`
-
-```python
-add_to_docket(self, docket: Docket, arguments: dict[str, Any] | None, **kwargs: Any) -> Execution
-```
-
-Schedule this prompt for background execution via docket.
-
-FunctionPrompt splats the arguments dict since .fn expects **kwargs.
-
-**Args:**
-- `docket`: The Docket instance
-- `arguments`: Prompt arguments
-- `fn_key`: Function lookup key in Docket registry (defaults to self.key)
-- `task_key`: Redis storage key for the result
-- `**kwargs`: Additional kwargs passed to docket.add()
-
diff --git a/docs/python-sdk/fastmcp-resources-function_resource.mdx b/docs/python-sdk/fastmcp-resources-function_resource.mdx
deleted file mode 100644
index ad184b53c8..0000000000
--- a/docs/python-sdk/fastmcp-resources-function_resource.mdx
+++ /dev/null
@@ -1,93 +0,0 @@
----
-title: function_resource
-sidebarTitle: function_resource
----
-
-# `fastmcp.resources.function_resource`
-
-
-Standalone @resource decorator for FastMCP.
-
-## Functions
-
-### `resource`
-
-```python
-resource(uri: str) -> Callable[[F], F]
-```
-
-
-Standalone decorator to mark a function as an MCP resource.
-
-Returns the original function with metadata attached. Register with a server
-using mcp.add_resource().
-
-
-## Classes
-
-### `DecoratedResource`
-
-
-Protocol for functions decorated with @resource.
-
-
-### `ResourceMeta`
-
-
-Metadata attached to functions by the @resource decorator.
-
-
-### `FunctionResource`
-
-
-A resource that defers data loading by wrapping a function.
-
-The function is only called when the resource is read, allowing for lazy loading
-of potentially expensive data. This is particularly useful when listing resources,
-as the function won't be called until the resource is actually accessed.
-
-The function can return:
-- str for text content (default)
-- bytes for binary content
-- other types will be converted to JSON
-
-
-**Methods:**
-
-#### `from_function`
-
-```python
-from_function(cls, fn: Callable[..., Any], uri: str | AnyUrl | None = None) -> FunctionResource
-```
-
-Create a FunctionResource from a function.
-
-**Args:**
-- `fn`: The function to wrap
-- `uri`: The URI for the resource (required if metadata not provided)
-- `metadata`: ResourceMeta object with all configuration. If provided,
-individual parameters must not be passed.
-- `name, title, etc.`: Individual parameters for backwards compatibility.
-Cannot be used together with metadata parameter.
-
-
-#### `read`
-
-```python
-read(self) -> str | bytes | ResourceResult
-```
-
-Read the resource by calling the wrapped function.
-
-
-#### `register_with_docket`
-
-```python
-register_with_docket(self, docket: Docket) -> None
-```
-
-Register this resource with docket for background execution.
-
-FunctionResource registers the underlying function, which has the user's
-Depends parameters for docket to resolve.
-
diff --git a/docs/python-sdk/fastmcp-server-auth-authorization.mdx b/docs/python-sdk/fastmcp-server-auth-authorization.mdx
deleted file mode 100644
index d8e0611a95..0000000000
--- a/docs/python-sdk/fastmcp-server-auth-authorization.mdx
+++ /dev/null
@@ -1,139 +0,0 @@
----
-title: authorization
-sidebarTitle: authorization
----
-
-# `fastmcp.server.auth.authorization`
-
-
-Authorization checks for FastMCP components.
-
-This module provides callable-based authorization for tools, resources, and prompts.
-Auth checks are functions that receive an AuthContext and return True to allow access
-or False to deny.
-
-Auth checks can also raise exceptions:
-- AuthorizationError: Propagates with the custom message for explicit denial
-- Other exceptions: Masked for security (logged, treated as auth failure)
-
-Example:
- ```python
- from fastmcp import FastMCP
- from fastmcp.server.auth import require_auth, require_scopes
-
- mcp = FastMCP()
-
- @mcp.tool(auth=require_auth)
- def protected_tool(): ...
-
- @mcp.resource("data://secret", auth=require_scopes("read"))
- def secret_data(): ...
-
- @mcp.prompt(auth=require_auth)
- def admin_prompt(): ...
- ```
-
-
-## Functions
-
-### `require_auth`
-
-```python
-require_auth(ctx: AuthContext) -> bool
-```
-
-
-Require any valid authentication.
-
-Returns True if the request has a valid token, False otherwise.
-
-
-### `require_scopes`
-
-```python
-require_scopes(*scopes: str) -> AuthCheck
-```
-
-
-Require specific OAuth scopes.
-
-Returns an auth check that requires ALL specified scopes to be present
-in the token (AND logic).
-
-**Args:**
-- `*scopes`: One or more scope strings that must all be present.
-
-
-### `restrict_tag`
-
-```python
-restrict_tag(tag: str) -> AuthCheck
-```
-
-
-Restrict components with a specific tag to require certain scopes.
-
-If the component has the specified tag, the token must have ALL the
-required scopes. If the component doesn't have the tag, access is allowed.
-
-**Args:**
-- `tag`: The tag that triggers the scope requirement.
-- `scopes`: List of scopes required when the tag is present.
-
-
-### `run_auth_checks`
-
-```python
-run_auth_checks(checks: AuthCheck | list[AuthCheck], ctx: AuthContext) -> bool
-```
-
-
-Run auth checks with AND logic.
-
-All checks must pass for authorization to succeed.
-
-Auth checks can:
-- Return True to allow access
-- Return False to deny access
-- Raise AuthorizationError to deny with a custom message (propagates)
-- Raise other exceptions (masked for security, treated as denial)
-
-**Args:**
-- `checks`: A single check function or list of check functions.
-- `ctx`: The auth context to pass to each check.
-
-**Returns:**
-- True if all checks pass, False if any check fails.
-
-**Raises:**
-- `AuthorizationError`: If an auth check explicitly raises it.
-
-
-## Classes
-
-### `AuthContext`
-
-
-Context passed to auth check callables.
-
-This object is passed to each auth check function and provides
-access to the current authentication token and the component being accessed.
-
-**Attributes:**
-- `token`: The current access token, or None if unauthenticated.
-- `component`: The component (tool, resource, or prompt) being accessed.
-- `tool`: Backwards-compatible alias for component when it's a Tool.
-
-
-**Methods:**
-
-#### `tool`
-
-```python
-tool(self) -> Tool | None
-```
-
-Backwards-compatible access to the component as a Tool.
-
-Returns the component if it's a Tool, None otherwise.
-
diff --git a/docs/python-sdk/fastmcp-server-middleware-authorization.mdx b/docs/python-sdk/fastmcp-server-middleware-authorization.mdx
deleted file mode 100644
index f5a41afdcd..0000000000
--- a/docs/python-sdk/fastmcp-server-middleware-authorization.mdx
+++ /dev/null
@@ -1,116 +0,0 @@
----
-title: authorization
-sidebarTitle: authorization
----
-
-# `fastmcp.server.middleware.authorization`
-
-
-Authorization middleware for FastMCP.
-
-This module provides middleware-based authorization using callable auth checks.
-AuthMiddleware applies auth checks globally to all components on the server.
-
-Example:
- ```python
- from fastmcp import FastMCP
- from fastmcp.server.auth import require_auth, require_scopes, restrict_tag
- from fastmcp.server.middleware import AuthMiddleware
-
- # Require auth for all components
- mcp = FastMCP(middleware=[
- AuthMiddleware(auth=require_auth)
- ])
-
- # Tag-based: components tagged "admin" require "admin" scope
- mcp = FastMCP(middleware=[
- AuthMiddleware(auth=restrict_tag("admin", scopes=["admin"]))
- ])
- ```
-
-
-## Classes
-
-### `AuthMiddleware`
-
-
-Global authorization middleware using callable checks.
-
-This middleware applies auth checks to all components (tools, resources,
-prompts) on the server. It uses the same callable API as component-level
-auth checks.
-
-The middleware:
-- Filters tools/resources/prompts from list responses based on auth checks
-- Checks auth before tool execution, resource read, and prompt render
-- Skips all auth checks for STDIO transport (no OAuth concept)
-
-**Args:**
-- `auth`: A single auth check function or list of check functions.
-All checks must pass for authorization to succeed (AND logic).
-
-
-**Methods:**
-
-#### `on_list_tools`
-
-```python
-on_list_tools(self, context: MiddlewareContext[mt.ListToolsRequest], call_next: CallNext[mt.ListToolsRequest, Sequence[Tool]]) -> Sequence[Tool]
-```
-
-Filter tools/list response based on auth checks.
-
-
-#### `on_call_tool`
-
-```python
-on_call_tool(self, context: MiddlewareContext[mt.CallToolRequestParams], call_next: CallNext[mt.CallToolRequestParams, ToolResult]) -> ToolResult
-```
-
-Check auth before tool execution.
-
-
-#### `on_list_resources`
-
-```python
-on_list_resources(self, context: MiddlewareContext[mt.ListResourcesRequest], call_next: CallNext[mt.ListResourcesRequest, Sequence[Resource]]) -> Sequence[Resource]
-```
-
-Filter resources/list response based on auth checks.
-
-
-#### `on_read_resource`
-
-```python
-on_read_resource(self, context: MiddlewareContext[mt.ReadResourceRequestParams], call_next: CallNext[mt.ReadResourceRequestParams, ResourceResult]) -> ResourceResult
-```
-
-Check auth before resource read.
-
-
-#### `on_list_resource_templates`
-
-```python
-on_list_resource_templates(self, context: MiddlewareContext[mt.ListResourceTemplatesRequest], call_next: CallNext[mt.ListResourceTemplatesRequest, Sequence[ResourceTemplate]]) -> Sequence[ResourceTemplate]
-```
-
-Filter resource templates/list response based on auth checks.
-
-
-#### `on_list_prompts`
-
-```python
-on_list_prompts(self, context: MiddlewareContext[mt.ListPromptsRequest], call_next: CallNext[mt.ListPromptsRequest, Sequence[Prompt]]) -> Sequence[Prompt]
-```
-
-Filter prompts/list response based on auth checks.
-
-
-#### `on_get_prompt`
-
-```python
-on_get_prompt(self, context: MiddlewareContext[mt.GetPromptRequestParams], call_next: CallNext[mt.GetPromptRequestParams, PromptResult]) -> PromptResult
-```
-
-Check auth before prompt render.
-
diff --git a/docs/python-sdk/fastmcp-server-middleware-ping.mdx b/docs/python-sdk/fastmcp-server-middleware-ping.mdx
deleted file mode 100644
index fe81c216dd..0000000000
--- a/docs/python-sdk/fastmcp-server-middleware-ping.mdx
+++ /dev/null
@@ -1,32 +0,0 @@
----
-title: ping
-sidebarTitle: ping
----
-
-# `fastmcp.server.middleware.ping`
-
-
-Ping middleware for keeping client connections alive.
-
-## Classes
-
-### `PingMiddleware`
-
-
-Middleware that sends periodic pings to keep client connections alive.
-
-Starts a background ping task on first message from each session. The task
-sends server-to-client pings at the configured interval until the session
-ends.
-
-
-**Methods:**
-
-#### `on_message`
-
-```python
-on_message(self, context: MiddlewareContext, call_next: CallNext) -> Any
-```
-
-Start ping task on first message from a session.
-
diff --git a/docs/python-sdk/fastmcp-server-providers-aggregate.mdx b/docs/python-sdk/fastmcp-server-providers-aggregate.mdx
deleted file mode 100644
index 61b90c87ff..0000000000
--- a/docs/python-sdk/fastmcp-server-providers-aggregate.mdx
+++ /dev/null
@@ -1,139 +0,0 @@
----
-title: aggregate
-sidebarTitle: aggregate
----
-
-# `fastmcp.server.providers.aggregate`
-
-
-AggregateProvider for combining multiple providers into one.
-
-This module provides `AggregateProvider` which presents multiple providers
-as a single unified provider. Used internally by FastMCP for aggregating
-components from all providers.
-
-
-## Classes
-
-### `AggregateProvider`
-
-
-Presents multiple providers as a single provider.
-
-Components are aggregated from all providers. For get_* operations,
-providers are queried in parallel and the highest version is returned.
-
-Errors from individual providers are logged and skipped (graceful degradation).
-
-
-**Methods:**
-
-#### `list_tools`
-
-```python
-list_tools(self) -> Sequence[Tool]
-```
-
-List all tools from all providers (with transforms applied).
-
-
-#### `get_tool`
-
-```python
-get_tool(self, name: str, version: VersionSpec | None = None) -> Tool | None
-```
-
-Get tool by name.
-
-**Args:**
-- `name`: The tool name.
-- `version`: If None, returns highest version across all providers.
-If specified, returns highest version matching the spec from any provider.
-
-
-#### `list_resources`
-
-```python
-list_resources(self) -> Sequence[Resource]
-```
-
-List all resources from all providers (with transforms applied).
-
-
-#### `get_resource`
-
-```python
-get_resource(self, uri: str, version: VersionSpec | None = None) -> Resource | None
-```
-
-Get resource by URI.
-
-**Args:**
-- `uri`: The resource URI.
-- `version`: If None, returns highest version across all providers.
-If specified, returns highest version matching the spec from any provider.
-
-
-#### `list_resource_templates`
-
-```python
-list_resource_templates(self) -> Sequence[ResourceTemplate]
-```
-
-List all resource templates from all providers (with transforms applied).
-
-
-#### `get_resource_template`
-
-```python
-get_resource_template(self, uri: str, version: VersionSpec | None = None) -> ResourceTemplate | None
-```
-
-Get resource template by URI.
-
-**Args:**
-- `uri`: The template URI to match.
-- `version`: If None, returns highest version across all providers.
-If specified, returns highest version matching the spec from any provider.
-
-
-#### `list_prompts`
-
-```python
-list_prompts(self) -> Sequence[Prompt]
-```
-
-List all prompts from all providers (with transforms applied).
-
-
-#### `get_prompt`
-
-```python
-get_prompt(self, name: str, version: VersionSpec | None = None) -> Prompt | None
-```
-
-Get prompt by name.
-
-**Args:**
-- `name`: The prompt name.
-- `version`: If None, returns highest version across all providers.
-If specified, returns highest version matching the spec from any provider.
-
-
-#### `get_tasks`
-
-```python
-get_tasks(self) -> Sequence[FastMCPComponent]
-```
-
-Get all task-eligible components from all providers.
-
-
-#### `lifespan`
-
-```python
-lifespan(self) -> AsyncIterator[None]
-```
-
-Combine lifespans of all providers.
-
diff --git a/docs/python-sdk/fastmcp-server-providers-filesystem.mdx b/docs/python-sdk/fastmcp-server-providers-filesystem.mdx
deleted file mode 100644
index 55e9b342cd..0000000000
--- a/docs/python-sdk/fastmcp-server-providers-filesystem.mdx
+++ /dev/null
@@ -1,128 +0,0 @@
----
-title: filesystem
-sidebarTitle: filesystem
----
-
-# `fastmcp.server.providers.filesystem`
-
-
-FileSystemProvider for filesystem-based component discovery.
-
-FileSystemProvider scans a directory for Python files, imports them, and
-registers any Tool, Resource, ResourceTemplate, or Prompt objects found.
-
-Components are created using the standalone decorators from fastmcp.tools,
-fastmcp.resources, and fastmcp.prompts:
-
-Example:
- ```python
- # In mcp/tools.py
- from fastmcp.tools import tool
-
- @tool
- def greet(name: str) -> str:
- return f"Hello, {name}!"
-
- # In main.py
- from pathlib import Path
-
- from fastmcp import FastMCP
- from fastmcp.server.providers import FileSystemProvider
-
- mcp = FastMCP("MyServer", providers=[FileSystemProvider(Path(__file__).parent / "mcp")])
- ```
-
-
-## Classes
-
-### `FileSystemProvider`
-
-
-Provider that discovers components from the filesystem.
-
-Scans a directory for Python files and registers any Tool, Resource,
-ResourceTemplate, or Prompt objects found. Components are created using
-the standalone decorators:
-- @tool from fastmcp.tools
-- @resource from fastmcp.resources
-- @prompt from fastmcp.prompts
-
-**Args:**
-- `root`: Root directory to scan. Defaults to current directory.
-- `reload`: If True, re-scan files on every request (dev mode).
-Defaults to False (scan once at init, cache results).
-
-
-**Methods:**
-
-#### `list_tools`
-
-```python
-list_tools(self) -> Sequence[Tool]
-```
-
-Return all tools, reloading if in reload mode.
-
-
-#### `get_tool`
-
-```python
-get_tool(self, name: str, version: VersionSpec | None = None) -> Tool | None
-```
-
-Get a tool by name, reloading if in reload mode.
-
-
-#### `list_resources`
-
-```python
-list_resources(self) -> Sequence[Resource]
-```
-
-Return all resources, reloading if in reload mode.
-
-
-#### `get_resource`
-
-```python
-get_resource(self, uri: str, version: VersionSpec | None = None) -> Resource | None
-```
-
-Get a resource by URI, reloading if in reload mode.
-
-
-#### `list_resource_templates`
-
-```python
-list_resource_templates(self) -> Sequence[ResourceTemplate]
-```
-
-Return all resource templates, reloading if in reload mode.
-
-
-#### `get_resource_template`
-
-```python
-get_resource_template(self, uri: str, version: VersionSpec | None = None) -> ResourceTemplate | None
-```
-
-Get a resource template, reloading if in reload mode.
-
-
-#### `list_prompts`
-
-```python
-list_prompts(self) -> Sequence[Prompt]
-```
-
-Return all prompts, reloading if in reload mode.
-
-
-#### `get_prompt`
-
-```python
-get_prompt(self, name: str, version: VersionSpec | None = None) -> Prompt | None
-```
-
-Get a prompt by name, reloading if in reload mode.
-
diff --git a/docs/python-sdk/fastmcp-server-providers-filesystem_discovery.mdx b/docs/python-sdk/fastmcp-server-providers-filesystem_discovery.mdx
deleted file mode 100644
index 0a02129c97..0000000000
--- a/docs/python-sdk/fastmcp-server-providers-filesystem_discovery.mdx
+++ /dev/null
@@ -1,104 +0,0 @@
----
-title: filesystem_discovery
-sidebarTitle: filesystem_discovery
----
-
-# `fastmcp.server.providers.filesystem_discovery`
-
-
-File discovery and module import utilities for filesystem-based routing.
-
-This module provides functions to:
-1. Discover Python files in a directory tree
-2. Import modules (as packages if __init__.py exists, else directly)
-3. Extract decorated components (Tool, Resource, Prompt objects) from imported modules
-
-
-## Functions
-
-### `discover_files`
-
-```python
-discover_files(root: Path) -> list[Path]
-```
-
-
-Recursively discover all Python files under a directory.
-
-Excludes __init__.py files (they're for package structure, not components).
-
-**Args:**
-- `root`: Root directory to scan.
-
-**Returns:**
-- List of .py file paths, sorted for deterministic order.
-
-
-### `import_module_from_file`
-
-```python
-import_module_from_file(file_path: Path) -> ModuleType
-```
-
-
-Import a Python file as a module.
-
-If the file is part of a package (directory has __init__.py), imports
-it as a proper package member (relative imports work). Otherwise,
-imports directly using spec_from_file_location.
-
-**Args:**
-- `file_path`: Path to the Python file.
-
-**Returns:**
-- The imported module.
-
-**Raises:**
-- `ImportError`: If the module cannot be imported.
-
-
-### `extract_components`
-
-```python
-extract_components(module: ModuleType) -> list[FastMCPComponent]
-```
-
-
-Extract all MCP components from a module.
-
-Scans all module attributes for instances of Tool, Resource,
-ResourceTemplate, or Prompt objects created by standalone decorators,
-or functions decorated with @tool/@resource/@prompt that have __fastmcp__ metadata.
-
-**Args:**
-- `module`: The imported module to scan.
-
-**Returns:**
-- List of component objects (Tool, Resource, ResourceTemplate, Prompt).
-
-
-### `discover_and_import`
-
-```python
-discover_and_import(root: Path) -> DiscoveryResult
-```
-
-
-Discover files, import modules, and extract components.
-
-This is the main entry point for filesystem-based discovery.
-
-**Args:**
-- `root`: Root directory to scan.
-
-**Returns:**
-- DiscoveryResult with components and any failed files.
-
-
-## Classes
-
-### `DiscoveryResult`
-
-
-Result of filesystem discovery.
-
diff --git a/docs/python-sdk/fastmcp-server-telemetry.mdx b/docs/python-sdk/fastmcp-server-telemetry.mdx
deleted file mode 100644
index a842c468d0..0000000000
--- a/docs/python-sdk/fastmcp-server-telemetry.mdx
+++ /dev/null
@@ -1,56 +0,0 @@
----
-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.
-
-
-### `server_span`
-
-```python
-server_span(name: str, method: str, server_name: str, component_type: str, component_key: str, resource_uri: str | None = None) -> Generator[Span, None, None]
-```
-
-
-Create a SERVER span with standard MCP attributes and auth context.
-
-Automatically records any exception on the span and sets error status.
-
-
-### `delegate_span`
-
-```python
-delegate_span(name: str, provider_type: str, component_key: str) -> 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-__init__.mdx b/docs/python-sdk/fastmcp-server-transforms-__init__.mdx
deleted file mode 100644
index 6b7e5db176..0000000000
--- a/docs/python-sdk/fastmcp-server-transforms-__init__.mdx
+++ /dev/null
@@ -1,196 +0,0 @@
----
-title: __init__
-sidebarTitle: __init__
----
-
-# `fastmcp.server.transforms`
-
-
-Transform system for component transformations.
-
-Transforms modify components (tools, resources, prompts) using a middleware pattern.
-Each transform wraps the next in the chain via `call_next`, allowing transforms to
-intercept, modify, or replace component queries.
-
-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.
-
-Transforms use a middleware pattern with `call_next` to chain operations.
-Each transform can intercept, modify, or pass through component queries.
-
-For list operations, call `call_next()` to get components from downstream,
-then transform the result. For get operations, optionally transform the
-name/uri before calling `call_next`, then transform the result.
-
-
-**Methods:**
-
-#### `list_tools`
-
-```python
-list_tools(self, call_next: ListToolsNext) -> Sequence[Tool]
-```
-
-List tools with transformation applied.
-
-**Args:**
-- `call_next`: Callable to get tools from downstream transforms/provider.
-
-**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, call_next: ListResourcesNext) -> Sequence[Resource]
-```
-
-List resources with transformation applied.
-
-**Args:**
-- `call_next`: Callable to get resources from downstream transforms/provider.
-
-**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, call_next: ListResourceTemplatesNext) -> Sequence[ResourceTemplate]
-```
-
-List resource templates with transformation applied.
-
-**Args:**
-- `call_next`: Callable to get templates from downstream transforms/provider.
-
-**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, call_next: ListPromptsNext) -> Sequence[Prompt]
-```
-
-List prompts with transformation applied.
-
-**Args:**
-- `call_next`: Callable to get prompts from downstream transforms/provider.
-
-**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-server-transforms-namespace.mdx b/docs/python-sdk/fastmcp-server-transforms-namespace.mdx
deleted file mode 100644
index 0260e3a2e0..0000000000
--- a/docs/python-sdk/fastmcp-server-transforms-namespace.mdx
+++ /dev/null
@@ -1,96 +0,0 @@
----
-title: namespace
-sidebarTitle: namespace
----
-
-# `fastmcp.server.transforms.namespace`
-
-
-Namespace transform for prefixing component names.
-
-## Classes
-
-### `Namespace`
-
-
-Prefixes component names with a namespace.
-
-- Tools: name → namespace_name
-- Prompts: name → namespace_name
-- Resources: protocol://path → protocol://namespace/path
-- Resource Templates: same as resources
-
-
-**Methods:**
-
-#### `list_tools`
-
-```python
-list_tools(self, call_next: ListToolsNext) -> Sequence[Tool]
-```
-
-Prefix tool names with namespace.
-
-
-#### `get_tool`
-
-```python
-get_tool(self, name: str, call_next: GetToolNext) -> Tool | None
-```
-
-Get tool by namespaced name.
-
-
-#### `list_resources`
-
-```python
-list_resources(self, call_next: ListResourcesNext) -> Sequence[Resource]
-```
-
-Add namespace path segment to resource URIs.
-
-
-#### `get_resource`
-
-```python
-get_resource(self, uri: str, call_next: GetResourceNext) -> Resource | None
-```
-
-Get resource by namespaced URI.
-
-
-#### `list_resource_templates`
-
-```python
-list_resource_templates(self, call_next: ListResourceTemplatesNext) -> Sequence[ResourceTemplate]
-```
-
-Add namespace path segment to template URIs.
-
-
-#### `get_resource_template`
-
-```python
-get_resource_template(self, uri: str, call_next: GetResourceTemplateNext) -> ResourceTemplate | None
-```
-
-Get resource template by namespaced URI.
-
-
-#### `list_prompts`
-
-```python
-list_prompts(self, call_next: ListPromptsNext) -> Sequence[Prompt]
-```
-
-Prefix prompt names with namespace.
-
-
-#### `get_prompt`
-
-```python
-get_prompt(self, name: str, call_next: GetPromptNext) -> Prompt | None
-```
-
-Get prompt by namespaced name.
-
diff --git a/docs/python-sdk/fastmcp-server-transforms-tool_transform.mdx b/docs/python-sdk/fastmcp-server-transforms-tool_transform.mdx
deleted file mode 100644
index 417e18f778..0000000000
--- a/docs/python-sdk/fastmcp-server-transforms-tool_transform.mdx
+++ /dev/null
@@ -1,40 +0,0 @@
----
-title: tool_transform
-sidebarTitle: tool_transform
----
-
-# `fastmcp.server.transforms.tool_transform`
-
-
-Transform for applying tool transformations.
-
-## Classes
-
-### `ToolTransform`
-
-
-Applies tool transformations to modify tool schemas.
-
-Wraps ToolTransformConfig to apply argument renames, schema changes,
-hidden arguments, and other transformations at the transform level.
-
-
-**Methods:**
-
-#### `list_tools`
-
-```python
-list_tools(self, call_next: ListToolsNext) -> Sequence[Tool]
-```
-
-Apply transforms to matching tools.
-
-
-#### `get_tool`
-
-```python
-get_tool(self, name: str, call_next: GetToolNext) -> Tool | None
-```
-
-Get tool by transformed name.
-
diff --git a/docs/python-sdk/fastmcp-server-transforms-version_filter.mdx b/docs/python-sdk/fastmcp-server-transforms-version_filter.mdx
deleted file mode 100644
index 7a2e434312..0000000000
--- a/docs/python-sdk/fastmcp-server-transforms-version_filter.mdx
+++ /dev/null
@@ -1,85 +0,0 @@
----
-title: version_filter
-sidebarTitle: version_filter
----
-
-# `fastmcp.server.transforms.version_filter`
-
-
-Version filter transform for filtering components by version range.
-
-## Classes
-
-### `VersionFilter`
-
-
-Filters components by version range.
-
-When applied to a provider or server, only components within the version
-range are visible. Within that filtered set, the highest version of each
-component is exposed to clients (standard deduplication behavior).
-
-Parameters mirror comparison operators for clarity:
-
- # Versions < 3.0 (v1 and v2)
- server.add_transform(VersionFilter(version_lt="3.0"))
-
- # Versions >= 2.0 and < 3.0 (only v2.x)
- server.add_transform(VersionFilter(version_gte="2.0", version_lt="3.0"))
-
-Works with any version string - PEP 440 (1.0, 2.0) or dates (2025-01-01).
-
-**Args:**
-- `version_gte`: Versions >= this value pass through.
-- `version_lt`: Versions < this value pass through.
-
-
-**Methods:**
-
-#### `list_tools`
-
-```python
-list_tools(self, call_next: ListToolsNext) -> Sequence[Tool]
-```
-
-#### `get_tool`
-
-```python
-get_tool(self, name: str, call_next: GetToolNext) -> Tool | None
-```
-
-#### `list_resources`
-
-```python
-list_resources(self, call_next: ListResourcesNext) -> Sequence[Resource]
-```
-
-#### `get_resource`
-
-```python
-get_resource(self, uri: str, call_next: GetResourceNext) -> Resource | None
-```
-
-#### `list_resource_templates`
-
-```python
-list_resource_templates(self, call_next: ListResourceTemplatesNext) -> Sequence[ResourceTemplate]
-```
-
-#### `get_resource_template`
-
-```python
-get_resource_template(self, uri: str, call_next: GetResourceTemplateNext) -> ResourceTemplate | None
-```
-
-#### `list_prompts`
-
-```python
-list_prompts(self, call_next: ListPromptsNext) -> Sequence[Prompt]
-```
-
-#### `get_prompt`
-
-```python
-get_prompt(self, name: str, call_next: GetPromptNext) -> Prompt | None
-```
diff --git a/docs/python-sdk/fastmcp-server-transforms-visibility.mdx b/docs/python-sdk/fastmcp-server-transforms-visibility.mdx
deleted file mode 100644
index 25ef0478d1..0000000000
--- a/docs/python-sdk/fastmcp-server-transforms-visibility.mdx
+++ /dev/null
@@ -1,158 +0,0 @@
----
-title: visibility
-sidebarTitle: visibility
----
-
-# `fastmcp.server.transforms.visibility`
-
-
-Visibility transform for filtering components based on enable/disable settings.
-
-This module provides the `Visibility` class which manages component visibility
-with blocklist and allowlist support. Components can be hidden by key or tag,
-and the visibility state is mutable - changes take effect on subsequent queries.
-
-
-## Classes
-
-### `Visibility`
-
-
-Filters components based on visibility settings.
-
-Manages blocklist and allowlist logic for controlling component visibility.
-Both servers and providers use this class. Visibility is hierarchical: if a
-component is hidden at any level (provider or server), it's hidden to the client.
-
-Filtering logic (blocklist wins over allowlist):
-1. If component key is in _disabled_keys → HIDDEN
-2. If any component tag is in _disabled_tags → HIDDEN
-3. If _default_enabled is False and component not in allowlist → HIDDEN
-4. Otherwise → VISIBLE
-
-The `only=True` flag on enable() switches to allowlist mode:
-- Sets _default_enabled = False
-- Clears existing allowlists
-- Adds specified keys/tags to allowlist
-
-
-**Methods:**
-
-#### `disable`
-
-```python
-disable(self) -> None
-```
-
-Add to blocklist (hide components).
-
-**Args:**
-- `keys`: Component keys to hide (e.g., "tool\:my_tool@", "resource\:file\://x@")
-- `tags`: Tags to hide - any component with these tags will be hidden
-
-
-#### `enable`
-
-```python
-enable(self) -> None
-```
-
-Remove from blocklist, or set allowlist with only=True.
-
-**Args:**
-- `keys`: Component keys to show
-- `tags`: Tags to show
-- `only`: If True, switches to allowlist mode - ONLY show these keys/tags.
-This sets default visibility to False, clears existing allowlists,
-and adds the specified keys/tags to the allowlist.
-
-
-#### `reset`
-
-```python
-reset(self) -> None
-```
-
-Reset to default state (everything enabled, no filters).
-
-
-#### `is_enabled`
-
-```python
-is_enabled(self, component: FastMCPComponent) -> bool
-```
-
-Check if component is enabled. Blocklist wins over allowlist.
-
-
-#### `list_tools`
-
-```python
-list_tools(self, call_next: ListToolsNext) -> Sequence[Tool]
-```
-
-Filter tools by visibility.
-
-
-#### `get_tool`
-
-```python
-get_tool(self, name: str, call_next: GetToolNext) -> Tool | None
-```
-
-Get tool if enabled, None otherwise.
-
-
-#### `list_resources`
-
-```python
-list_resources(self, call_next: ListResourcesNext) -> Sequence[Resource]
-```
-
-Filter resources by visibility.
-
-
-#### `get_resource`
-
-```python
-get_resource(self, uri: str, call_next: GetResourceNext) -> Resource | None
-```
-
-Get resource if enabled, None otherwise.
-
-
-#### `list_resource_templates`
-
-```python
-list_resource_templates(self, call_next: ListResourceTemplatesNext) -> Sequence[ResourceTemplate]
-```
-
-Filter resource templates by visibility.
-
-
-#### `get_resource_template`
-
-```python
-get_resource_template(self, uri: str, call_next: GetResourceTemplateNext) -> ResourceTemplate | None
-```
-
-Get resource template if enabled, None otherwise.
-
-
-#### `list_prompts`
-
-```python
-list_prompts(self, call_next: ListPromptsNext) -> Sequence[Prompt]
-```
-
-Filter prompts by visibility.
-
-
-#### `get_prompt`
-
-```python
-get_prompt(self, name: str, call_next: GetPromptNext) -> Prompt | None
-```
-
-Get prompt if enabled, None otherwise.
-
diff --git a/docs/python-sdk/fastmcp-telemetry.mdx b/docs/python-sdk/fastmcp-telemetry.mdx
deleted file mode 100644
index 805e9940d9..0000000000
--- a/docs/python-sdk/fastmcp-telemetry.mdx
+++ /dev/null
@@ -1,95 +0,0 @@
----
-title: telemetry
-sidebarTitle: telemetry
----
-
-# `fastmcp.telemetry`
-
-
-OpenTelemetry instrumentation for FastMCP.
-
-This module provides native OpenTelemetry integration for FastMCP servers and clients.
-It uses only the opentelemetry-api package, so telemetry is a no-op unless the user
-installs an OpenTelemetry SDK and configures exporters.
-
-Example usage with SDK:
- ```python
- from opentelemetry import trace
- from opentelemetry.sdk.trace import TracerProvider
- from opentelemetry.sdk.trace.export import ConsoleSpanExporter, SimpleSpanProcessor
-
- # Configure the SDK (user responsibility)
- provider = TracerProvider()
- provider.add_span_processor(SimpleSpanProcessor(ConsoleSpanExporter()))
- trace.set_tracer_provider(provider)
-
- # Now FastMCP will emit traces
- from fastmcp import FastMCP
- mcp = FastMCP("my-server")
- ```
-
-
-## Functions
-
-### `get_tracer`
-
-```python
-get_tracer(version: str | None = None) -> Tracer
-```
-
-
-Get the FastMCP tracer for creating spans.
-
-**Args:**
-- `version`: Optional version string for the instrumentation
-
-**Returns:**
-- A tracer instance. Returns a no-op tracer if no SDK is configured.
-
-
-### `inject_trace_context`
-
-```python
-inject_trace_context(meta: dict[str, Any] | None = None) -> dict[str, Any] | None
-```
-
-
-Inject current trace context into a meta dict for MCP request propagation.
-
-**Args:**
-- `meta`: Optional existing meta dict to merge with trace context
-
-**Returns:**
-- A new dict containing the original meta (if any) plus trace context keys,
-- or None if no trace context to inject and meta was None
-
-
-### `record_span_error`
-
-```python
-record_span_error(span: Span, exception: BaseException) -> None
-```
-
-
-Record an exception on a span and set error status.
-
-
-### `extract_trace_context`
-
-```python
-extract_trace_context(meta: dict[str, Any] | None) -> Context
-```
-
-
-Extract trace context from an MCP request meta dict.
-
-If already in a valid trace (e.g., from HTTP propagation), the existing
-trace context is preserved and meta is not used.
-
-**Args:**
-- `meta`: The meta dict from an MCP request (ctx.request_context.meta)
-
-**Returns:**
-- An OpenTelemetry Context with the extracted trace context,
-- or the current context if no trace context found or already in a trace
-
diff --git a/docs/python-sdk/fastmcp-tools-function_parsing.mdx b/docs/python-sdk/fastmcp-tools-function_parsing.mdx
deleted file mode 100644
index 2f69d15482..0000000000
--- a/docs/python-sdk/fastmcp-tools-function_parsing.mdx
+++ /dev/null
@@ -1,21 +0,0 @@
----
-title: function_parsing
-sidebarTitle: function_parsing
----
-
-# `fastmcp.tools.function_parsing`
-
-
-Function introspection and schema generation for FastMCP tools.
-
-## Classes
-
-### `ParsedFunction`
-
-**Methods:**
-
-#### `from_function`
-
-```python
-from_function(cls, fn: Callable[..., Any], exclude_args: list[str] | None = None, validate: bool = True, wrap_non_object_output_schema: bool = True) -> ParsedFunction
-```
diff --git a/docs/python-sdk/fastmcp-tools-function_tool.mdx b/docs/python-sdk/fastmcp-tools-function_tool.mdx
deleted file mode 100644
index b9bd0e7da2..0000000000
--- a/docs/python-sdk/fastmcp-tools-function_tool.mdx
+++ /dev/null
@@ -1,108 +0,0 @@
----
-title: function_tool
-sidebarTitle: function_tool
----
-
-# `fastmcp.tools.function_tool`
-
-
-Standalone @tool decorator for FastMCP.
-
-## Functions
-
-### `tool`
-
-```python
-tool(name_or_fn: str | Callable[..., Any] | None = None) -> Any
-```
-
-
-Standalone decorator to mark a function as an MCP tool.
-
-Returns the original function with metadata attached. Register with a server
-using mcp.add_tool().
-
-
-## Classes
-
-### `DecoratedTool`
-
-
-Protocol for functions decorated with @tool.
-
-
-### `ToolMeta`
-
-
-Metadata attached to functions by the @tool decorator.
-
-
-### `FunctionTool`
-
-**Methods:**
-
-#### `to_mcp_tool`
-
-```python
-to_mcp_tool(self, **overrides: Any) -> mcp.types.Tool
-```
-
-Convert the FastMCP tool to an MCP tool.
-
-Extends the base implementation to add task execution mode if enabled.
-
-
-#### `from_function`
-
-```python
-from_function(cls, fn: Callable[..., Any]) -> FunctionTool
-```
-
-Create a FunctionTool from a function.
-
-**Args:**
-- `fn`: The function to wrap
-- `metadata`: ToolMeta object with all configuration. If provided,
-individual parameters must not be passed.
-- `name, title, etc.`: Individual parameters for backwards compatibility.
-Cannot be used together with metadata parameter.
-
-
-#### `run`
-
-```python
-run(self, arguments: dict[str, Any]) -> ToolResult
-```
-
-Run the tool with arguments.
-
-
-#### `register_with_docket`
-
-```python
-register_with_docket(self, docket: Docket) -> None
-```
-
-Register this tool with docket for background execution.
-
-FunctionTool registers the underlying function, which has the user's
-Depends parameters for docket to resolve.
-
-
-#### `add_to_docket`
-
-```python
-add_to_docket(self, docket: Docket, arguments: dict[str, Any], **kwargs: Any) -> Execution
-```
-
-Schedule this tool for background execution via docket.
-
-FunctionTool splats the arguments dict since .fn expects **kwargs.
-
-**Args:**
-- `docket`: The Docket instance
-- `arguments`: Tool arguments
-- `fn_key`: Function lookup key in Docket registry (defaults to self.key)
-- `task_key`: Redis storage key for the result
-- `**kwargs`: Additional kwargs passed to docket.add()
-
diff --git a/docs/python-sdk/fastmcp-utilities-version_check.mdx b/docs/python-sdk/fastmcp-utilities-version_check.mdx
deleted file mode 100644
index a88805fb2d..0000000000
--- a/docs/python-sdk/fastmcp-utilities-version_check.mdx
+++ /dev/null
@@ -1,40 +0,0 @@
----
-title: version_check
-sidebarTitle: version_check
----
-
-# `fastmcp.utilities.version_check`
-
-
-Version checking utilities for FastMCP.
-
-## Functions
-
-### `get_latest_version`
-
-```python
-get_latest_version(include_prereleases: bool = False) -> str | None
-```
-
-
-Get the latest version of FastMCP from PyPI, using cache when available.
-
-**Args:**
-- `include_prereleases`: If True, include pre-release versions.
-
-**Returns:**
-- The latest version string, or None if unavailable.
-
-
-### `check_for_newer_version`
-
-```python
-check_for_newer_version() -> str | None
-```
-
-
-Check if a newer version of FastMCP is available.
-
-**Returns:**
-- The latest version string if newer than current, None otherwise.
-
diff --git a/docs/python-sdk/fastmcp-utilities-versions.mdx b/docs/python-sdk/fastmcp-utilities-versions.mdx
deleted file mode 100644
index 9adb00b50a..0000000000
--- a/docs/python-sdk/fastmcp-utilities-versions.mdx
+++ /dev/null
@@ -1,190 +0,0 @@
----
-title: versions
-sidebarTitle: versions
----
-
-# `fastmcp.utilities.versions`
-
-
-Version comparison utilities for component versioning.
-
-This module provides utilities for comparing component versions. Versions are
-strings that are first attempted to be parsed as PEP 440 versions (using the
-`packaging` library), falling back to lexicographic string comparison.
-
-Examples:
- - "1", "2", "10" → parsed as PEP 440, compared semantically (1 < 2 < 10)
- - "1.0", "2.0" → parsed as PEP 440
- - "v1.0" → 'v' prefix stripped, parsed as "1.0"
- - "2025-01-15" → not valid PEP 440, compared as strings
- - None → sorts lowest (unversioned components)
-
-
-## Functions
-
-### `parse_version_key`
-
-```python
-parse_version_key(version: str | None) -> VersionKey
-```
-
-
-Parse a version string into a sortable key.
-
-**Args:**
-- `version`: The version string, or None for unversioned.
-
-**Returns:**
-- A VersionKey suitable for sorting.
-
-
-### `version_sort_key`
-
-```python
-version_sort_key(component: FastMCPComponent) -> VersionKey
-```
-
-
-Get a sort key for a component based on its version.
-
-Use with sorted() or max() to order components by version.
-
-**Args:**
-- `component`: The component to get a sort key for.
-
-**Returns:**
-- A sortable VersionKey.
-
-
-### `compare_versions`
-
-```python
-compare_versions(a: str | None, b: str | None) -> int
-```
-
-
-Compare two version strings.
-
-**Args:**
-- `a`: First version string (or None).
-- `b`: Second version string (or None).
-
-**Returns:**
-- -1 if a < b, 0 if a == b, 1 if a > b.
-
-
-### `is_version_greater`
-
-```python
-is_version_greater(a: str | None, b: str | None) -> bool
-```
-
-
-Check if version a is greater than version b.
-
-**Args:**
-- `a`: First version string (or None).
-- `b`: Second version string (or None).
-
-**Returns:**
-- True if a > b, False otherwise.
-
-
-### `max_version`
-
-```python
-max_version(a: str | None, b: str | None) -> str | None
-```
-
-
-Return the greater of two versions.
-
-**Args:**
-- `a`: First version string (or None).
-- `b`: Second version string (or None).
-
-**Returns:**
-- The greater version, or None if both are None.
-
-
-### `min_version`
-
-```python
-min_version(a: str | None, b: str | None) -> str | None
-```
-
-
-Return the lesser of two versions.
-
-**Args:**
-- `a`: First version string (or None).
-- `b`: Second version string (or None).
-
-**Returns:**
-- The lesser version, or None if both are None.
-
-
-## Classes
-
-### `VersionSpec`
-
-
-Specification for filtering components by version.
-
-Used by transforms and providers to filter components to a specific
-version or version range. Unversioned components (version=None) always
-match any spec.
-
-**Args:**
-- `gte`: If set, only versions >= this value match.
-- `lt`: If set, only versions < this value match.
-- `eq`: If set, only this exact version matches (gte/lt ignored).
-
-
-**Methods:**
-
-#### `matches`
-
-```python
-matches(self, version: str | None) -> bool
-```
-
-Check if a version matches this spec.
-
-**Args:**
-- `version`: The version to check, or None for unversioned.
-
-**Returns:**
-- True if the version matches the spec.
-
-
-#### `intersect`
-
-```python
-intersect(self, other: VersionSpec | None) -> VersionSpec
-```
-
-Return a spec that satisfies both this spec and other.
-
-Used by transforms to combine caller constraints with filter constraints.
-For example, if a VersionFilter has lt="3.0" and caller requests eq="1.0",
-the intersection validates "1.0" is in range and returns the exact spec.
-
-**Args:**
-- `other`: Another spec to intersect with, or None.
-
-**Returns:**
-- A VersionSpec that matches only versions satisfying both specs.
-
-
-### `VersionKey`
-
-
-A comparable version key that handles None, PEP 440 versions, and strings.
-
-Comparison order:
-1. None (unversioned) sorts lowest
-2. PEP 440 versions sort by semantic version order
-3. Invalid versions (strings) sort lexicographically
-4. When comparing PEP 440 vs string, PEP 440 comes first
-
From a9c6026c4df60957d069236b7654ad4e833feeae Mon Sep 17 00:00:00 2001
From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
Date: Fri, 16 Jan 2026 21:25:45 -0500
Subject: [PATCH 5/5] Add type guard for meta['fastmcp'] before dict union
---
src/fastmcp/utilities/components.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/fastmcp/utilities/components.py b/src/fastmcp/utilities/components.py
index 49109c1aa4..53bcc17d6f 100644
--- a/src/fastmcp/utilities/components.py
+++ b/src/fastmcp/utilities/components.py
@@ -151,7 +151,9 @@ def get_meta(self) -> dict[str, Any]:
fastmcp_meta["version"] = self.version
# overwrite any existing fastmcp meta with keys from the new one
- if upstream_meta := meta.get("fastmcp"):
+ if (upstream_meta := meta.get("fastmcp")) is not None:
+ if not isinstance(upstream_meta, dict):
+ raise TypeError("meta['fastmcp'] must be a dict")
fastmcp_meta = upstream_meta | fastmcp_meta
meta["fastmcp"] = fastmcp_meta