From d408dbc4771ea30b076dbc6128fb86749f81e2fa Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Tue, 22 Jul 2025 19:27:43 -0400 Subject: [PATCH] Update SDK docs (#1236) --- docs/docs.json | 31 +++- docs/python-sdk/fastmcp-cli-cli.mdx | 19 +- .../fastmcp-cli-install-claude_code.mdx | 5 +- .../fastmcp-cli-install-claude_desktop.mdx | 5 +- .../python-sdk/fastmcp-cli-install-cursor.mdx | 5 +- ...g.mdx => fastmcp-cli-install-mcp_json.mdx} | 17 +- docs/python-sdk/fastmcp-cli-run.mdx | 50 +++++- docs/python-sdk/fastmcp-client-transports.mdx | 6 +- docs/python-sdk/fastmcp-mcp_config.mdx | 168 +++++++++++------- docs/python-sdk/fastmcp-server-context.mdx | 76 +++++--- docs/python-sdk/fastmcp-server-middleware.mdx | 56 ------ docs/python-sdk/fastmcp-server-proxy.mdx | 91 ++++++---- docs/python-sdk/fastmcp-server-server.mdx | 118 ++++++------ docs/python-sdk/fastmcp-settings.mdx | 39 ++-- docs/python-sdk/fastmcp-tools-tool.mdx | 30 ++-- .../python-sdk/fastmcp-tools-tool_manager.mdx | 47 +++-- .../fastmcp-tools-tool_transform.mdx | 57 +++++- .../fastmcp-utilities-json_schema.mdx | 2 +- .../fastmcp-utilities-mcp_config.mdx | 34 +--- docs/python-sdk/fastmcp-utilities-openapi.mdx | 31 ++-- docs/python-sdk/fastmcp-utilities-tests.mdx | 4 +- docs/python-sdk/fastmcp-utilities-types.mdx | 36 ++-- src/fastmcp/mcp_config.py | 20 ++- src/fastmcp/utilities/openapi.py | 3 +- src/fastmcp/utilities/types.py | 11 +- 25 files changed, 572 insertions(+), 389 deletions(-) rename docs/python-sdk/{fastmcp-cli-install-mcp_config.mdx => fastmcp-cli-install-mcp_json.mdx} (51%) delete mode 100644 docs/python-sdk/fastmcp-server-middleware.mdx diff --git a/docs/docs.json b/docs/docs.json index c81d310a9..bff00e977 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -65,7 +65,10 @@ { "group": "Essentials", "icon": "cube", - "pages": ["servers/server", "deployment/running-server"] + "pages": [ + "servers/server", + "deployment/running-server" + ] }, { "group": "Core Components", @@ -93,7 +96,9 @@ { "group": "Authentication", "icon": "shield-check", - "pages": ["servers/auth/bearer"] + "pages": [ + "servers/auth/bearer" + ] } ] }, @@ -103,7 +108,10 @@ { "group": "Essentials", "icon": "cube", - "pages": ["clients/client", "clients/transports"] + "pages": [ + "clients/client", + "clients/transports" + ] }, { "group": "Core Operations", @@ -129,7 +137,10 @@ { "group": "Authentication", "icon": "user-shield", - "pages": ["clients/auth/oauth", "clients/auth/bearer"] + "pages": [ + "clients/auth/oauth", + "clients/auth/bearer" + ] } ] }, @@ -175,12 +186,17 @@ }, { "anchor": "What's New", - "pages": ["updates", "changelog"] + "pages": [ + "updates", + "changelog" + ] }, { "anchor": "Community", "icon": "users", - "pages": ["community/showcase"] + "pages": [ + "community/showcase" + ] } ] }, @@ -207,7 +223,7 @@ "python-sdk/fastmcp-cli-install-claude_code", "python-sdk/fastmcp-cli-install-claude_desktop", "python-sdk/fastmcp-cli-install-cursor", - "python-sdk/fastmcp-cli-install-mcp_config", + "python-sdk/fastmcp-cli-install-mcp_json", "python-sdk/fastmcp-cli-install-shared" ] }, @@ -318,6 +334,7 @@ "python-sdk/fastmcp-utilities-json_schema", "python-sdk/fastmcp-utilities-json_schema_type", "python-sdk/fastmcp-utilities-logging", + "python-sdk/fastmcp-utilities-mcp_config", "python-sdk/fastmcp-utilities-openapi", "python-sdk/fastmcp-utilities-tests", "python-sdk/fastmcp-utilities-types" diff --git a/docs/python-sdk/fastmcp-cli-cli.mdx b/docs/python-sdk/fastmcp-cli-cli.mdx index 51e8bd4e1..3c1bd0c60 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 -### `version` +### `version` ```python version() @@ -20,7 +20,7 @@ version() Display version information and platform details. -### `dev` +### `dev` ```python dev(server_spec: str) -> None @@ -33,7 +33,7 @@ Run an MCP server with the MCP Inspector for development. - `server_spec`: Python file to run, optionally with \:object suffix -### `run` +### `run` ```python run(server_spec: str) -> None @@ -42,19 +42,20 @@ run(server_spec: str) -> None Run an MCP server or connect to a remote one. -The server can be specified in three ways: -1. Module approach: server.py - runs the module directly, looking for an object named 'mcp', 'server', or 'app' -2. Import approach: server.py:app - imports and runs the specified server object -3. URL approach: http://server-url - connects to a remote server and creates a proxy +The server can be specified in four ways: +1. Module approach: "server.py" - runs the module directly, looking for an object named 'mcp', 'server', or 'app' +2. Import approach: "server.py:app" - imports and runs the specified server object +3. URL approach: "http://server-url" - connects to a remote server and creates a proxy +4. MCPConfig file: "mcp.json" - runs as a proxy server for the MCP Servers in the MCPConfig file Server arguments can be passed after -- : fastmcp run server.py -- --config config.json --debug **Args:** -- `server_spec`: Python file, object specification (file\:obj), or URL +- `server_spec`: Python file, object specification (file\:obj), MCPConfig file, or URL -### `inspect` +### `inspect` ```python inspect(server_spec: str) -> None diff --git a/docs/python-sdk/fastmcp-cli-install-claude_code.mdx b/docs/python-sdk/fastmcp-cli-install-claude_code.mdx index 207756e69..cd2c07592 100644 --- a/docs/python-sdk/fastmcp-cli-install-claude_code.mdx +++ b/docs/python-sdk/fastmcp-cli-install-claude_code.mdx @@ -49,12 +49,15 @@ Install FastMCP server in Claude Code. - `with_editable`: Optional directory to install in editable mode - `with_packages`: Optional list of additional packages to install - `env_vars`: Optional dictionary of environment variables +- `python_version`: Optional Python version to use +- `with_requirements`: Optional requirements file to install from +- `project`: Optional project directory to run within **Returns:** - True if installation was successful, False otherwise -### `claude_code_command` +### `claude_code_command` ```python claude_code_command(server_spec: str) -> None diff --git a/docs/python-sdk/fastmcp-cli-install-claude_desktop.mdx b/docs/python-sdk/fastmcp-cli-install-claude_desktop.mdx index ceb3ee328..4bd05ac95 100644 --- a/docs/python-sdk/fastmcp-cli-install-claude_desktop.mdx +++ b/docs/python-sdk/fastmcp-cli-install-claude_desktop.mdx @@ -36,12 +36,15 @@ Install FastMCP server in Claude Desktop. - `with_editable`: Optional directory to install in editable mode - `with_packages`: Optional list of additional packages to install - `env_vars`: Optional dictionary of environment variables +- `python_version`: Optional Python version to use +- `with_requirements`: Optional requirements file to install from +- `project`: Optional project directory to run within **Returns:** - True if installation was successful, False otherwise -### `claude_desktop_command` +### `claude_desktop_command` ```python claude_desktop_command(server_spec: str) -> None diff --git a/docs/python-sdk/fastmcp-cli-install-cursor.mdx b/docs/python-sdk/fastmcp-cli-install-cursor.mdx index 29c20d827..2f2c9499a 100644 --- a/docs/python-sdk/fastmcp-cli-install-cursor.mdx +++ b/docs/python-sdk/fastmcp-cli-install-cursor.mdx @@ -59,12 +59,15 @@ Install FastMCP server in Cursor. - `with_editable`: Optional directory to install in editable mode - `with_packages`: Optional list of additional packages to install - `env_vars`: Optional dictionary of environment variables +- `python_version`: Optional Python version to use +- `with_requirements`: Optional requirements file to install from +- `project`: Optional project directory to run within **Returns:** - True if installation was successful, False otherwise -### `cursor_command` +### `cursor_command` ```python cursor_command(server_spec: str) -> None diff --git a/docs/python-sdk/fastmcp-cli-install-mcp_config.mdx b/docs/python-sdk/fastmcp-cli-install-mcp_json.mdx similarity index 51% rename from docs/python-sdk/fastmcp-cli-install-mcp_config.mdx rename to docs/python-sdk/fastmcp-cli-install-mcp_json.mdx index f22480400..aecf21fa7 100644 --- a/docs/python-sdk/fastmcp-cli-install-mcp_config.mdx +++ b/docs/python-sdk/fastmcp-cli-install-mcp_json.mdx @@ -1,19 +1,19 @@ --- -title: mcp_config -sidebarTitle: mcp_config +title: mcp_json +sidebarTitle: mcp_json --- -# `fastmcp.cli.install.mcp_config` +# `fastmcp.cli.install.mcp_json` MCP configuration JSON generation for FastMCP install using Cyclopts. ## Functions -### `install_mcp_config` +### `install_mcp_json` ```python -install_mcp_config(file: Path, server_object: str | None, name: str) -> bool +install_mcp_json(file: Path, server_object: str | None, name: str) -> bool ``` @@ -27,15 +27,18 @@ Generate MCP configuration JSON for manual installation. - `with_packages`: Optional list of additional packages to install - `env_vars`: Optional dictionary of environment variables - `copy`: If True, copy to clipboard instead of printing to stdout +- `python_version`: Optional Python version to use +- `with_requirements`: Optional requirements file to install from +- `project`: Optional project directory to run within **Returns:** - True if generation was successful, False otherwise -### `mcp_config_command` +### `mcp_json_command` ```python -mcp_config_command(server_spec: str) -> None +mcp_json_command(server_spec: str) -> None ``` diff --git a/docs/python-sdk/fastmcp-cli-run.mdx b/docs/python-sdk/fastmcp-cli-run.mdx index 16cb54405..b1a477db1 100644 --- a/docs/python-sdk/fastmcp-cli-run.mdx +++ b/docs/python-sdk/fastmcp-cli-run.mdx @@ -10,7 +10,7 @@ FastMCP run command implementation with enhanced type hints. ## Functions -### `is_url` +### `is_url` ```python is_url(path: str) -> bool @@ -20,7 +20,7 @@ is_url(path: str) -> bool Check if a string is a URL. -### `parse_file_path` +### `parse_file_path` ```python parse_file_path(server_spec: str) -> tuple[Path, str | None] @@ -36,7 +36,7 @@ Parse a file path that may include a server object specification. - Tuple of (file_path, server_object) -### `import_server` +### `import_server` ```python import_server(file: Path, server_object: str | None = None) -> Any @@ -53,7 +53,30 @@ Import a MCP server from a file. - The server object -### `create_client_server` +### `run_with_uv` + +```python +run_with_uv(server_spec: str, python_version: str | None = None, with_packages: list[str] | None = None, with_requirements: Path | None = None, project: Path | None = None, transport: TransportType | None = None, host: str | None = None, port: int | None = None, path: str | None = None, log_level: LogLevelType | None = None, show_banner: bool = True) -> None +``` + + +Run a MCP server using uv run subprocess. + +**Args:** +- `server_spec`: Python file, object specification (file\:obj), or URL +- `python_version`: Python version to use (e.g. "3.10") +- `with_packages`: Additional packages to install +- `with_requirements`: Requirements file to use +- `project`: Run the command within the given project directory +- `transport`: Transport protocol to use +- `host`: Host to bind to when using http transport +- `port`: Port to bind to when using http transport +- `path`: Path to bind to when using http transport +- `log_level`: Log level +- `show_banner`: Whether to show the server banner + + +### `create_client_server` ```python create_client_server(url: str) -> Any @@ -69,7 +92,17 @@ Create a FastMCP server from a client URL. - A FastMCP server instance -### `import_server_with_args` +### `create_mcp_config_server` + +```python +create_mcp_config_server(mcp_config_path: Path) -> FastMCP[None] +``` + + +Create a FastMCP server from a MCPConfig. + + +### `import_server_with_args` ```python import_server_with_args(file: Path, server_object: str | None = None, server_args: list[str] | None = None) -> Any @@ -87,17 +120,17 @@ Import a server with optional command line arguments. - The imported server object -### `run_command` +### `run_command` ```python -run_command(server_spec: str, transport: TransportType | None = None, host: str | None = None, port: int | None = None, path: str | None = None, log_level: LogLevelType | None = None, server_args: list[str] | None = None, show_banner: bool = True) -> None +run_command(server_spec: str, transport: TransportType | None = None, host: str | None = None, port: int | None = None, path: str | None = None, log_level: LogLevelType | None = None, server_args: list[str] | None = None, show_banner: bool = True, use_direct_import: bool = False) -> None ``` Run a MCP server or connect to a remote one. **Args:** -- `server_spec`: Python file, object specification (file\:obj), or URL +- `server_spec`: Python file, object specification (file\:obj), MCPConfig file, or URL - `transport`: Transport protocol to use - `host`: Host to bind to when using http transport - `port`: Port to bind to when using http transport @@ -105,4 +138,5 @@ Run a MCP server or connect to a remote one. - `log_level`: Log level - `server_args`: Additional arguments to pass to the server - `show_banner`: Whether to show the server banner +- `use_direct_import`: Whether to use direct import instead of subprocess diff --git a/docs/python-sdk/fastmcp-client-transports.mdx b/docs/python-sdk/fastmcp-client-transports.mdx index 8e29e754f..0a1c7190d 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 @@ -238,7 +238,7 @@ object or dictionary matching the MCPConfig schema. It supports two key scenario 1. If the MCPConfig contains exactly one server, it creates a direct transport to that server. 2. If the MCPConfig contains multiple servers, it creates a composite client by mounting - all servers on a single FastMCP instance, with each server's name used as its mounting prefix. + all servers on a single FastMCP instance, with each server's name, by default, used as its mounting prefix. In the multi-server case, tools are accessible with the prefix pattern `{server_name}_{tool_name}` and resources with the pattern `protocol://{server_name}/path/to/resource`. @@ -281,7 +281,7 @@ async with client: **Methods:** -#### `connect_session` +#### `connect_session` ```python connect_session(self, **session_kwargs: Unpack[SessionKwargs]) -> AsyncIterator[ClientSession] diff --git a/docs/python-sdk/fastmcp-mcp_config.mdx b/docs/python-sdk/fastmcp-mcp_config.mdx index 3c6839dad..bd3bd8e06 100644 --- a/docs/python-sdk/fastmcp-mcp_config.mdx +++ b/docs/python-sdk/fastmcp-mcp_config.mdx @@ -15,22 +15,24 @@ The configuration format supports both stdio and remote (HTTP/SSE) transports, w field definitions for server metadata, authentication, and execution parameters. Example configuration: - { - "mcpServers": { - "my-server": { - "command": "npx", - "args": ["-y", "@my/mcp-server"], - "env": {"API_KEY": "secret"}, - "timeout": 30000, - "description": "My MCP server" - } +```json +{ + "mcpServers": { + "my-server": { + "command": "npx", + "args": ["-y", "@my/mcp-server"], + "env": {"API_KEY": "secret"}, + "timeout": 30000, + "description": "My MCP server" } } +} +``` ## Functions -### `infer_transport_type_from_url` +### `infer_transport_type_from_url` ```python infer_transport_type_from_url(url: str | AnyUrl) -> Literal['http', 'sse'] @@ -40,19 +42,22 @@ 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: StdioMCPServer | RemoteMCPServer) -> None +update_config_file(file_path: Path, server_name: str, server_config: CanonicalMCPServerTypes) -> None ``` -Update MCP configuration file with new server, preserving existing fields. +Update an MCP configuration file from a server object, preserving existing fields. + +This is used for updating the mcpServer configurations of third-party tools so we do not +worry about transforming server objects here. ## Classes -### `StdioMCPServer` +### `StdioMCPServer` MCP server configuration for stdio transport. @@ -62,13 +67,19 @@ This is the canonical configuration format for MCP servers using stdio transport **Methods:** -#### `to_transport` +#### `to_transport` ```python to_transport(self) -> StdioTransport ``` -### `RemoteMCPServer` +### `TransformingStdioMCPServer` + + +A Stdio server with tool transforms. + + +### `RemoteMCPServer` MCP server configuration for HTTP/SSE transport. @@ -78,13 +89,85 @@ This is the canonical configuration format for MCP servers using remote transpor **Methods:** -#### `to_transport` +#### `to_transport` ```python to_transport(self) -> StreamableHttpTransport | SSETransport ``` -### `MCPConfig` +### `TransformingRemoteMCPServer` + + +A Remote server with tool transforms. + + +### `MCPConfig` + + +A configuration object for MCP Servers that conforms to the canonical MCP configuration format +while adding additional fields for enabling FastMCP-specific features like tool transformations +and filtering by tags. + +For an MCPConfig that is strictly canonical, see the `CanonicalMCPConfig` class. + + +**Methods:** + +#### `validate_mcp_servers` + +```python +validate_mcp_servers(self, info: ValidationInfo) -> dict[str, Any] +``` + +Validate the MCP servers. + + +#### `add_server` + +```python +add_server(self, name: str, server: MCPServerTypes) -> None +``` + +Add or update a server in the configuration. + + +#### `from_dict` + +```python +from_dict(cls, config: dict[str, Any]) -> Self +``` + +Parse MCP configuration from dictionary format. + + +#### `to_dict` + +```python +to_dict(self) -> dict[str, Any] +``` + +Convert MCPConfig to dictionary format, preserving all fields. + + +#### `write_to_file` + +```python +write_to_file(self, file_path: Path) -> None +``` + +Write configuration to JSON file. + + +#### `from_file` + +```python +from_file(cls, file_path: Path) -> Self +``` + +Load configuration from JSON file. + + +### `CanonicalMCPConfig` Canonical MCP configuration format. @@ -95,56 +178,11 @@ The format is designed to be client-agnostic and extensible for future use cases **Methods:** -#### `from_dict` +#### `add_server` ```python -from_dict(cls, config: dict[str, Any]) -> MCPConfig -``` - -Parse MCP configuration from dictionary format. - - -#### `to_dict` - -```python -to_dict(self) -> dict[str, Any] -``` - -Convert MCPConfig to dictionary format, preserving all fields. - - -#### `write_to_file` - -```python -write_to_file(self, file_path: Path) -> None -``` - -Write configuration to JSON file. - - -#### `from_file` - -```python -from_file(cls, file_path: Path) -> MCPConfig -``` - -Load configuration from JSON file. - - -#### `add_server` - -```python -add_server(self, name: str, server: StdioMCPServer | RemoteMCPServer) -> None +add_server(self, name: str, server: CanonicalMCPServerTypes) -> None ``` Add or update a server in the configuration. - -#### `remove_server` - -```python -remove_server(self, name: str) -> None -``` - -Remove a server from the configuration. - diff --git a/docs/python-sdk/fastmcp-server-context.mdx b/docs/python-sdk/fastmcp-server-context.mdx index b41e84aa0..edca73dda 100644 --- a/docs/python-sdk/fastmcp-server-context.mdx +++ b/docs/python-sdk/fastmcp-server-context.mdx @@ -7,7 +7,7 @@ sidebarTitle: context ## Functions -### `set_context` +### `set_context` ```python set_context(context: Context) -> Generator[Context, None, None] @@ -15,7 +15,7 @@ set_context(context: Context) -> Generator[Context, None, None] ## Classes -### `Context` +### `Context` Context object providing access to MCP capabilities. @@ -44,16 +44,26 @@ 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_value("key", "value") + value = ctx.get_state_value("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. + The context parameter name can be anything as long as it's annotated with Context. The context is optional - tools that don't need it can omit the parameter. **Methods:** -#### `request_context` +#### `request_context` ```python request_context(self) -> RequestContext @@ -64,7 +74,7 @@ Access to the underlying request context. If called outside of a request context, this will raise a ValueError. -#### `report_progress` +#### `report_progress` ```python report_progress(self, progress: float, total: float | None = None, message: str | None = None) -> None @@ -77,7 +87,7 @@ Report progress for the current operation. - `total`: Optional total value e.g. 100 -#### `read_resource` +#### `read_resource` ```python read_resource(self, uri: str | AnyUrl) -> list[ReadResourceContents] @@ -92,7 +102,7 @@ Read a resource by URI. - The resource content as either text or bytes -#### `log` +#### `log` ```python log(self, message: str, level: LoggingLevel | None = None, logger_name: str | None = None) -> None @@ -107,7 +117,7 @@ Send a log message to the client. - `logger_name`: Optional logger name -#### `client_id` +#### `client_id` ```python client_id(self) -> str | None @@ -116,7 +126,7 @@ client_id(self) -> str | None Get the client ID if available. -#### `request_id` +#### `request_id` ```python request_id(self) -> str @@ -125,7 +135,7 @@ request_id(self) -> str Get the unique ID for this request. -#### `session_id` +#### `session_id` ```python session_id(self) -> str | None @@ -142,7 +152,7 @@ the same client session. - for stdio and in-memory transports which don't use session IDs. -#### `session` +#### `session` ```python session(self) -> ServerSession @@ -151,7 +161,7 @@ session(self) -> ServerSession Access to the underlying session for advanced usage. -#### `debug` +#### `debug` ```python debug(self, message: str, logger_name: str | None = None) -> None @@ -160,7 +170,7 @@ debug(self, message: str, logger_name: str | None = None) -> None Send a debug log message. -#### `info` +#### `info` ```python info(self, message: str, logger_name: str | None = None) -> None @@ -169,7 +179,7 @@ info(self, message: str, logger_name: str | None = None) -> None Send an info log message. -#### `warning` +#### `warning` ```python warning(self, message: str, logger_name: str | None = None) -> None @@ -178,7 +188,7 @@ warning(self, message: str, logger_name: str | None = None) -> None Send a warning log message. -#### `error` +#### `error` ```python error(self, message: str, logger_name: str | None = None) -> None @@ -187,7 +197,7 @@ error(self, message: str, logger_name: str | None = None) -> None Send an error log message. -#### `list_roots` +#### `list_roots` ```python list_roots(self) -> list[Root] @@ -196,7 +206,7 @@ list_roots(self) -> list[Root] List the roots available to the server, as indicated by the client. -#### `send_tool_list_changed` +#### `send_tool_list_changed` ```python send_tool_list_changed(self) -> None @@ -205,7 +215,7 @@ send_tool_list_changed(self) -> None Send a tool list changed notification to the client. -#### `send_resource_list_changed` +#### `send_resource_list_changed` ```python send_resource_list_changed(self) -> None @@ -214,7 +224,7 @@ send_resource_list_changed(self) -> None Send a resource list changed notification to the client. -#### `send_prompt_list_changed` +#### `send_prompt_list_changed` ```python send_prompt_list_changed(self) -> None @@ -223,7 +233,7 @@ send_prompt_list_changed(self) -> None Send a prompt list changed notification to the client. -#### `sample` +#### `sample` ```python sample(self, messages: str | list[str | SamplingMessage], system_prompt: str | None = None, include_context: IncludeContext | None = None, temperature: float | None = None, max_tokens: int | None = None, model_preferences: ModelPreferences | str | list[str] | None = None) -> ContentBlock @@ -236,25 +246,25 @@ completion from the client. The client must be appropriately configured, or the request will error. -#### `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: type[T] | list[str] | None = None) -> AcceptedElicitation[T] | AcceptedElicitation[dict[str, Any]] | AcceptedElicitation[str] | DeclinedElicitation | CancelledElicitation @@ -283,7 +293,7 @@ type or dataclass or BaseModel. If it is a primitive type, an object schema with a single "value" field will be generated. -#### `get_http_request` +#### `get_http_request` ```python get_http_request(self) -> Request @@ -291,3 +301,21 @@ get_http_request(self) -> Request Get the active starlette request. + +#### `set_state` + +```python +set_state(self, key: str, value: Any) -> None +``` + +Set a value in the context 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. + diff --git a/docs/python-sdk/fastmcp-server-middleware.mdx b/docs/python-sdk/fastmcp-server-middleware.mdx deleted file mode 100644 index ec8eab242..000000000 --- a/docs/python-sdk/fastmcp-server-middleware.mdx +++ /dev/null @@ -1,56 +0,0 @@ ---- -title: middleware -sidebarTitle: middleware ---- - -# `fastmcp.server.middleware` - -## Functions - -### `make_middleware_wrapper` - -```python -make_middleware_wrapper(middleware: Middleware, call_next: CallNext[T, R]) -> CallNext[T, R] -``` - - -Create a wrapper that applies a single middleware to a context. The -closure bakes in the middleware and call_next function, so it can be -passed to other functions that expect a call_next function. - - -## Classes - -### `CallNext` - -### `CallToolResult` - -### `ListToolsResult` - -### `ListResourcesResult` - -### `ListResourceTemplatesResult` - -### `ListPromptsResult` - -### `ServerResultProtocol` - -### `MiddlewareContext` - - -Unified context for all middleware operations. - - -**Methods:** - -#### `copy` - -```python -copy(self, **kwargs: Any) -> MiddlewareContext[T] -``` - -### `Middleware` - - -Base class for FastMCP middleware with dispatching hooks. - diff --git a/docs/python-sdk/fastmcp-server-proxy.mdx b/docs/python-sdk/fastmcp-server-proxy.mdx index db83a5611..ca07a9cda 100644 --- a/docs/python-sdk/fastmcp-server-proxy.mdx +++ b/docs/python-sdk/fastmcp-server-proxy.mdx @@ -7,7 +7,7 @@ sidebarTitle: proxy ## Functions -### `default_proxy_roots_handler` +### `default_proxy_roots_handler` ```python default_proxy_roots_handler(context: RequestContext[ClientSession, LifespanContextT]) -> RootsList @@ -19,7 +19,7 @@ A handler that forwards the list roots request from the remote server to the pro ## Classes -### `ProxyToolManager` +### `ProxyToolManager` A ToolManager that sources its tools from a remote client in addition to local and mounted tools. @@ -27,7 +27,7 @@ A ToolManager that sources its tools from a remote client in addition to local a **Methods:** -#### `get_tools` +#### `get_tools` ```python get_tools(self) -> dict[str, Tool] @@ -36,7 +36,7 @@ get_tools(self) -> dict[str, Tool] Gets the unfiltered tool inventory including local, mounted, and proxy tools. -#### `list_tools` +#### `list_tools` ```python list_tools(self) -> list[Tool] @@ -45,7 +45,7 @@ list_tools(self) -> list[Tool] Gets the filtered list of tools including local, mounted, and proxy tools. -#### `call_tool` +#### `call_tool` ```python call_tool(self, key: str, arguments: dict[str, Any]) -> ToolResult @@ -54,7 +54,7 @@ call_tool(self, key: str, arguments: dict[str, Any]) -> ToolResult Calls a tool, trying local/mounted first, then proxy if not found. -### `ProxyResourceManager` +### `ProxyResourceManager` A ResourceManager that sources its resources from a remote client in addition to local and mounted resources. @@ -62,7 +62,7 @@ A ResourceManager that sources its resources from a remote client in addition to **Methods:** -#### `get_resources` +#### `get_resources` ```python get_resources(self) -> dict[str, Resource] @@ -71,7 +71,7 @@ get_resources(self) -> dict[str, Resource] Gets the unfiltered resource inventory including local, mounted, and proxy resources. -#### `get_resource_templates` +#### `get_resource_templates` ```python get_resource_templates(self) -> dict[str, ResourceTemplate] @@ -80,7 +80,7 @@ get_resource_templates(self) -> dict[str, ResourceTemplate] Gets the unfiltered template inventory including local, mounted, and proxy templates. -#### `list_resources` +#### `list_resources` ```python list_resources(self) -> list[Resource] @@ -89,7 +89,7 @@ list_resources(self) -> list[Resource] Gets the filtered list of resources including local, mounted, and proxy resources. -#### `list_resource_templates` +#### `list_resource_templates` ```python list_resource_templates(self) -> list[ResourceTemplate] @@ -98,7 +98,7 @@ list_resource_templates(self) -> list[ResourceTemplate] Gets the filtered list of templates including local, mounted, and proxy templates. -#### `read_resource` +#### `read_resource` ```python read_resource(self, uri: AnyUrl | str) -> str | bytes @@ -107,7 +107,7 @@ read_resource(self, uri: AnyUrl | str) -> str | bytes Reads a resource, trying local/mounted first, then proxy if not found. -### `ProxyPromptManager` +### `ProxyPromptManager` A PromptManager that sources its prompts from a remote client in addition to local and mounted prompts. @@ -115,7 +115,7 @@ A PromptManager that sources its prompts from a remote client in addition to loc **Methods:** -#### `get_prompts` +#### `get_prompts` ```python get_prompts(self) -> dict[str, Prompt] @@ -124,7 +124,7 @@ get_prompts(self) -> dict[str, Prompt] Gets the unfiltered prompt inventory including local, mounted, and proxy prompts. -#### `list_prompts` +#### `list_prompts` ```python list_prompts(self) -> list[Prompt] @@ -133,7 +133,7 @@ list_prompts(self) -> list[Prompt] Gets the filtered list of prompts including local, mounted, and proxy prompts. -#### `render_prompt` +#### `render_prompt` ```python render_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> GetPromptResult @@ -142,7 +142,7 @@ render_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> GetPr Renders a prompt, trying local/mounted first, then proxy if not found. -### `ProxyTool` +### `ProxyTool` A Tool that represents and executes a tool on a remote server. @@ -150,7 +150,7 @@ A Tool that represents and executes a tool on a remote server. **Methods:** -#### `from_mcp_tool` +#### `from_mcp_tool` ```python from_mcp_tool(cls, client: Client, mcp_tool: mcp.types.Tool) -> ProxyTool @@ -159,7 +159,7 @@ from_mcp_tool(cls, client: Client, mcp_tool: mcp.types.Tool) -> ProxyTool 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 @@ -168,7 +168,7 @@ run(self, arguments: dict[str, Any], context: Context | None = None) -> ToolResu Executes the tool by making a call through the client. -### `ProxyResource` +### `ProxyResource` A Resource that represents and reads a resource from a remote server. @@ -176,7 +176,7 @@ A Resource that represents and reads a resource from a remote server. **Methods:** -#### `from_mcp_resource` +#### `from_mcp_resource` ```python from_mcp_resource(cls, client: Client, mcp_resource: mcp.types.Resource) -> ProxyResource @@ -185,7 +185,7 @@ from_mcp_resource(cls, client: Client, mcp_resource: mcp.types.Resource) -> Prox Factory method to create a ProxyResource from a raw MCP resource schema. -#### `read` +#### `read` ```python read(self) -> str | bytes @@ -194,7 +194,7 @@ read(self) -> str | bytes Read the resource content from the remote server. -### `ProxyTemplate` +### `ProxyTemplate` A ResourceTemplate that represents and creates resources from a remote server template. @@ -202,7 +202,7 @@ A ResourceTemplate that represents and creates resources from a remote server te **Methods:** -#### `from_mcp_template` +#### `from_mcp_template` ```python from_mcp_template(cls, client: Client, mcp_template: mcp.types.ResourceTemplate) -> ProxyTemplate @@ -211,7 +211,7 @@ from_mcp_template(cls, client: Client, mcp_template: mcp.types.ResourceTemplate) 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 @@ -220,7 +220,7 @@ create_resource(self, uri: str, params: dict[str, Any], context: Context | None Create a resource from the template by calling the remote server. -### `ProxyPrompt` +### `ProxyPrompt` A Prompt that represents and renders a prompt from a remote server. @@ -228,7 +228,7 @@ A Prompt that represents and renders a prompt from a remote server. **Methods:** -#### `from_mcp_prompt` +#### `from_mcp_prompt` ```python from_mcp_prompt(cls, client: Client, mcp_prompt: mcp.types.Prompt) -> ProxyPrompt @@ -237,7 +237,7 @@ from_mcp_prompt(cls, client: Client, mcp_prompt: mcp.types.Prompt) -> ProxyPromp Factory method to create a ProxyPrompt from a raw MCP prompt schema. -#### `render` +#### `render` ```python render(self, arguments: dict[str, Any]) -> list[PromptMessage] @@ -246,14 +246,14 @@ render(self, arguments: dict[str, Any]) -> list[PromptMessage] Render the prompt by making a call through the client. -### `FastMCPProxy` +### `FastMCPProxy` A FastMCP server that acts as a proxy to a remote MCP-compliant server. It uses specialized managers that fulfill requests via a client factory. -### `ProxyClient` +### `ProxyClient` A proxy client that forwards advanced interactions between a remote MCP server and the proxy's connected clients. @@ -262,7 +262,7 @@ Supports forwarding roots, sampling, elicitation, logging, and progress. **Methods:** -#### `default_sampling_handler` +#### `default_sampling_handler` ```python default_sampling_handler(cls, messages: list[mcp.types.SamplingMessage], params: mcp.types.CreateMessageRequestParams, context: RequestContext[ClientSession, LifespanContextT]) -> mcp.types.CreateMessageResult @@ -271,7 +271,7 @@ default_sampling_handler(cls, messages: list[mcp.types.SamplingMessage], params: A handler that forwards the sampling request from the remote server to the proxy's connected clients and relays the response back to the remote server. -#### `default_elicitation_handler` +#### `default_elicitation_handler` ```python default_elicitation_handler(cls, message: str, response_type: type, params: mcp.types.ElicitRequestParams, context: RequestContext[ClientSession, LifespanContextT]) -> ElicitResult @@ -280,7 +280,7 @@ default_elicitation_handler(cls, message: str, response_type: type, params: mcp. A handler that forwards the elicitation request from the remote server to the proxy's connected clients and relays the response back to the remote server. -#### `default_log_handler` +#### `default_log_handler` ```python default_log_handler(cls, message: LogMessage) -> None @@ -289,7 +289,7 @@ default_log_handler(cls, message: LogMessage) -> None A handler that forwards the log notification from the remote server to the proxy's connected clients. -#### `default_progress_handler` +#### `default_progress_handler` ```python default_progress_handler(cls, progress: float, total: float | None, message: str | None) -> None @@ -297,3 +297,28 @@ default_progress_handler(cls, progress: float, total: float | None, message: str A handler that forwards the progress notification from the remote server to the proxy's connected clients. + +### `StatefulProxyClient` + + +A proxy client that provides a stateful client factory for the proxy server. + +The stateful proxy client bound its copy to the server session. +And it will be disconnected when the session is exited. + +This is useful to proxy a stateful mcp server such as the Playwright MCP server. +Note that it is essential to ensure that the proxy server itself is also stateful. + + +**Methods:** + +#### `new_stateful` + +```python +new_stateful(self) -> Client[ClientTransportT] +``` + +Create a new stateful proxy client instance with the same configuration. + +Use this method as the client factory for stateful proxy server. + diff --git a/docs/python-sdk/fastmcp-server-server.mdx b/docs/python-sdk/fastmcp-server-server.mdx index 986e382bd..611980c70 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 context object -### `add_resource_prefix` +### `add_resource_prefix` ```python add_resource_prefix(uri: str, prefix: str, prefix_format: Literal['protocol', 'path'] | None = None) -> str @@ -64,7 +64,7 @@ add_resource_prefix("resource:///absolute/path", "prefix") - `ValueError`: If the URI doesn't match the expected protocol\://path format -### `remove_resource_prefix` +### `remove_resource_prefix` ```python remove_resource_prefix(uri: str, prefix: str, prefix_format: Literal['protocol', 'path'] | None = None) -> str @@ -103,7 +103,7 @@ remove_resource_prefix("resource://prefix//absolute/path", "prefix") - `ValueError`: If the URI doesn't match the expected protocol\://path format -### `has_resource_prefix` +### `has_resource_prefix` ```python has_resource_prefix(uri: str, prefix: str, prefix_format: Literal['protocol', 'path'] | None = None) -> bool @@ -143,29 +143,29 @@ False ## Classes -### `FastMCP` +### `FastMCP` **Methods:** -#### `settings` +#### `settings` ```python settings(self) -> Settings ``` -#### `name` +#### `name` ```python name(self) -> str ``` -#### `instructions` +#### `instructions` ```python instructions(self) -> str | None ``` -#### `run_async` +#### `run_async` ```python run_async(self, transport: Transport | None = None, show_banner: bool = True, **transport_kwargs: Any) -> None @@ -177,7 +177,7 @@ Run the FastMCP server asynchronously. - `transport`: Transport protocol to use ("stdio", "sse", or "streamable-http") -#### `run` +#### `run` ```python run(self, transport: Transport | None = None, show_banner: bool = True, **transport_kwargs: Any) -> None @@ -189,13 +189,13 @@ Run the FastMCP server. Note this is a synchronous function. - `transport`: Transport protocol to use ("stdio", "sse", or "streamable-http") -#### `add_middleware` +#### `add_middleware` ```python add_middleware(self, middleware: Middleware) -> None ``` -#### `get_tools` +#### `get_tools` ```python get_tools(self) -> dict[str, Tool] @@ -204,13 +204,13 @@ get_tools(self) -> dict[str, Tool] Get all registered tools, indexed by registered key. -#### `get_tool` +#### `get_tool` ```python get_tool(self, key: str) -> Tool ``` -#### `get_resources` +#### `get_resources` ```python get_resources(self) -> dict[str, Resource] @@ -219,13 +219,13 @@ get_resources(self) -> dict[str, Resource] Get all registered resources, indexed by registered key. -#### `get_resource` +#### `get_resource` ```python get_resource(self, key: str) -> Resource ``` -#### `get_resource_templates` +#### `get_resource_templates` ```python get_resource_templates(self) -> dict[str, ResourceTemplate] @@ -234,7 +234,7 @@ get_resource_templates(self) -> dict[str, ResourceTemplate] Get all registered resource templates, indexed by registered key. -#### `get_resource_template` +#### `get_resource_template` ```python get_resource_template(self, key: str) -> ResourceTemplate @@ -243,7 +243,7 @@ get_resource_template(self, key: str) -> ResourceTemplate Get a registered resource template by key. -#### `get_prompts` +#### `get_prompts` ```python get_prompts(self) -> dict[str, Prompt] @@ -252,16 +252,16 @@ get_prompts(self) -> dict[str, Prompt] List all available prompts. -#### `get_prompt` +#### `get_prompt` ```python get_prompt(self, key: str) -> Prompt ``` -#### `custom_route` +#### `custom_route` ```python -custom_route(self, path: str, methods: list[str], name: str | None = None, include_in_schema: bool = True) +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]]] ``` Decorator to register a custom HTTP route on the FastMCP server. @@ -279,7 +279,7 @@ 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 @@ -297,7 +297,7 @@ with the Context type annotation. See the @tool decorator for examples. - The tool instance that was added to the server. -#### `remove_tool` +#### `remove_tool` ```python remove_tool(self, name: str) -> None @@ -312,19 +312,37 @@ Remove a tool from the server. - `NotFoundError`: If the tool is not found -#### `tool` +#### `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` ```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 @@ -379,7 +397,7 @@ server.tool(my_function, name="custom_name") ``` -#### `add_resource` +#### `add_resource` ```python add_resource(self, resource: Resource) -> Resource @@ -394,7 +412,7 @@ Add a resource to the server. - The resource instance that was added to the server. -#### `add_template` +#### `add_template` ```python add_template(self, template: ResourceTemplate) -> ResourceTemplate @@ -409,7 +427,7 @@ Add a resource template to the server. - The template instance that was added to the server. -#### `add_resource_fn` +#### `add_resource_fn` ```python add_resource_fn(self, fn: AnyFunction, uri: str, name: str | None = None, description: str | None = None, mime_type: str | None = None, tags: set[str] | None = None) -> None @@ -429,7 +447,7 @@ has parameters, it will be registered as a template resource. - `tags`: Optional set of tags for categorizing the resource -#### `resource` +#### `resource` ```python resource(self, uri: str) -> Callable[[AnyFunction], Resource | ResourceTemplate] @@ -487,7 +505,7 @@ async def get_weather(city: str) -> str: ``` -#### `add_prompt` +#### `add_prompt` ```python add_prompt(self, prompt: Prompt) -> Prompt @@ -502,19 +520,19 @@ Add a prompt to the server. - 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 @@ -591,7 +609,7 @@ Decorator to register a prompt. ``` -#### `run_stdio_async` +#### `run_stdio_async` ```python run_stdio_async(self, show_banner: bool = True) -> None @@ -600,7 +618,7 @@ run_stdio_async(self, show_banner: bool = True) -> None Run the server using stdio transport. -#### `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, stateless_http: bool | None = None) -> None @@ -619,7 +637,7 @@ Run the server using HTTP transport. - `stateless_http`: Whether to use stateless HTTP (defaults to settings.stateless_http) -#### `run_sse_async` +#### `run_sse_async` ```python run_sse_async(self, host: str | None = None, port: int | None = None, log_level: str | None = None, path: str | None = None, uvicorn_config: dict[str, Any] | None = None) -> None @@ -628,7 +646,7 @@ run_sse_async(self, host: str | None = None, port: int | None = None, log_level: Run the server using SSE transport. -#### `sse_app` +#### `sse_app` ```python sse_app(self, path: str | None = None, message_path: str | None = None, middleware: list[ASGIMiddleware] | None = None) -> StarletteWithLifespan @@ -642,7 +660,7 @@ Create a Starlette app for the SSE server. - `middleware`: A list of middleware to apply to the app -#### `streamable_http_app` +#### `streamable_http_app` ```python streamable_http_app(self, path: str | None = None, middleware: list[ASGIMiddleware] | None = None) -> StarletteWithLifespan @@ -655,7 +673,7 @@ Create a Starlette app for the StreamableHTTP server. - `middleware`: A list of middleware to apply to the app -#### `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') -> StarletteWithLifespan @@ -672,13 +690,13 @@ Create a Starlette app using the specified HTTP transport. - A Starlette application configured with the specified transport -#### `run_streamable_http_async` +#### `run_streamable_http_async` ```python run_streamable_http_async(self, host: str | None = None, port: int | None = None, log_level: str | None = None, path: str | None = None, uvicorn_config: dict[str, Any] | None = None) -> None ``` -#### `mount` +#### `mount` ```python mount(self, server: FastMCP[LifespanResultT], prefix: str | None = None, as_proxy: bool | None = None) -> None @@ -732,7 +750,7 @@ automatically determined based on whether the server has a custom lifespan - `prompt_separator`: Deprecated. Separator character for prompt names. -#### `import_server` +#### `import_server` ```python import_server(self, server: FastMCP[LifespanResultT], prefix: str | None = None, tool_separator: str | None = None, resource_separator: str | None = None, prompt_separator: str | None = None) -> None @@ -773,25 +791,25 @@ applied using the protocol\://prefix/path format - `prompt_separator`: Deprecated. Separator for prompt names. -#### `from_openapi` +#### `from_openapi` ```python -from_openapi(cls, openapi_spec: dict[str, Any], client: httpx.AsyncClient, 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, **settings: Any) -> FastMCPOpenAPI +from_openapi(cls, openapi_spec: dict[str, Any], client: httpx.AsyncClient, route_maps: list[RouteMap] | list[RouteMapNew] | None = None, route_map_fn: OpenAPIRouteMapFn | OpenAPIRouteMapFnNew | None = None, mcp_component_fn: OpenAPIComponentFn | OpenAPIComponentFnNew | None = None, mcp_names: dict[str, str] | None = None, tags: set[str] | None = None, **settings: Any) -> FastMCPOpenAPI | FastMCPOpenAPINew ``` Create a FastMCP server from an OpenAPI specification. -#### `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, **settings: Any) -> FastMCPOpenAPI +from_fastapi(cls, app: Any, name: str | None = None, route_maps: list[RouteMap] | list[RouteMapNew] | None = None, route_map_fn: OpenAPIRouteMapFn | OpenAPIRouteMapFnNew | None = None, mcp_component_fn: OpenAPIComponentFn | OpenAPIComponentFnNew | None = None, mcp_names: dict[str, str] | None = None, httpx_client_kwargs: dict[str, Any] | None = None, tags: set[str] | None = None, **settings: Any) -> FastMCPOpenAPI | FastMCPOpenAPINew ``` Create a FastMCP server from a FastAPI application. -#### `as_proxy` +#### `as_proxy` ```python as_proxy(cls, backend: Client[ClientTransportT] | ClientTransport | FastMCP[Any] | AnyUrl | Path | MCPConfig | dict[str, Any] | str, **settings: Any) -> FastMCPProxy @@ -805,7 +823,7 @@ instance or any value accepted as the `transport` argument of `fastmcp.client.Client` constructor. -#### `from_client` +#### `from_client` ```python from_client(cls, client: Client[ClientTransportT], **settings: Any) -> FastMCPProxy @@ -814,4 +832,4 @@ from_client(cls, client: Client[ClientTransportT], **settings: Any) -> FastMCPPr Create a FastMCP proxy server from a FastMCP client. -### `MountedServer` +### `MountedServer` diff --git a/docs/python-sdk/fastmcp-settings.mdx b/docs/python-sdk/fastmcp-settings.mdx index 7f546c31b..6c460937b 100644 --- a/docs/python-sdk/fastmcp-settings.mdx +++ b/docs/python-sdk/fastmcp-settings.mdx @@ -25,7 +25,9 @@ get_field_value(self, field: FieldInfo, field_name: str) -> tuple[Any, str, bool ### `ExtendedSettingsConfigDict` -### `Settings` +### `ExperimentalSettings` + +### `Settings` FastMCP settings. @@ -33,13 +35,33 @@ FastMCP settings. **Methods:** -#### `settings_customise_sources` +#### `get_setting` + +```python +get_setting(self, attr: str) -> Any +``` + +Get a setting. If the setting contains one or more `__`, it will be +treated as a nested setting. + + +#### `set_setting` + +```python +set_setting(self, attr: str, value: Any) -> None +``` + +Set a setting. If the setting contains one or more `__`, it will be +treated as a nested setting. + + +#### `settings_customise_sources` ```python settings_customise_sources(cls, settings_cls: type[BaseSettings], init_settings: PydanticBaseSettingsSource, env_settings: PydanticBaseSettingsSource, dotenv_settings: PydanticBaseSettingsSource, file_secret_settings: PydanticBaseSettingsSource) -> tuple[PydanticBaseSettingsSource, ...] ``` -#### `settings` +#### `settings` ```python settings(self) -> Self @@ -49,17 +71,8 @@ This property is for backwards compatibility with FastMCP < 2.8.0, which accessed fastmcp.settings.settings -#### `normalize_log_level` +#### `normalize_log_level` ```python normalize_log_level(cls, v) ``` - -#### `setup_logging` - -```python -setup_logging(self) -> Self -``` - -Finalize the settings. - diff --git a/docs/python-sdk/fastmcp-tools-tool.mdx b/docs/python-sdk/fastmcp-tools-tool.mdx index 60c8fff9a..ce27bb86f 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]] ``` -### `Tool` +### `Tool` Internal tool registration info. @@ -33,25 +33,25 @@ Internal tool registration info. **Methods:** -#### `enable` +#### `enable` ```python enable(self) -> None ``` -#### `disable` +#### `disable` ```python disable(self) -> None ``` -#### `to_mcp_tool` +#### `to_mcp_tool` ```python to_mcp_tool(self, **overrides: Any) -> MCPTool ``` -#### `from_function` +#### `from_function` ```python from_function(fn: Callable[..., Any], name: str | None = None, title: str | None = None, description: str | None = None, tags: set[str] | None = None, annotations: ToolAnnotations | None = None, exclude_args: list[str] | None = None, output_schema: dict[str, Any] | None | NotSetT | Literal[False] = NotSet, serializer: Callable[[Any], str] | None = None, enabled: bool | None = None) -> FunctionTool @@ -60,7 +60,7 @@ from_function(fn: Callable[..., Any], name: str | None = None, title: str | None Create a Tool from a function. -#### `run` +#### `run` ```python run(self, arguments: dict[str, Any]) -> ToolResult @@ -75,17 +75,17 @@ implemented by subclasses. (list of ContentBlocks, dict of structured output). -#### `from_tool` +#### `from_tool` ```python from_tool(cls, tool: Tool, transform_fn: Callable[..., Any] | None = None, name: str | None = None, title: str | None | NotSetT = NotSet, transform_args: dict[str, ArgTransform] | None = None, description: str | None | NotSetT = NotSet, tags: set[str] | None = None, annotations: ToolAnnotations | None = None, output_schema: dict[str, Any] | None | Literal[False] = None, serializer: Callable[[Any], str] | None = None, enabled: bool | None = None) -> TransformedTool ``` -### `FunctionTool` +### `FunctionTool` **Methods:** -#### `from_function` +#### `from_function` ```python from_function(cls, fn: Callable[..., Any], name: str | None = None, title: str | None = None, description: str | None = None, tags: set[str] | None = None, annotations: ToolAnnotations | None = None, exclude_args: list[str] | None = None, output_schema: dict[str, Any] | None | NotSetT | Literal[False] = NotSet, serializer: Callable[[Any], str] | None = None, enabled: bool | None = None) -> FunctionTool @@ -94,7 +94,7 @@ from_function(cls, fn: Callable[..., Any], name: str | None = None, title: str | Create a Tool from a function. -#### `run` +#### `run` ```python run(self, arguments: dict[str, Any]) -> ToolResult @@ -103,11 +103,11 @@ run(self, arguments: dict[str, Any]) -> ToolResult Run the tool with arguments. -### `ParsedFunction` +### `ParsedFunction` **Methods:** -#### `from_function` +#### `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-tool_manager.mdx b/docs/python-sdk/fastmcp-tools-tool_manager.mdx index f9b6b61f7..3b94ee85e 100644 --- a/docs/python-sdk/fastmcp-tools-tool_manager.mdx +++ b/docs/python-sdk/fastmcp-tools-tool_manager.mdx @@ -7,7 +7,7 @@ sidebarTitle: tool_manager ## Classes -### `ToolManager` +### `ToolManager` Manages FastMCP tools. @@ -15,7 +15,7 @@ Manages FastMCP tools. **Methods:** -#### `mount` +#### `mount` ```python mount(self, server: MountedServer) -> None @@ -24,7 +24,7 @@ mount(self, server: MountedServer) -> None Adds a mounted server as a source for tools. -#### `has_tool` +#### `has_tool` ```python has_tool(self, key: str) -> bool @@ -33,7 +33,7 @@ has_tool(self, key: str) -> bool Check if a tool exists. -#### `get_tool` +#### `get_tool` ```python get_tool(self, key: str) -> Tool @@ -42,7 +42,7 @@ get_tool(self, key: str) -> Tool Get tool by key. -#### `get_tools` +#### `get_tools` ```python get_tools(self) -> dict[str, Tool] @@ -51,7 +51,7 @@ get_tools(self) -> dict[str, Tool] Gets the complete, unfiltered inventory of all tools. -#### `list_tools` +#### `list_tools` ```python list_tools(self) -> list[Tool] @@ -60,7 +60,7 @@ list_tools(self) -> list[Tool] Lists all tools, applying protocol filtering. -#### `add_tool_from_fn` +#### `add_tool_from_fn` ```python add_tool_from_fn(self, fn: Callable[..., Any], name: str | None = None, description: str | None = None, tags: set[str] | None = None, annotations: ToolAnnotations | None = None, serializer: Callable[[Any], str] | None = None, exclude_args: list[str] | None = None) -> Tool @@ -69,7 +69,7 @@ add_tool_from_fn(self, fn: Callable[..., Any], name: str | None = None, descript Add a tool to the server. -#### `add_tool` +#### `add_tool` ```python add_tool(self, tool: Tool) -> Tool @@ -78,7 +78,34 @@ add_tool(self, tool: Tool) -> Tool Register a tool with the server. -#### `remove_tool` +#### `add_tool_transformation` + +```python +add_tool_transformation(self, tool_name: str, transformation: ToolTransformConfig) -> None +``` + +Add a tool transformation. + + +#### `get_tool_transformation` + +```python +get_tool_transformation(self, tool_name: str) -> ToolTransformConfig | None +``` + +Get a tool transformation. + + +#### `remove_tool_transformation` + +```python +remove_tool_transformation(self, tool_name: str) -> None +``` + +Remove a tool transformation. + + +#### `remove_tool` ```python remove_tool(self, key: str) -> None @@ -93,7 +120,7 @@ Remove a tool from the server. - `NotFoundError`: If the tool is not found -#### `call_tool` +#### `call_tool` ```python call_tool(self, key: str, arguments: dict[str, Any]) -> ToolResult diff --git a/docs/python-sdk/fastmcp-tools-tool_transform.mdx b/docs/python-sdk/fastmcp-tools-tool_transform.mdx index f39ece8f4..b2ad153fb 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) -> 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) -> ToolResult @@ -62,9 +62,20 @@ 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` + +```python +apply_transformations_to_tools(tools: dict[str, Tool], transformations: dict[str, ToolTransformConfig]) -> dict[str, Tool] +``` + + +Apply a list of transformations to a list of tools. Tools that do not have any transforamtions +are left unchanged. + + ## Classes -### `ArgTransform` +### `ArgTransform` Configuration for transforming a parent tool's argument. @@ -126,7 +137,24 @@ ArgTransform(name="new_name", description="New desc", default=None, type=int) ``` -### `TransformedTool` +### `ArgTransformConfig` + + +A model for requesting a single argument transform. + + +**Methods:** + +#### `to_arg_transform` + +```python +to_arg_transform(self) -> ArgTransform +``` + +Convert the argument transform to a FastMCP argument transform. + + +### `TransformedTool` A tool that is transformed from another tool. @@ -143,7 +171,7 @@ inherited from the parent tool but can be overridden or disabled. **Methods:** -#### `run` +#### `run` ```python run(self, arguments: dict[str, Any]) -> ToolResult @@ -162,7 +190,7 @@ 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 | None | NotSetT = NotSet, description: str | None | NotSetT = NotSet, tags: set[str] | None = None, transform_fn: Callable[..., Any] | None = None, transform_args: dict[str, ArgTransform] | None = None, annotations: ToolAnnotations | None = None, output_schema: dict[str, Any] | None | Literal[False] = None, serializer: Callable[[Any], str] | None = None, enabled: bool | None = None) -> TransformedTool @@ -239,3 +267,20 @@ async def custom_output(**kwargs) -> ToolResult: ) ``` + +### `ToolTransformConfig` + + +Provides a way to transform a tool. + + +**Methods:** + +#### `apply` + +```python +apply(self, tool: Tool) -> TransformedTool +``` + +Create a TransformedTool from a provided tool and this transformation configuration. + diff --git a/docs/python-sdk/fastmcp-utilities-json_schema.mdx b/docs/python-sdk/fastmcp-utilities-json_schema.mdx index 451b3dbff..b782a2668 100644 --- a/docs/python-sdk/fastmcp-utilities-json_schema.mdx +++ b/docs/python-sdk/fastmcp-utilities-json_schema.mdx @@ -7,7 +7,7 @@ sidebarTitle: json_schema ## Functions -### `compress_schema` +### `compress_schema` ```python compress_schema(schema: dict, prune_params: list[str] | None = None, prune_defs: bool = True, prune_additional_properties: bool = True, prune_titles: bool = False) -> dict diff --git a/docs/python-sdk/fastmcp-utilities-mcp_config.mdx b/docs/python-sdk/fastmcp-utilities-mcp_config.mdx index fe1d6f156..eac19c909 100644 --- a/docs/python-sdk/fastmcp-utilities-mcp_config.mdx +++ b/docs/python-sdk/fastmcp-utilities-mcp_config.mdx @@ -7,44 +7,22 @@ sidebarTitle: mcp_config ## Functions -### `infer_transport_type_from_url` +### `composite_server_from_mcp_config` ```python -infer_transport_type_from_url(url: str | AnyUrl) -> Literal['http', 'sse'] +composite_server_from_mcp_config(config: MCPConfig, name_as_prefix: bool = True) -> FastMCP ``` -Infer the appropriate transport type from the given URL. +A utility function to create a composite server from an MCPConfig. -## Classes - -### `StdioMCPServer` - -**Methods:** - -#### `to_transport` +### `mount_mcp_config_into_server` ```python -to_transport(self) -> StdioTransport +mount_mcp_config_into_server(config: MCPConfig, server: FastMCP, name_as_prefix: bool = True) -> None ``` -### `RemoteMCPServer` -**Methods:** +A utility function to mount the servers from an MCPConfig into a FastMCP server. -#### `to_transport` - -```python -to_transport(self) -> StreamableHttpTransport | SSETransport -``` - -### `MCPConfig` - -**Methods:** - -#### `from_dict` - -```python -from_dict(cls, config: dict[str, Any]) -> MCPConfig -``` diff --git a/docs/python-sdk/fastmcp-utilities-openapi.mdx b/docs/python-sdk/fastmcp-utilities-openapi.mdx index 4cb84f5f4..970ebaaf1 100644 --- a/docs/python-sdk/fastmcp-utilities-openapi.mdx +++ b/docs/python-sdk/fastmcp-utilities-openapi.mdx @@ -7,7 +7,7 @@ sidebarTitle: openapi ## Functions -### `format_array_parameter` +### `format_array_parameter` ```python format_array_parameter(values: list, parameter_name: str, is_query_parameter: bool = False) -> str | list @@ -25,7 +25,7 @@ Format an array parameter according to OpenAPI specifications. - String (comma-separated) or list (for query params with explode=True) -### `format_deep_object_parameter` +### `format_deep_object_parameter` ```python format_deep_object_parameter(param_value: dict, parameter_name: str) -> dict[str, str] @@ -37,8 +37,7 @@ Format a dictionary parameter for deepObject style serialization. According to OpenAPI 3.0 spec, deepObject style with explode=true serializes object properties as separate query parameters with bracket notation. -For example: {"id": "123", "type": "user"} becomes: -param[id]=123¶m[type]=user +For example: `{"id": "123", "type": "user"}` becomes `param[id]=123¶m[type]=user`. **Args:** - `param_value`: Dictionary value to format @@ -48,7 +47,7 @@ param[id]=123¶m[type]=user - Dictionary with bracketed parameter names as keys -### `parse_openapi_to_http_routes` +### `parse_openapi_to_http_routes` ```python parse_openapi_to_http_routes(openapi_dict: dict[str, Any]) -> list[HTTPRoute] @@ -61,7 +60,7 @@ using the openapi-pydantic library. Supports both OpenAPI 3.0.x and 3.1.x versions. -### `clean_schema_for_display` +### `clean_schema_for_display` ```python clean_schema_for_display(schema: JsonSchema | None) -> JsonSchema | None @@ -71,7 +70,7 @@ clean_schema_for_display(schema: JsonSchema | None) -> JsonSchema | None Clean up a schema dictionary for display by removing internal/complex fields. -### `generate_example_from_schema` +### `generate_example_from_schema` ```python generate_example_from_schema(schema: JsonSchema | None) -> Any @@ -82,7 +81,7 @@ Generate a simple example value from a JSON schema dictionary. Very basic implementation focusing on types. -### `format_json_for_description` +### `format_json_for_description` ```python format_json_for_description(data: Any, indent: int = 2) -> str @@ -92,7 +91,7 @@ format_json_for_description(data: Any, indent: int = 2) -> str Formats Python data as a JSON string block for markdown. -### `format_description_with_responses` +### `format_description_with_responses` ```python format_description_with_responses(base_description: str, responses: dict[str, Any], parameters: list[ParameterInfo] | None = None, request_body: RequestBodyInfo | None = None) -> str @@ -115,7 +114,7 @@ including its description, whether it is required, and its content schema. - and the request body. -### `extract_output_schema_from_responses` +### `extract_output_schema_from_responses` ```python extract_output_schema_from_responses(responses: dict[str, ResponseInfo], schema_definitions: dict[str, Any] | None = None) -> dict[str, Any] | None @@ -138,31 +137,31 @@ object type, it wraps it to comply with MCP requirements. ## Classes -### `ParameterInfo` +### `ParameterInfo` Represents a single parameter for an HTTP operation in our IR. -### `RequestBodyInfo` +### `RequestBodyInfo` Represents the request body for an HTTP operation in our IR. -### `ResponseInfo` +### `ResponseInfo` Represents response information in our IR. -### `HTTPRoute` +### `HTTPRoute` Intermediate Representation for a single OpenAPI operation. -### `OpenAPIParser` +### `OpenAPIParser` Unified parser for OpenAPI schemas with generic type parameters to handle both 3.0 and 3.1. @@ -170,7 +169,7 @@ Unified parser for OpenAPI schemas with generic type parameters to handle both 3 **Methods:** -#### `parse` +#### `parse` ```python parse(self) -> list[HTTPRoute] diff --git a/docs/python-sdk/fastmcp-utilities-tests.mdx b/docs/python-sdk/fastmcp-utilities-tests.mdx index f8f1d8fb8..5766b4d02 100644 --- a/docs/python-sdk/fastmcp-utilities-tests.mdx +++ b/docs/python-sdk/fastmcp-utilities-tests.mdx @@ -20,7 +20,7 @@ Temporarily override FastMCP setting values. - `**kwargs`: The settings to override, including nested settings. -### `run_server_in_process` +### `run_server_in_process` ```python run_server_in_process(server_fn: Callable[..., None], *args, **kwargs) -> Generator[str, None, None] @@ -41,7 +41,7 @@ not pickleable, so we need a function that creates and runs one. - The server URL. -### `caplog_for_fastmcp` +### `caplog_for_fastmcp` ```python caplog_for_fastmcp(caplog) diff --git a/docs/python-sdk/fastmcp-utilities-types.mdx b/docs/python-sdk/fastmcp-utilities-types.mdx index 378e0e076..4d08be539 100644 --- a/docs/python-sdk/fastmcp-utilities-types.mdx +++ b/docs/python-sdk/fastmcp-utilities-types.mdx @@ -10,7 +10,7 @@ Common types used across FastMCP. ## Functions -### `get_cached_typeadapter` +### `get_cached_typeadapter` ```python get_cached_typeadapter(cls: T) -> TypeAdapter[T] @@ -23,7 +23,7 @@ However, this isn't feasible for user-generated functions. Instead, we use a cache to minimize the cost of creating them as much as possible. -### `issubclass_safe` +### `issubclass_safe` ```python issubclass_safe(cls: type, base: type) -> bool @@ -33,7 +33,7 @@ issubclass_safe(cls: type, base: type) -> bool Check if cls is a subclass of base, even if cls is a type variable. -### `is_class_member_of_type` +### `is_class_member_of_type` ```python is_class_member_of_type(cls: type, base: type) -> bool @@ -46,7 +46,7 @@ Base can be a type, a UnionType, or an Annotated type. Generic types are not considered members (e.g. T is not a member of list\[T]). -### `find_kwarg_by_type` +### `find_kwarg_by_type` ```python find_kwarg_by_type(fn: Callable, kwarg_type: type) -> str | None @@ -58,7 +58,7 @@ Find the name of the kwarg that is of type kwarg_type. Includes union types that contain the kwarg_type, as well as Annotated types. -### `replace_type` +### `replace_type` ```python replace_type(type_, type_map: dict[type, type]) @@ -75,23 +75,25 @@ This is useful for transforming types when creating tools. - `old_type`: The type to replace. - `new_type`: The type to replace old_type with. -**Examples:** +Examples: +```python +>>> replace_type(list[int | bool], {int: str}) +list[str | bool] ->>> replace_type(list\[int | bool], {int: str}) -list\[str | bool] ->>> replace_type(list\[list\[int]], {int: str}) -list\[list\[str]] +>>> replace_type(list[list[int]], {int: str}) +list[list[str]] +``` ## Classes -### `FastMCPBaseModel` +### `FastMCPBaseModel` Base model for FastMCP models. -### `Image` +### `Image` Helper class for returning images from tools. @@ -99,7 +101,7 @@ Helper class for returning images from tools. **Methods:** -#### `to_image_content` +#### `to_image_content` ```python to_image_content(self, mime_type: str | None = None, annotations: Annotations | None = None) -> mcp.types.ImageContent @@ -108,7 +110,7 @@ to_image_content(self, mime_type: str | None = None, annotations: Annotations | Convert to MCP ImageContent. -### `Audio` +### `Audio` Helper class for returning audio from tools. @@ -116,13 +118,13 @@ Helper class for returning audio from tools. **Methods:** -#### `to_audio_content` +#### `to_audio_content` ```python to_audio_content(self, mime_type: str | None = None, annotations: Annotations | None = None) -> mcp.types.AudioContent ``` -### `File` +### `File` Helper class for returning audio from tools. @@ -130,7 +132,7 @@ Helper class for returning audio from tools. **Methods:** -#### `to_resource_content` +#### `to_resource_content` ```python to_resource_content(self, mime_type: str | None = None, annotations: Annotations | None = None) -> mcp.types.EmbeddedResource diff --git a/src/fastmcp/mcp_config.py b/src/fastmcp/mcp_config.py index e6758e0c7..a534fac38 100644 --- a/src/fastmcp/mcp_config.py +++ b/src/fastmcp/mcp_config.py @@ -7,17 +7,19 @@ The configuration format supports both stdio and remote (HTTP/SSE) transports, w field definitions for server metadata, authentication, and execution parameters. Example configuration: - { - "mcpServers": { - "my-server": { - "command": "npx", - "args": ["-y", "@my/mcp-server"], - "env": {"API_KEY": "secret"}, - "timeout": 30000, - "description": "My MCP server" - } +```json +{ + "mcpServers": { + "my-server": { + "command": "npx", + "args": ["-y", "@my/mcp-server"], + "env": {"API_KEY": "secret"}, + "timeout": 30000, + "description": "My MCP server" } } +} +``` """ from __future__ import annotations diff --git a/src/fastmcp/utilities/openapi.py b/src/fastmcp/utilities/openapi.py index a636e815c..ef7ae874f 100644 --- a/src/fastmcp/utilities/openapi.py +++ b/src/fastmcp/utilities/openapi.py @@ -101,8 +101,7 @@ def format_deep_object_parameter( According to OpenAPI 3.0 spec, deepObject style with explode=true serializes object properties as separate query parameters with bracket notation. - For example: {"id": "123", "type": "user"} becomes: - param[id]=123¶m[type]=user + For example: `{"id": "123", "type": "user"}` becomes `param[id]=123¶m[type]=user`. Args: param_value: Dictionary value to format diff --git a/src/fastmcp/utilities/types.py b/src/fastmcp/utilities/types.py index d309f2af9..815e1faba 100644 --- a/src/fastmcp/utilities/types.py +++ b/src/fastmcp/utilities/types.py @@ -368,12 +368,13 @@ def replace_type(type_, type_map: dict[type, type]): new_type: The type to replace old_type with. Examples: - >>> replace_type(list[int | bool], {int: str}) - list[str | bool] - - >>> replace_type(list[list[int]], {int: str}) - list[list[str]] + ```python + >>> replace_type(list[int | bool], {int: str}) + list[str | bool] + >>> replace_type(list[list[int]], {int: str}) + list[list[str]] + ``` """ if type_ in type_map: return type_map[type_]