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