diff --git a/docs/style.css b/docs/css/banner.css
similarity index 52%
rename from docs/style.css
rename to docs/css/banner.css
index 1e98ae2ff6a4c4c29f98d5e34d317c8ffeac0392..093d9b797a4d87004cc482c4d82006a499a1b2aa 100644
--- a/docs/style.css
+++ b/docs/css/banner.css
@@ -1,17 +1,3 @@
-/* Code highlighting -- target only inline code elements, not code blocks */
-p code:not(pre code),
-table code:not(pre code),
-li code:not(pre code),
-h1 code:not(pre code),
-h2 code:not(pre code),
-h3 code:not(pre code),
-h4 code:not(pre code),
-h5 code:not(pre code),
-h6 code:not(pre code) {
- color: #f72585 !important;
- background-color: rgba(247, 37, 133, 0.09);
-}
-
/* Banner styling -- improve readability with better contrast */
#banner {
background: #f1f5f9 !important;
@@ -79,41 +65,3 @@ h6 code:not(pre code) {
color: #f1f5f9 !important;
}
-/* Version badge -- display a badge with the current version of the documentation */
-.version-badge {
- display: inline-block;
- align-items: center;
- gap: 0.3em;
- font-size: 1em;
- margin-top: 0px;
- margin-bottom: 0px;
- padding-top: 6px;
- padding-bottom: 6px;
- padding-left: 20px;
- padding-right: 20px;
- font-family: "Inter", sans-serif;
- color: #ff5400;
- background: #fef2f2;
- border: 1px solid rgba(220, 38, 38, 0.3);
- border-radius: 12px;
- box-shadow: none;
- vertical-align: middle;
- position: relative;
- transition: box-shadow 0.2s, transform 0.15s;
-}
-
-.version-badge-container {
- margin: 0;
- padding: 0;
-}
-
-.version-badge:hover {
- box-shadow: 0 2px 8px 0 rgba(160, 132, 252, 0.1);
- transform: translateY(-1px) scale(1.03);
-}
-
-.dark .version-badge {
- color: #f1f5f9;
- background: #334155;
- border: 1px solid #64748b;
-}
diff --git a/docs/css/python-sdk.css b/docs/css/python-sdk.css
new file mode 100644
index 0000000000000000000000000000000000000000..72a64c21a66e4d5385e0740c3bc63acaf7f68dbe
--- /dev/null
+++ b/docs/css/python-sdk.css
@@ -0,0 +1,3 @@
+a:has(svg.icon) {
+ border: none !important;
+}
\ No newline at end of file
diff --git a/docs/css/style.css b/docs/css/style.css
new file mode 100644
index 0000000000000000000000000000000000000000..9716917b1dd3af068bee1605c6adadeba2d4b108
--- /dev/null
+++ b/docs/css/style.css
@@ -0,0 +1,13 @@
+/* Code highlighting -- target only inline code elements, not code blocks */
+p code:not(pre code),
+table code:not(pre code),
+li code:not(pre code),
+h1 code:not(pre code),
+h2 code:not(pre code),
+h3 code:not(pre code),
+h4 code:not(pre code),
+h5 code:not(pre code),
+h6 code:not(pre code) {
+ color: #f72585 !important;
+ background-color: rgba(247, 37, 133, 0.09);
+}
diff --git a/docs/css/version-badge.css b/docs/css/version-badge.css
new file mode 100644
index 0000000000000000000000000000000000000000..daff22177fb089b81937e5526845372cdf5cf013
--- /dev/null
+++ b/docs/css/version-badge.css
@@ -0,0 +1,39 @@
+/* Version badge -- display a badge with the current version of the documentation */
+.version-badge {
+ display: inline-block;
+ align-items: center;
+ gap: 0.3em;
+ font-size: 1em;
+ margin-top: 0px;
+ margin-bottom: 0px;
+ padding-top: 6px;
+ padding-bottom: 6px;
+ padding-left: 20px;
+ padding-right: 20px;
+ font-family: "Inter", sans-serif;
+ color: #ff5400;
+ background: #fef2f2;
+ border: 1px solid rgba(220, 38, 38, 0.3);
+ border-radius: 12px;
+ box-shadow: none;
+ vertical-align: middle;
+ position: relative;
+ transition: box-shadow 0.2s, transform 0.15s;
+}
+
+.version-badge-container {
+ margin: 0;
+ padding: 0;
+}
+
+.version-badge:hover {
+ box-shadow: 0 2px 8px 0 rgba(160, 132, 252, 0.1);
+ transform: translateY(-1px) scale(1.03);
+}
+
+.dark .version-badge {
+ color: #f1f5f9;
+ background: #334155;
+ border: 1px solid #64748b;
+}
+
diff --git a/docs/python-sdk/fastmcp-cli-claude.mdx b/docs/python-sdk/fastmcp-cli-claude.mdx
index 0f8b035fbf088d31fdd484764df79c395f722a67..b56b633383d7c1d0ccb1048d2dfdd6db0f8c3e69 100644
--- a/docs/python-sdk/fastmcp-cli-claude.mdx
+++ b/docs/python-sdk/fastmcp-cli-claude.mdx
@@ -10,7 +10,7 @@ Claude app integration utilities.
## Functions
-### `get_claude_config_path` ↗
+### `get_claude_config_path`
```python
get_claude_config_path() -> Path | None
@@ -20,7 +20,7 @@ get_claude_config_path() -> Path | None
Get the Claude config directory based on platform.
-### `update_claude_config` ↗
+### `update_claude_config`
```python
update_claude_config(file_spec: str, server_name: str) -> bool
diff --git a/docs/python-sdk/fastmcp-cli-cli.mdx b/docs/python-sdk/fastmcp-cli-cli.mdx
index f682abafea46aa7eabe651794f64afc1cf91258d..3ab68da9a4427caa94d56574806ef67f8444725c 100644
--- a/docs/python-sdk/fastmcp-cli-cli.mdx
+++ b/docs/python-sdk/fastmcp-cli-cli.mdx
@@ -10,13 +10,13 @@ FastMCP CLI tools.
## Functions
-### `version` ↗
+### `version`
```python
version(ctx: Context)
```
-### `dev` ↗
+### `dev`
```python
dev(server_spec: str = typer.Argument(..., help='Python file to run, optionally with :object suffix'), with_editable: Annotated[Path | None, typer.Option('--with-editable', '-e', help='Directory containing pyproject.toml to install in editable mode', exists=True, file_okay=False, resolve_path=True)] = None, with_packages: Annotated[list[str], typer.Option('--with', help='Additional packages to install')] = [], inspector_version: Annotated[str | None, typer.Option('--inspector-version', help='Version of the MCP Inspector to use')] = None, ui_port: Annotated[int | None, typer.Option('--ui-port', help='Port for the MCP Inspector UI')] = None, server_port: Annotated[int | None, typer.Option('--server-port', help='Port for the MCP Inspector Proxy server')] = None) -> None
@@ -26,7 +26,7 @@ dev(server_spec: str = typer.Argument(..., help='Python file to run, optionally
Run a MCP server with the MCP Inspector.
-### `run` ↗
+### `run`
```python
run(ctx: typer.Context, server_spec: str = typer.Argument(..., help='Python file, object specification (file:obj), or URL'), transport: Annotated[str | None, typer.Option('--transport', '-t', help='Transport protocol to use (stdio, http, or sse)')] = None, host: Annotated[str | None, typer.Option('--host', help='Host to bind to when using http transport (default: 127.0.0.1)')] = None, port: Annotated[int | None, typer.Option('--port', '-p', help='Port to bind to when using http transport (default: 8000)')] = None, log_level: Annotated[str | None, typer.Option('--log-level', '-l', help='Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)')] = None) -> None
@@ -51,7 +51,7 @@ Server arguments can be passed after -- :
fastmcp run server.py -- --config config.json --debug
-### `install` ↗
+### `install`
```python
install(server_spec: str = typer.Argument(..., help='Python file to run, optionally with :object suffix'), server_name: Annotated[str | None, typer.Option('--name', '-n', help="Custom name for the server (defaults to server's name attribute or file name)")] = None, with_editable: Annotated[Path | None, typer.Option('--with-editable', '-e', help='Directory containing pyproject.toml to install in editable mode', exists=True, file_okay=False, resolve_path=True)] = None, with_packages: Annotated[list[str], typer.Option('--with', help='Additional packages to install')] = [], env_vars: Annotated[list[str], typer.Option('--env-var', '-v', help='Environment variables in KEY=VALUE format')] = [], env_file: Annotated[Path | None, typer.Option('--env-file', '-f', help='Load environment variables from a .env file', exists=True, file_okay=True, dir_okay=False, resolve_path=True)] = None) -> None
@@ -64,7 +64,7 @@ Environment variables are preserved once added and only updated if new values
are explicitly provided.
-### `inspect` ↗
+### `inspect`
```python
inspect(server_spec: str = typer.Argument(..., help='Python file to inspect, optionally with :object suffix'), output: Annotated[Path, typer.Option('--output', '-o', help='Output file path for the JSON report (default: server-info.json)')] = Path('server-info.json')) -> None
diff --git a/docs/python-sdk/fastmcp-cli-run.mdx b/docs/python-sdk/fastmcp-cli-run.mdx
index 6c2c90686916167dcd6edc5967c22e7e797ef10d..78adc9056a069cc3b989ba05e66a0d70f863ccf5 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.
## 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,7 @@ Import a MCP server from a file.
- The server object
-### `create_client_server` ↗
+### `create_client_server`
```python
create_client_server(url: str) -> Any
@@ -69,7 +69,7 @@ Create a FastMCP server from a client URL.
- A FastMCP server instance
-### `import_server_with_args` ↗
+### `import_server_with_args`
```python
import_server_with_args(file: Path, server_object: str | None = None, server_args: list[str] | None = None) -> Any
@@ -87,7 +87,7 @@ Import a server with optional command line arguments.
- The imported server object
-### `run_command` ↗
+### `run_command`
```python
run_command(server_spec: str, transport: str | None = None, host: str | None = None, port: int | None = None, log_level: str | None = None, server_args: list[str] | None = None) -> None
diff --git a/docs/python-sdk/fastmcp-client-auth-bearer.mdx b/docs/python-sdk/fastmcp-client-auth-bearer.mdx
index d8a1c2df5194a763b4481e40f448e8619b2c7d50..c83e354b54fce14a7db1ab3cd854a88682cd574a 100644
--- a/docs/python-sdk/fastmcp-client-auth-bearer.mdx
+++ b/docs/python-sdk/fastmcp-client-auth-bearer.mdx
@@ -7,11 +7,11 @@ sidebarTitle: bearer
## Classes
-### `BearerAuth` ↗
+### `BearerAuth`
**Methods:**
-#### `auth_flow` ↗
+#### `auth_flow`
```python
auth_flow(self, request)
diff --git a/docs/python-sdk/fastmcp-client-auth-oauth.mdx b/docs/python-sdk/fastmcp-client-auth-oauth.mdx
index c1973ff59c3be94c100959f0635969bb66219b2d..19ad489e995c66d3d03df993dcad54771cdd9831 100644
--- a/docs/python-sdk/fastmcp-client-auth-oauth.mdx
+++ b/docs/python-sdk/fastmcp-client-auth-oauth.mdx
@@ -7,13 +7,13 @@ sidebarTitle: oauth
## Functions
-### `default_cache_dir` ↗
+### `default_cache_dir`
```python
default_cache_dir() -> Path
```
-### `OAuth` ↗
+### `OAuth`
```python
OAuth(mcp_url: str, scopes: str | list[str] | None = None, client_name: str = 'FastMCP Client', token_storage_cache_dir: Path | None = None, additional_client_metadata: dict[str, Any] | None = None) -> _MCPOAuthClientProvider
@@ -38,7 +38,7 @@ httpx.AsyncClient (or appropriate FastMCP client/transport instance)
## Classes
-### `ServerOAuthMetadata` ↗
+### `ServerOAuthMetadata`
More flexible OAuth metadata model that accepts broader ranges of values
@@ -48,13 +48,13 @@ This handles real-world OAuth servers like PayPal that may support
additional methods not in the MCP specification.
-### `OAuthClientProvider` ↗
+### `OAuthClientProvider`
OAuth client provider with more flexible OAuth metadata discovery.
-### `FileTokenStorage` ↗
+### `FileTokenStorage`
File-based token storage implementation for OAuth credentials and tokens.
@@ -65,7 +65,7 @@ Each instance is tied to a specific server URL for proper token isolation.
**Methods:**
-#### `get_base_url` ↗
+#### `get_base_url`
```python
get_base_url(url: str) -> str
@@ -74,7 +74,7 @@ get_base_url(url: str) -> str
Extract the base URL (scheme + host) from a URL.
-#### `get_cache_key` ↗
+#### `get_cache_key`
```python
get_cache_key(self) -> str
@@ -83,7 +83,7 @@ get_cache_key(self) -> str
Generate a safe filesystem key from the server's base URL.
-#### `clear` ↗
+#### `clear`
```python
clear(self) -> None
@@ -92,7 +92,7 @@ clear(self) -> None
Clear all cached data for this server.
-#### `clear_all` ↗
+#### `clear_all`
```python
clear_all(cls, cache_dir: Path | None = None) -> None
diff --git a/docs/python-sdk/fastmcp-client-client.mdx b/docs/python-sdk/fastmcp-client-client.mdx
index 09c17155c6172760985ea4c0297a40980312d9ac..3b99527e77b861f18e0c91c82fe465da199c486c 100644
--- a/docs/python-sdk/fastmcp-client-client.mdx
+++ b/docs/python-sdk/fastmcp-client-client.mdx
@@ -7,7 +7,7 @@ sidebarTitle: client
## Classes
-### `Client` ↗
+### `Client`
MCP client that delegates connection management to a Transport instance.
@@ -48,7 +48,7 @@ async with client:
**Methods:**
-#### `session` ↗
+#### `session`
```python
session(self) -> ClientSession
@@ -57,7 +57,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
@@ -66,7 +66,7 @@ initialize_result(self) -> mcp.types.InitializeResult
Get the result of the initialization request.
-#### `set_roots` ↗
+#### `set_roots`
```python
set_roots(self, roots: RootsList | RootsHandler) -> None
@@ -75,7 +75,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) -> None
@@ -84,7 +84,7 @@ set_sampling_callback(self, sampling_callback: SamplingHandler) -> None
Set the sampling callback for the client.
-#### `is_connected` ↗
+#### `is_connected`
```python
is_connected(self) -> bool
diff --git a/docs/python-sdk/fastmcp-client-logging.mdx b/docs/python-sdk/fastmcp-client-logging.mdx
index 07bf911dd8de3f587aa23df0481b37694ca6fc02..83da895c3b70914a24675b92f8a715c3e9b0b9c4 100644
--- a/docs/python-sdk/fastmcp-client-logging.mdx
+++ b/docs/python-sdk/fastmcp-client-logging.mdx
@@ -7,7 +7,7 @@ sidebarTitle: logging
## Functions
-### `create_log_callback` ↗
+### `create_log_callback`
```python
create_log_callback(handler: LogHandler | None = None) -> LoggingFnT
diff --git a/docs/python-sdk/fastmcp-client-oauth_callback.mdx b/docs/python-sdk/fastmcp-client-oauth_callback.mdx
index 8ae599c7d5b8807a47fc037306ac834886d4ccc5..e251c5ac4603ec9d4523f48a21a5e06f4bfc756f 100644
--- a/docs/python-sdk/fastmcp-client-oauth_callback.mdx
+++ b/docs/python-sdk/fastmcp-client-oauth_callback.mdx
@@ -15,7 +15,7 @@ and display styled responses to users.
## Functions
-### `create_callback_html` ↗
+### `create_callback_html`
```python
create_callback_html(message: str, is_success: bool = True, title: str = 'FastMCP OAuth', server_url: str | None = None) -> str
@@ -25,7 +25,7 @@ create_callback_html(message: str, is_success: bool = True, title: str = 'FastMC
Create a styled HTML response for OAuth callbacks.
-### `create_oauth_callback_server` ↗
+### `create_oauth_callback_server`
```python
create_oauth_callback_server(port: int, callback_path: str = '/callback', server_url: str | None = None, response_future: asyncio.Future | None = None) -> Server
@@ -46,17 +46,17 @@ Create an OAuth callback server.
## Classes
-### `CallbackResponse` ↗
+### `CallbackResponse`
**Methods:**
-#### `from_dict` ↗
+#### `from_dict`
```python
from_dict(cls, data: dict[str, str]) -> CallbackResponse
```
-#### `to_dict` ↗
+#### `to_dict`
```python
to_dict(self) -> dict[str, str]
diff --git a/docs/python-sdk/fastmcp-client-roots.mdx b/docs/python-sdk/fastmcp-client-roots.mdx
index b61c561a92e424a8ada70e70b270241e8127028b..a081bc2fa4245e5607c944a4e46123f4343757aa 100644
--- a/docs/python-sdk/fastmcp-client-roots.mdx
+++ b/docs/python-sdk/fastmcp-client-roots.mdx
@@ -7,13 +7,13 @@ sidebarTitle: roots
## Functions
-### `convert_roots_list` ↗
+### `convert_roots_list`
```python
convert_roots_list(roots: RootsList) -> list[mcp.types.Root]
```
-### `create_roots_callback` ↗
+### `create_roots_callback`
```python
create_roots_callback(handler: RootsList | RootsHandler) -> ListRootsFnT
diff --git a/docs/python-sdk/fastmcp-client-sampling.mdx b/docs/python-sdk/fastmcp-client-sampling.mdx
index dc2912fb9e679131d8089d4023db09e50cf41ac1..53d3893de278135d0baa25661bd1023b8268a1be 100644
--- a/docs/python-sdk/fastmcp-client-sampling.mdx
+++ b/docs/python-sdk/fastmcp-client-sampling.mdx
@@ -7,7 +7,7 @@ sidebarTitle: sampling
## Functions
-### `create_sampling_callback` ↗
+### `create_sampling_callback`
```python
create_sampling_callback(sampling_handler: SamplingHandler) -> SamplingFnT
diff --git a/docs/python-sdk/fastmcp-client-transports.mdx b/docs/python-sdk/fastmcp-client-transports.mdx
index f83a119fe00eaa6b39594e543eb65371ff8580eb..adbab20ee7ec0559fc8f44af5106b82ea18464ef 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.
@@ -72,25 +72,25 @@ A Transport is responsible for establishing and managing connections
to an MCP server, and providing a ClientSession within an async context.
-### `WSTransport` ↗
+### `WSTransport`
Transport implementation that connects to an MCP server via WebSockets.
-### `SSETransport` ↗
+### `SSETransport`
Transport implementation that connects to an MCP server via Server-Sent Events.
-### `StreamableHttpTransport` ↗
+### `StreamableHttpTransport`
Transport implementation that connects to an MCP server via Streamable HTTP Requests.
-### `StdioTransport` ↗
+### `StdioTransport`
Base transport for connecting to an MCP server via subprocess with stdio.
@@ -99,37 +99,37 @@ This is a base class that can be subclassed for specific command-based
transports like Python, Node, Uvx, etc.
-### `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.
-### `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.
@@ -140,7 +140,7 @@ servers from the low-level MCP SDK. This is particularly useful for unit
tests or scenarios where client and server run in the same runtime.
-### `MCPConfigTransport` ↗
+### `MCPConfigTransport`
Transport for connecting to one or more MCP servers defined in an MCPConfig.
diff --git a/docs/python-sdk/fastmcp-exceptions.mdx b/docs/python-sdk/fastmcp-exceptions.mdx
index b7930d0acdb547a12fc48234e344e01be56f43b7..6b54286b557e33a64326004b0e224fd4bda435fa 100644
--- a/docs/python-sdk/fastmcp-exceptions.mdx
+++ b/docs/python-sdk/fastmcp-exceptions.mdx
@@ -10,55 +10,55 @@ Custom exceptions for FastMCP.
## Classes
-### `FastMCPError` ↗
+### `FastMCPError`
Base error for FastMCP.
-### `ValidationError` ↗
+### `ValidationError`
Error in validating parameters or return values.
-### `ResourceError` ↗
+### `ResourceError`
Error in resource operations.
-### `ToolError` ↗
+### `ToolError`
Error in tool operations.
-### `PromptError` ↗
+### `PromptError`
Error in prompt operations.
-### `InvalidSignature` ↗
+### `InvalidSignature`
Invalid signature for use with FastMCP.
-### `ClientError` ↗
+### `ClientError`
Error in client operations.
-### `NotFoundError` ↗
+### `NotFoundError`
Object not found.
-### `DisabledError` ↗
+### `DisabledError`
Object is disabled.
diff --git a/docs/python-sdk/fastmcp-prompts-prompt.mdx b/docs/python-sdk/fastmcp-prompts-prompt.mdx
index 90e83def37ab26b9ff7455cd130573422905923c..726962933d8b5c81263bc9d1c11c45b570044cb8 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.
## Functions
-### `Message` ↗
+### `Message`
```python
Message(content: str | MCPContent, role: Role | None = None, **kwargs: Any) -> PromptMessage
@@ -22,13 +22,13 @@ A user-friendly constructor for PromptMessage.
## Classes
-### `PromptArgument` ↗
+### `PromptArgument`
An argument that can be passed to a prompt.
-### `Prompt` ↗
+### `Prompt`
A prompt template that can be rendered with parameters.
@@ -36,7 +36,7 @@ A prompt template that can be rendered with parameters.
**Methods:**
-#### `to_mcp_prompt` ↗
+#### `to_mcp_prompt`
```python
to_mcp_prompt(self, **overrides: Any) -> MCPPrompt
@@ -45,7 +45,7 @@ to_mcp_prompt(self, **overrides: Any) -> MCPPrompt
Convert the prompt to an MCP prompt.
-#### `from_function` ↗
+#### `from_function`
```python
from_function(fn: Callable[..., PromptResult | Awaitable[PromptResult]], name: str | None = None, description: str | None = None, tags: set[str] | None = None, enabled: bool | None = None) -> FunctionPrompt
@@ -60,7 +60,7 @@ The function can return:
- A sequence of any of the above
-### `FunctionPrompt` ↗
+### `FunctionPrompt`
A prompt that is a function.
@@ -68,7 +68,7 @@ A prompt that is a function.
**Methods:**
-#### `from_function` ↗
+#### `from_function`
```python
from_function(cls, fn: Callable[..., PromptResult | Awaitable[PromptResult]], name: str | None = None, description: str | None = None, tags: set[str] | None = None, enabled: bool | None = None) -> FunctionPrompt
diff --git a/docs/python-sdk/fastmcp-prompts-prompt_manager.mdx b/docs/python-sdk/fastmcp-prompts-prompt_manager.mdx
index e4f9dc68ec084ef3b4af76caeb446b6b32fe10cc..2ba84f742c5069314ef10ad83f2dbc6e25c54cdb 100644
--- a/docs/python-sdk/fastmcp-prompts-prompt_manager.mdx
+++ b/docs/python-sdk/fastmcp-prompts-prompt_manager.mdx
@@ -7,7 +7,7 @@ sidebarTitle: prompt_manager
## Classes
-### `PromptManager` ↗
+### `PromptManager`
Manages FastMCP prompts.
@@ -15,7 +15,7 @@ Manages FastMCP prompts.
**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 prompts.
-#### `add_prompt_from_fn` ↗
+#### `add_prompt_from_fn`
```python
add_prompt_from_fn(self, fn: Callable[..., PromptResult | Awaitable[PromptResult]], name: str | None = None, description: str | None = None, tags: set[str] | None = None) -> FunctionPrompt
@@ -33,7 +33,7 @@ add_prompt_from_fn(self, fn: Callable[..., PromptResult | Awaitable[PromptResult
Create a prompt from a function.
-#### `add_prompt` ↗
+#### `add_prompt`
```python
add_prompt(self, prompt: Prompt) -> Prompt
diff --git a/docs/python-sdk/fastmcp-resources-resource.mdx b/docs/python-sdk/fastmcp-resources-resource.mdx
index e649ff1ec80e8db73f110c106bde86e04e05dba6..ac6c401399f85a5aa4235a547a02d5fb8f32e683 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
-### `Resource` ↗
+### `Resource`
Base class for all resources.
@@ -18,13 +18,13 @@ Base class for all resources.
**Methods:**
-#### `from_function` ↗
+#### `from_function`
```python
from_function(fn: Callable[[], Any], uri: str | AnyUrl, name: str | None = None, description: str | None = None, mime_type: str | None = None, tags: set[str] | None = None, enabled: bool | None = None) -> FunctionResource
```
-#### `set_default_mime_type` ↗
+#### `set_default_mime_type`
```python
set_default_mime_type(cls, mime_type: str | None) -> str
@@ -33,7 +33,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
@@ -42,7 +42,7 @@ set_default_name(self) -> Self
Set default name from URI if not provided.
-#### `to_mcp_resource` ↗
+#### `to_mcp_resource`
```python
to_mcp_resource(self, **overrides: Any) -> MCPResource
@@ -51,7 +51,7 @@ to_mcp_resource(self, **overrides: Any) -> MCPResource
Convert the resource to an MCPResource.
-#### `key` ↗
+#### `key`
```python
key(self) -> str
@@ -63,7 +63,7 @@ keys having a certain value, as the same tool loaded from different
hierarchies of servers may have different keys.
-### `FunctionResource` ↗
+### `FunctionResource`
A resource that defers data loading by wrapping a function.
@@ -80,7 +80,7 @@ The function can return:
**Methods:**
-#### `from_function` ↗
+#### `from_function`
```python
from_function(cls, fn: Callable[[], Any], uri: str | AnyUrl, name: str | None = None, description: str | None = None, mime_type: str | None = None, tags: set[str] | None = None, enabled: bool | None = None) -> FunctionResource
diff --git a/docs/python-sdk/fastmcp-resources-resource_manager.mdx b/docs/python-sdk/fastmcp-resources-resource_manager.mdx
index da08b45a726b5d100df4018921cdf3bab2947ad8..f3b4fa65f982018bb9ac711d3abeb14e33f36f30 100644
--- a/docs/python-sdk/fastmcp-resources-resource_manager.mdx
+++ b/docs/python-sdk/fastmcp-resources-resource_manager.mdx
@@ -10,7 +10,7 @@ Resource manager functionality.
## Classes
-### `ResourceManager` ↗
+### `ResourceManager`
Manages FastMCP resources.
@@ -18,7 +18,7 @@ Manages FastMCP resources.
**Methods:**
-#### `mount` ↗
+#### `mount`
```python
mount(self, server: MountedServer) -> None
@@ -27,7 +27,7 @@ mount(self, server: MountedServer) -> None
Adds a mounted server as a source for resources and templates.
-#### `add_resource_or_template_from_fn` ↗
+#### `add_resource_or_template_from_fn`
```python
add_resource_or_template_from_fn(self, fn: Callable[..., Any], uri: str, name: str | None = None, description: str | None = None, mime_type: str | None = None, tags: set[str] | None = None) -> Resource | ResourceTemplate
@@ -48,7 +48,7 @@ Add a resource or template to the manager from a function.
- returns the existing resource or template.
-#### `add_resource_from_fn` ↗
+#### `add_resource_from_fn`
```python
add_resource_from_fn(self, fn: Callable[..., Any], uri: str, name: str | None = None, description: str | None = None, mime_type: str | None = None, tags: set[str] | None = None) -> Resource
@@ -69,7 +69,7 @@ Add a resource to the manager from a function.
- returns the existing resource.
-#### `add_resource` ↗
+#### `add_resource`
```python
add_resource(self, resource: Resource) -> Resource
@@ -83,7 +83,7 @@ will be used as the storage key. To overwrite it, call
Resource.with_key() before calling this method.
-#### `add_template_from_fn` ↗
+#### `add_template_from_fn`
```python
add_template_from_fn(self, fn: Callable[..., Any], uri_template: str, name: str | None = None, description: str | None = None, mime_type: str | None = None, tags: set[str] | None = None) -> ResourceTemplate
@@ -92,7 +92,7 @@ add_template_from_fn(self, fn: Callable[..., Any], uri_template: str, name: str
Create a template from a function.
-#### `add_template` ↗
+#### `add_template`
```python
add_template(self, template: ResourceTemplate) -> ResourceTemplate
diff --git a/docs/python-sdk/fastmcp-resources-template.mdx b/docs/python-sdk/fastmcp-resources-template.mdx
index 1f21f3d3a0994c9e55f26e6788aebc5f03ed4d3e..99f8218e13cbbfe12dd75ef1b80e22e2e952b4ae 100644
--- a/docs/python-sdk/fastmcp-resources-template.mdx
+++ b/docs/python-sdk/fastmcp-resources-template.mdx
@@ -10,13 +10,13 @@ Resource template functionality.
## Functions
-### `build_regex` ↗
+### `build_regex`
```python
build_regex(template: str) -> re.Pattern
```
-### `match_uri_template` ↗
+### `match_uri_template`
```python
match_uri_template(uri: str, uri_template: str) -> dict[str, str] | None
@@ -24,7 +24,7 @@ match_uri_template(uri: str, uri_template: str) -> dict[str, str] | None
## Classes
-### `ResourceTemplate` ↗
+### `ResourceTemplate`
A template for dynamically creating resources.
@@ -32,13 +32,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, description: str | None = None, mime_type: str | None = None, tags: set[str] | None = None, enabled: bool | None = None) -> FunctionResourceTemplate
```
-#### `set_default_mime_type` ↗
+#### `set_default_mime_type`
```python
set_default_mime_type(cls, mime_type: str | None) -> str
@@ -47,7 +47,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
@@ -56,7 +56,7 @@ matches(self, uri: str) -> dict[str, Any] | None
Check if URI matches template and extract parameters.
-#### `to_mcp_template` ↗
+#### `to_mcp_template`
```python
to_mcp_template(self, **overrides: Any) -> MCPResourceTemplate
@@ -65,7 +65,7 @@ to_mcp_template(self, **overrides: Any) -> MCPResourceTemplate
Convert the resource template to an MCPResourceTemplate.
-#### `from_mcp_template` ↗
+#### `from_mcp_template`
```python
from_mcp_template(cls, mcp_template: MCPResourceTemplate) -> ResourceTemplate
@@ -74,7 +74,7 @@ from_mcp_template(cls, mcp_template: MCPResourceTemplate) -> ResourceTemplate
Creates a FastMCP ResourceTemplate from a raw MCP ResourceTemplate object.
-#### `key` ↗
+#### `key`
```python
key(self) -> str
@@ -86,7 +86,7 @@ keys having a certain value, as the same tool loaded from different
hierarchies of servers may have different keys.
-### `FunctionResourceTemplate` ↗
+### `FunctionResourceTemplate`
A template for dynamically creating resources.
@@ -94,7 +94,7 @@ A template for dynamically creating resources.
**Methods:**
-#### `from_function` ↗
+#### `from_function`
```python
from_function(cls, fn: Callable[..., Any], uri_template: str, name: str | None = None, description: str | None = None, mime_type: str | None = None, tags: set[str] | None = None, enabled: bool | None = None) -> FunctionResourceTemplate
diff --git a/docs/python-sdk/fastmcp-resources-types.mdx b/docs/python-sdk/fastmcp-resources-types.mdx
index 67caa4744eafe371d6e9b733b328c02bd7f73bee..7fa595b8e0389ef9c1ee7b612d3de12ba66732eb 100644
--- a/docs/python-sdk/fastmcp-resources-types.mdx
+++ b/docs/python-sdk/fastmcp-resources-types.mdx
@@ -10,19 +10,19 @@ Concrete resource implementations.
## Classes
-### `TextResource` ↗
+### `TextResource`
A resource that reads from a string.
-### `BinaryResource` ↗
+### `BinaryResource`
A resource that reads from bytes.
-### `FileResource` ↗
+### `FileResource`
A resource that reads from a file.
@@ -32,7 +32,7 @@ Set is_binary=True to read file as binary data instead of text.
**Methods:**
-#### `validate_absolute_path` ↗
+#### `validate_absolute_path`
```python
validate_absolute_path(cls, path: Path) -> Path
@@ -41,7 +41,7 @@ validate_absolute_path(cls, path: Path) -> Path
Ensure path is absolute.
-#### `set_binary_from_mime_type` ↗
+#### `set_binary_from_mime_type`
```python
set_binary_from_mime_type(cls, is_binary: bool, info: ValidationInfo) -> bool
@@ -50,13 +50,13 @@ set_binary_from_mime_type(cls, is_binary: bool, info: ValidationInfo) -> bool
Set is_binary based on mime_type if not explicitly set.
-### `HttpResource` ↗
+### `HttpResource`
A resource that reads from an HTTP endpoint.
-### `DirectoryResource` ↗
+### `DirectoryResource`
A resource that lists files in a directory.
@@ -64,7 +64,7 @@ A resource that lists files in a directory.
**Methods:**
-#### `validate_absolute_path` ↗
+#### `validate_absolute_path`
```python
validate_absolute_path(cls, path: Path) -> Path
@@ -73,7 +73,7 @@ validate_absolute_path(cls, path: Path) -> Path
Ensure path is absolute.
-#### `list_files` ↗
+#### `list_files`
```python
list_files(self) -> list[Path]
diff --git a/docs/python-sdk/fastmcp-server-auth-auth.mdx b/docs/python-sdk/fastmcp-server-auth-auth.mdx
index 7401e82fb9e030b02d745cfec7279e916330c76a..5fd5cce45275ad692b160456b2ad65a8934c907c 100644
--- a/docs/python-sdk/fastmcp-server-auth-auth.mdx
+++ b/docs/python-sdk/fastmcp-server-auth-auth.mdx
@@ -7,4 +7,4 @@ sidebarTitle: auth
## Classes
-### `OAuthProvider` ↗
+### `OAuthProvider`
diff --git a/docs/python-sdk/fastmcp-server-auth-providers-bearer.mdx b/docs/python-sdk/fastmcp-server-auth-providers-bearer.mdx
index 666b904052af19d2d5281f6ec56120c594e22b56..f6a6285be7e7ab70caeba95434e92386580138f8 100644
--- a/docs/python-sdk/fastmcp-server-auth-providers-bearer.mdx
+++ b/docs/python-sdk/fastmcp-server-auth-providers-bearer.mdx
@@ -7,23 +7,23 @@ sidebarTitle: bearer
## Classes
-### `JWKData` ↗
+### `JWKData`
JSON Web Key data structure.
-### `JWKSData` ↗
+### `JWKSData`
JSON Web Key Set data structure.
-### `RSAKeyPair` ↗
+### `RSAKeyPair`
**Methods:**
-#### `generate` ↗
+#### `generate`
```python
generate(cls) -> 'RSAKeyPair'
@@ -35,7 +35,7 @@ Generate an RSA key pair for testing.
- (private_key_pem, public_key_pem)
-#### `create_token` ↗
+#### `create_token`
```python
create_token(self, subject: str = 'fastmcp-user', issuer: str = 'https://fastmcp.example.com', audience: str | list[str] | None = None, scopes: list[str] | None = None, expires_in_seconds: int = 3600, additional_claims: dict[str, Any] | None = None, kid: str | None = None) -> str
@@ -57,7 +57,7 @@ Generate a test JWT token for testing purposes.
- Signed JWT token string
-### `BearerAuthProvider` ↗
+### `BearerAuthProvider`
Simple JWT Bearer Token validator for hosted MCP servers.
diff --git a/docs/python-sdk/fastmcp-server-auth-providers-bearer_env.mdx b/docs/python-sdk/fastmcp-server-auth-providers-bearer_env.mdx
index 9acb518dea3dc012655b372aac19e9cc75b3433e..e1984efb66172c2174e5a5096ef9974174556c9c 100644
--- a/docs/python-sdk/fastmcp-server-auth-providers-bearer_env.mdx
+++ b/docs/python-sdk/fastmcp-server-auth-providers-bearer_env.mdx
@@ -7,13 +7,13 @@ sidebarTitle: bearer_env
## Classes
-### `EnvBearerAuthProviderSettings` ↗
+### `EnvBearerAuthProviderSettings`
Settings for the BearerAuthProvider.
-### `EnvBearerAuthProvider` ↗
+### `EnvBearerAuthProvider`
A BearerAuthProvider that loads settings from environment variables. Any
diff --git a/docs/python-sdk/fastmcp-server-auth-providers-in_memory.mdx b/docs/python-sdk/fastmcp-server-auth-providers-in_memory.mdx
index 2f8b21b6106f484af4bf0a30d3b042ecd1a21a8b..c11f3b87e009c42bc61836adcfd82d568c4d8f9f 100644
--- a/docs/python-sdk/fastmcp-server-auth-providers-in_memory.mdx
+++ b/docs/python-sdk/fastmcp-server-auth-providers-in_memory.mdx
@@ -7,7 +7,7 @@ sidebarTitle: in_memory
## Classes
-### `InMemoryOAuthProvider` ↗
+### `InMemoryOAuthProvider`
An in-memory OAuth provider for testing purposes.
diff --git a/docs/python-sdk/fastmcp-server-context.mdx b/docs/python-sdk/fastmcp-server-context.mdx
index 005b4f7c73ed1cfd558fe4c1196ae9e5d79c0aa2..4cc497740309e15b9cf786f8283207dcf7b5afa6 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.
@@ -53,7 +53,7 @@ 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 +64,7 @@ Access to the underlying request context.
If called outside of a request context, this will raise a ValueError.
-#### `client_id` ↗
+#### `client_id`
```python
client_id(self) -> str | None
@@ -73,7 +73,7 @@ client_id(self) -> str | None
Get the client ID if available.
-#### `request_id` ↗
+#### `request_id`
```python
request_id(self) -> str
@@ -82,7 +82,7 @@ request_id(self) -> str
Get the unique ID for this request.
-#### `session_id` ↗
+#### `session_id`
```python
session_id(self) -> str | None
@@ -99,7 +99,7 @@ the same client session.
- for stdio and in-memory transports which don't use session IDs.
-#### `session` ↗
+#### `session`
```python
session(self)
@@ -108,7 +108,7 @@ session(self)
Access to the underlying session for advanced usage.
-#### `get_http_request` ↗
+#### `get_http_request`
```python
get_http_request(self) -> Request
diff --git a/docs/python-sdk/fastmcp-server-dependencies.mdx b/docs/python-sdk/fastmcp-server-dependencies.mdx
index c082a1b35fa8df249a54764a5d58b4705b98938a..dce54051b5c8a1111edf1e52a15d97ff752fe85e 100644
--- a/docs/python-sdk/fastmcp-server-dependencies.mdx
+++ b/docs/python-sdk/fastmcp-server-dependencies.mdx
@@ -7,19 +7,19 @@ sidebarTitle: dependencies
## Functions
-### `get_context` ↗
+### `get_context`
```python
get_context() -> Context
```
-### `get_http_request` ↗
+### `get_http_request`
```python
get_http_request() -> Request
```
-### `get_http_headers` ↗
+### `get_http_headers`
```python
get_http_headers(include_all: bool = False) -> dict[str, str]
diff --git a/docs/python-sdk/fastmcp-server-http.mdx b/docs/python-sdk/fastmcp-server-http.mdx
index 86624d867adc045350cd4ee9ce8f8bebc904ee1e..75afb765f0bb55519b3f23dfe8c746e205a14d5e 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]
```
-### `setup_auth_middleware_and_routes` ↗
+### `setup_auth_middleware_and_routes`
```python
setup_auth_middleware_and_routes(auth: OAuthProvider) -> tuple[list[Middleware], list[BaseRoute], list[str]]
@@ -29,7 +29,7 @@ Set up authentication middleware and routes if auth is enabled.
- Tuple of (middleware, auth_routes, required_scopes)
-### `create_base_app` ↗
+### `create_base_app`
```python
create_base_app(routes: list[BaseRoute], middleware: list[Middleware], debug: bool = False, lifespan: Callable | None = None) -> StarletteWithLifespan
@@ -48,7 +48,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: OAuthProvider | None = None, debug: bool = False, routes: list[BaseRoute] | None = None, middleware: list[Middleware] | None = None) -> StarletteWithLifespan
@@ -70,7 +70,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, auth: OAuthProvider | None = None, json_response: bool = False, stateless_http: bool = False, debug: bool = False, routes: list[BaseRoute] | None = None, middleware: list[Middleware] | None = None) -> StarletteWithLifespan
@@ -96,17 +96,17 @@ Return an instance of the StreamableHTTP server app.
## Classes
-### `StarletteWithLifespan` ↗
+### `StarletteWithLifespan`
**Methods:**
-#### `lifespan` ↗
+#### `lifespan`
```python
lifespan(self) -> Lifespan
```
-### `RequestContextMiddleware` ↗
+### `RequestContextMiddleware`
Middleware that stores each request in a ContextVar
diff --git a/docs/python-sdk/fastmcp-server-middleware-error_handling.mdx b/docs/python-sdk/fastmcp-server-middleware-error_handling.mdx
index 79836b77216b9df8875e4ffca8aafa6713f9d2f9..735b3c3e5ed592c2b1e3448dc5f8f7cbcf1f4a2e 100644
--- a/docs/python-sdk/fastmcp-server-middleware-error_handling.mdx
+++ b/docs/python-sdk/fastmcp-server-middleware-error_handling.mdx
@@ -10,7 +10,7 @@ Error handling middleware for consistent error responses and tracking.
## Classes
-### `ErrorHandlingMiddleware` ↗
+### `ErrorHandlingMiddleware`
Middleware that provides consistent error handling and logging.
@@ -21,7 +21,7 @@ proper MCP error responses. Also tracks error patterns for monitoring.
**Methods:**
-#### `get_error_stats` ↗
+#### `get_error_stats`
```python
get_error_stats(self) -> dict[str, int]
@@ -30,7 +30,7 @@ get_error_stats(self) -> dict[str, int]
Get error statistics for monitoring.
-### `RetryMiddleware` ↗
+### `RetryMiddleware`
Middleware that implements automatic retry logic for failed requests.
diff --git a/docs/python-sdk/fastmcp-server-middleware-logging.mdx b/docs/python-sdk/fastmcp-server-middleware-logging.mdx
index 74d5599b1c57bae455904cfae487a3fd3a513e85..c45e3096a363d6dda3df0b06dec737cf178b406b 100644
--- a/docs/python-sdk/fastmcp-server-middleware-logging.mdx
+++ b/docs/python-sdk/fastmcp-server-middleware-logging.mdx
@@ -10,7 +10,7 @@ Comprehensive logging middleware for FastMCP servers.
## Classes
-### `LoggingMiddleware` ↗
+### `LoggingMiddleware`
Middleware that provides comprehensive request and response logging.
@@ -19,7 +19,7 @@ Logs all MCP messages with configurable detail levels. Useful for debugging,
monitoring, and understanding server usage patterns.
-### `StructuredLoggingMiddleware` ↗
+### `StructuredLoggingMiddleware`
Middleware that provides structured JSON logging for better log analysis.
diff --git a/docs/python-sdk/fastmcp-server-middleware-middleware.mdx b/docs/python-sdk/fastmcp-server-middleware-middleware.mdx
index 60ffe3c740c4335c77d8a7030b6e5352811ffdac..179864e5db77864a64c3e86f68b90588fdff72d4 100644
--- a/docs/python-sdk/fastmcp-server-middleware-middleware.mdx
+++ b/docs/python-sdk/fastmcp-server-middleware-middleware.mdx
@@ -7,7 +7,7 @@ sidebarTitle: middleware
## Functions
-### `make_middleware_wrapper` ↗
+### `make_middleware_wrapper`
```python
make_middleware_wrapper(middleware: Middleware, call_next: CallNext[T, R]) -> CallNext[T, R]
@@ -21,21 +21,21 @@ passed to other functions that expect a call_next function.
## Classes
-### `CallNext` ↗
+### `CallNext`
-### `CallToolResult` ↗
+### `CallToolResult`
-### `ListToolsResult` ↗
+### `ListToolsResult`
-### `ListResourcesResult` ↗
+### `ListResourcesResult`
-### `ListResourceTemplatesResult` ↗
+### `ListResourceTemplatesResult`
-### `ListPromptsResult` ↗
+### `ListPromptsResult`
-### `ServerResultProtocol` ↗
+### `ServerResultProtocol`
-### `MiddlewareContext` ↗
+### `MiddlewareContext`
Unified context for all middleware operations.
@@ -43,13 +43,13 @@ Unified context for all middleware operations.
**Methods:**
-#### `copy` ↗
+#### `copy`
```python
copy(self, **kwargs: Any) -> MiddlewareContext[T]
```
-### `Middleware` ↗
+### `Middleware`
Base class for FastMCP middleware with dispatching hooks.
diff --git a/docs/python-sdk/fastmcp-server-middleware-rate_limiting.mdx b/docs/python-sdk/fastmcp-server-middleware-rate_limiting.mdx
index 43a90a95b281108535589970bb6014753cff8200..a983ce3f457f545721b7e6cf232adfd400d28c05 100644
--- a/docs/python-sdk/fastmcp-server-middleware-rate_limiting.mdx
+++ b/docs/python-sdk/fastmcp-server-middleware-rate_limiting.mdx
@@ -10,25 +10,25 @@ Rate limiting middleware for protecting FastMCP servers from abuse.
## Classes
-### `RateLimitError` ↗
+### `RateLimitError`
Error raised when rate limit is exceeded.
-### `TokenBucketRateLimiter` ↗
+### `TokenBucketRateLimiter`
Token bucket implementation for rate limiting.
-### `SlidingWindowRateLimiter` ↗
+### `SlidingWindowRateLimiter`
Sliding window rate limiter implementation.
-### `RateLimitingMiddleware` ↗
+### `RateLimitingMiddleware`
Middleware that implements rate limiting to prevent server abuse.
@@ -37,7 +37,7 @@ Uses a token bucket algorithm by default, allowing for burst traffic
while maintaining a sustainable long-term rate.
-### `SlidingWindowRateLimitingMiddleware` ↗
+### `SlidingWindowRateLimitingMiddleware`
Middleware that implements sliding window rate limiting.
diff --git a/docs/python-sdk/fastmcp-server-middleware-timing.mdx b/docs/python-sdk/fastmcp-server-middleware-timing.mdx
index 3d448ffffce5125d862494d05c982d3c885778fc..c2805a3f7e4a6ad0f045300bc9fc7c3f9efbe4c8 100644
--- a/docs/python-sdk/fastmcp-server-middleware-timing.mdx
+++ b/docs/python-sdk/fastmcp-server-middleware-timing.mdx
@@ -10,7 +10,7 @@ Timing middleware for measuring and logging request performance.
## Classes
-### `TimingMiddleware` ↗
+### `TimingMiddleware`
Middleware that logs the execution time of requests.
@@ -19,7 +19,7 @@ Only measures and logs timing for request messages (not notifications).
Provides insights into performance characteristics of your MCP server.
-### `DetailedTimingMiddleware` ↗
+### `DetailedTimingMiddleware`
Enhanced timing middleware with per-operation breakdowns.
diff --git a/docs/python-sdk/fastmcp-server-openapi.mdx b/docs/python-sdk/fastmcp-server-openapi.mdx
index ad670dcd7106108d9a2261f67201581dabcf0993..e57a6fd180f6ed94766a1bc7f9493ff06a1140a1 100644
--- a/docs/python-sdk/fastmcp-server-openapi.mdx
+++ b/docs/python-sdk/fastmcp-server-openapi.mdx
@@ -10,13 +10,13 @@ FastMCP server implementation for OpenAPI integration.
## Classes
-### `MCPType` ↗
+### `MCPType`
Type of FastMCP component to create from a route.
-### `RouteType` ↗
+### `RouteType`
Deprecated: Use MCPType instead.
@@ -24,31 +24,31 @@ Deprecated: Use MCPType instead.
This enum is kept for backward compatibility and will be removed in a future version.
-### `RouteMap` ↗
+### `RouteMap`
Mapping configuration for HTTP routes to FastMCP component types.
-### `OpenAPITool` ↗
+### `OpenAPITool`
Tool implementation for OpenAPI endpoints.
-### `OpenAPIResource` ↗
+### `OpenAPIResource`
Resource implementation for OpenAPI endpoints.
-### `OpenAPIResourceTemplate` ↗
+### `OpenAPIResourceTemplate`
Resource template implementation for OpenAPI endpoints.
-### `FastMCPOpenAPI` ↗
+### `FastMCPOpenAPI`
FastMCP server implementation that creates components from an OpenAPI schema.
diff --git a/docs/python-sdk/fastmcp-server-proxy.mdx b/docs/python-sdk/fastmcp-server-proxy.mdx
index b363b853cfef462c1ab42a589cd44ff0b04d320e..e480b9167e551fd38e857f585040ced45ea852c2 100644
--- a/docs/python-sdk/fastmcp-server-proxy.mdx
+++ b/docs/python-sdk/fastmcp-server-proxy.mdx
@@ -7,25 +7,25 @@ sidebarTitle: proxy
## Classes
-### `ProxyToolManager` ↗
+### `ProxyToolManager`
A ToolManager that sources its tools from a remote client in addition to local and mounted tools.
-### `ProxyResourceManager` ↗
+### `ProxyResourceManager`
A ResourceManager that sources its resources from a remote client in addition to local and mounted resources.
-### `ProxyPromptManager` ↗
+### `ProxyPromptManager`
A PromptManager that sources its prompts from a remote client in addition to local and mounted prompts.
-### `ProxyTool` ↗
+### `ProxyTool`
A Tool that represents and executes a tool on a remote server.
@@ -33,7 +33,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
@@ -42,7 +42,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.
-### `ProxyResource` ↗
+### `ProxyResource`
A Resource that represents and reads a resource from a remote server.
@@ -50,7 +50,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
@@ -59,7 +59,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.
-### `ProxyTemplate` ↗
+### `ProxyTemplate`
A ResourceTemplate that represents and creates resources from a remote server template.
@@ -67,7 +67,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
@@ -76,7 +76,7 @@ from_mcp_template(cls, client: Client, mcp_template: mcp.types.ResourceTemplate)
Factory method to create a ProxyTemplate from a raw MCP template schema.
-### `ProxyPrompt` ↗
+### `ProxyPrompt`
A Prompt that represents and renders a prompt from a remote server.
@@ -84,7 +84,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
@@ -93,7 +93,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.
-### `FastMCPProxy` ↗
+### `FastMCPProxy`
A FastMCP server that acts as a proxy to a remote MCP-compliant server.
diff --git a/docs/python-sdk/fastmcp-server-server.mdx b/docs/python-sdk/fastmcp-server-server.mdx
index c89bb01525fd254dd34f2588b6b8745e55721528..8e6cc2bf50de5ba097cfce6ea209fcc9b67fcccb 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
-### `add_resource_prefix` ↗
+### `add_resource_prefix`
```python
add_resource_prefix(uri: str, prefix: str, prefix_format: Literal['protocol', 'path'] | None = None) -> str
@@ -28,18 +28,27 @@ Add a prefix to a resource URI.
**Examples:**
->>> add_resource_prefix("resource://path/to/resource", "prefix")
-"resource://prefix/path/to/resource" # with new style
->>> add_resource_prefix("resource://path/to/resource", "prefix")
-"prefix+resource://path/to/resource" # with legacy style
->>> add_resource_prefix("resource:///absolute/path", "prefix")
-"resource://prefix//absolute/path" # with new style
+With new style:
+```python
+add_resource_prefix("resource://path/to/resource", "prefix")
+"resource://prefix/path/to/resource"
+```
+With legacy style:
+```python
+add_resource_prefix("resource://path/to/resource", "prefix")
+"prefix+resource://path/to/resource"
+```
+With absolute path:
+```python
+add_resource_prefix("resource:///absolute/path", "prefix")
+"resource://prefix//absolute/path"
+```
**Raises:**
- `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
@@ -58,18 +67,27 @@ Returns:
**Examples:**
->>> remove_resource_prefix("resource://prefix/path/to/resource", "prefix")
-"resource://path/to/resource" # with new style
->>> remove_resource_prefix("prefix+resource://path/to/resource", "prefix")
-"resource://path/to/resource" # with legacy style
->>> remove_resource_prefix("resource://prefix//absolute/path", "prefix")
-"resource:///absolute/path" # with new style
+With new style:
+```python
+remove_resource_prefix("resource://prefix/path/to/resource", "prefix")
+"resource://path/to/resource"
+```
+With legacy style:
+```python
+remove_resource_prefix("prefix+resource://path/to/resource", "prefix")
+"resource://path/to/resource"
+```
+With absolute path:
+```python
+remove_resource_prefix("resource://prefix//absolute/path", "prefix")
+"resource:///absolute/path"
+```
**Raises:**
- `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
@@ -87,12 +105,21 @@ Check if a resource URI has a specific prefix.
**Examples:**
->>> has_resource_prefix("resource://prefix/path/to/resource", "prefix")
-True # with new style
->>> has_resource_prefix("prefix+resource://path/to/resource", "prefix")
-True # with legacy style
->>> has_resource_prefix("resource://other/path/to/resource", "prefix")
+With new style:
+```python
+has_resource_prefix("resource://prefix/path/to/resource", "prefix")
+True
+```
+With legacy style:
+```python
+has_resource_prefix("prefix+resource://path/to/resource", "prefix")
+True
+```
+With other path:
+```python
+has_resource_prefix("resource://other/path/to/resource", "prefix")
False
+```
**Raises:**
- `ValueError`: If the URI doesn't match the expected protocol\://path format
@@ -100,29 +127,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` ↗
+#### `run`
```python
run(self, transport: Transport | None = None, **transport_kwargs: Any) -> None
@@ -134,13 +161,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
```
-#### `custom_route` ↗
+#### `custom_route`
```python
custom_route(self, path: str, methods: list[str], name: str | None = None, include_in_schema: bool = True)
@@ -161,7 +188,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) -> None
@@ -176,7 +203,7 @@ with the Context type annotation. See the @tool decorator for examples.
- `tool`: The Tool instance to register
-#### `remove_tool` ↗
+#### `remove_tool`
```python
remove_tool(self, name: str) -> None
@@ -191,19 +218,19 @@ Remove a tool from the server.
- `NotFoundError`: If the tool is not 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
@@ -227,12 +254,37 @@ This decorator supports multiple calling patterns:
- `name`: Optional name for the tool (keyword-only, alternative to name_or_fn)
- `description`: Optional description of what the tool does
- `tags`: Optional set of tags for categorizing the tool
-- `annotations`: Optional annotations about the tool's behavior (e.g. {"is_async"\: True})
+- `annotations`: Optional annotations about the tool's behavior
- `exclude_args`: Optional list of argument names to exclude from the tool schema
- `enabled`: Optional boolean to enable or disable the tool
+**Examples:**
+
+Register a tool with a custom name:
+```python
+@server.tool
+def my_tool(x: int) -> str:
+ return str(x)
+
+# Register a tool with a custom name
+@server.tool
+def my_tool(x: int) -> str:
+ return str(x)
+
+@server.tool("custom_name")
+def my_tool(x: int) -> str:
+ return str(x)
+
+@server.tool(name="custom_name")
+def my_tool(x: int) -> str:
+ return str(x)
+
+# Direct function call
+server.tool(my_function, name="custom_name")
+```
+
-#### `add_resource` ↗
+#### `add_resource`
```python
add_resource(self, resource: Resource) -> None
@@ -244,7 +296,7 @@ Add a resource to the server.
- `resource`: A Resource instance to add
-#### `add_template` ↗
+#### `add_template`
```python
add_template(self, template: ResourceTemplate) -> None
@@ -256,7 +308,7 @@ Add a resource template to the server.
- `template`: A ResourceTemplate instance to add
-#### `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
@@ -276,7 +328,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]
@@ -305,8 +357,36 @@ has parameters, it will be registered as a template resource.
- `tags`: Optional set of tags for categorizing the resource
- `enabled`: Optional boolean to enable or disable the resource
+**Examples:**
+
+Register a resource with a custom name:
+```python
+@server.resource("resource://my-resource")
+def get_data() -> str:
+ return "Hello, world!"
+
+@server.resource("resource://my-resource")
+async get_data() -> str:
+ data = await fetch_data()
+ return f"Hello, world! {data}"
+
+@server.resource("resource://{city}/weather")
+def get_weather(city: str) -> str:
+ return f"Weather for {city}"
+
+@server.resource("resource://{city}/weather")
+def get_weather_with_context(city: str, ctx: Context) -> str:
+ ctx.info(f"Fetching weather for {city}")
+ return f"Weather for {city}"
+
+@server.resource("resource://{city}/weather")
+async def get_weather(city: str) -> str:
+ data = await fetch_weather(city)
+ return f"Weather for {city}: {data}"
+```
-#### `add_prompt` ↗
+
+#### `add_prompt`
```python
add_prompt(self, prompt: Prompt) -> None
@@ -318,19 +398,19 @@ Add a prompt to the server.
- `prompt`: A Prompt instance to add
-#### `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
@@ -356,9 +436,11 @@ Decorator to register a prompt.
tags: Optional set of tags for categorizing the prompt
enabled: Optional boolean to enable or disable the prompt
- Example:
+ Examples:
+
+ ```python
@server.prompt
- def analyze_table(table_name: str) -> list\[Message]:
+ def analyze_table(table_name: str) -> list[Message]:
schema = read_table_schema(table_name)
return [
{
@@ -369,7 +451,7 @@ Decorator to register a prompt.
]
@server.prompt()
- def analyze_with_context(table_name: str, ctx: Context) -> list\[Message]:
+ def analyze_with_context(table_name: str, ctx: Context) -> list[Message]:
ctx.info(f"Analyzing table {table_name}")
schema = read_table_schema(table_name)
return [
@@ -381,7 +463,7 @@ Decorator to register a prompt.
]
@server.prompt("custom_name")
- def analyze_file(path: str) -> list\[Message]:
+ def analyze_file(path: str) -> list[Message]:
content = await read_file(path)
return [
{
@@ -397,14 +479,15 @@ Decorator to register a prompt.
]
@server.prompt(name="custom_name")
- def another_prompt(data: str) -> list\[Message]:
+ def another_prompt(data: str) -> list[Message]:
return [{"role": "user", "content": data}]
# Direct function call
server.prompt(my_function, name="custom_name")
+ ```
-#### `sse_app` ↗
+#### `sse_app`
```python
sse_app(self, path: str | None = None, message_path: str | None = None, middleware: list[ASGIMiddleware] | None = None) -> StarletteWithLifespan
@@ -418,7 +501,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
@@ -431,7 +514,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
@@ -448,7 +531,7 @@ Create a Starlette app using the specified HTTP transport.
- A Starlette application configured with the specified transport
-#### `mount` ↗
+#### `mount`
```python
mount(self, server: FastMCP[LifespanResultT], prefix: str | None = None, as_proxy: bool | None = None) -> None
@@ -502,7 +585,7 @@ automatically determined based on whether the server has a custom lifespan
- `prompt_separator`: Deprecated. Separator character 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
@@ -511,7 +594,7 @@ from_openapi(cls, openapi_spec: dict[str, Any], client: httpx.AsyncClient, route
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
@@ -520,7 +603,7 @@ from_fastapi(cls, app: Any, name: str | None = None, route_maps: list[RouteMap]
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
@@ -528,13 +611,13 @@ as_proxy(cls, backend: Client[ClientTransportT] | ClientTransport | FastMCP[Any]
Create a FastMCP proxy server for the given backend.
-The ``backend`` argument can be either an existing :class:`~fastmcp.client.Client`
-instance or any value accepted as the ``transport`` argument of
-:class:`~fastmcp.client.Client`. This mirrors the convenience of the
-``Client`` constructor.
+The `backend` argument can be either an existing `fastmcp.client.Client`
+instance or any value accepted as the `transport` argument of
+`fastmcp.client.Client`. This mirrors the convenience of the
+`fastmcp.client.Client` constructor.
-#### `from_client` ↗
+#### `from_client`
```python
from_client(cls, client: Client[ClientTransportT], **settings: Any) -> FastMCPProxy
@@ -543,4 +626,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 9f1319e278115feef321ab5e7047468d75c30c6f..6725277cb13597cb79ab83ad73ca06aa49693e30 100644
--- a/docs/python-sdk/fastmcp-settings.mdx
+++ b/docs/python-sdk/fastmcp-settings.mdx
@@ -7,7 +7,7 @@ sidebarTitle: settings
## Classes
-### `ExtendedEnvSettingsSource` ↗
+### `ExtendedEnvSettingsSource`
A special EnvSettingsSource that allows for multiple env var prefixes to be used.
@@ -17,15 +17,15 @@ Raises a deprecation warning if the old `FASTMCP_SERVER_` prefix is used.
**Methods:**
-#### `get_field_value` ↗
+#### `get_field_value`
```python
get_field_value(self, field: FieldInfo, field_name: str) -> tuple[Any, str, bool]
```
-### `ExtendedSettingsConfigDict` ↗
+### `ExtendedSettingsConfigDict`
-### `Settings` ↗
+### `Settings`
FastMCP settings.
@@ -33,13 +33,13 @@ FastMCP settings.
**Methods:**
-#### `settings_customise_sources` ↗
+#### `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,7 +49,7 @@ This property is for backwards compatibility with FastMCP < 2.8.0,
which accessed fastmcp.settings.settings
-#### `setup_logging` ↗
+#### `setup_logging`
```python
setup_logging(self) -> Self
diff --git a/docs/python-sdk/fastmcp-tools-tool.mdx b/docs/python-sdk/fastmcp-tools-tool.mdx
index 18b4fb6888f0ead5f58eedf49c286b63fef73344..07aef85a947ae4ffa6c3ed7f34100a963b11eb2e 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,7 +15,7 @@ default_serializer(data: Any) -> str
## Classes
-### `Tool` ↗
+### `Tool`
Internal tool registration info.
@@ -23,13 +23,13 @@ Internal tool registration info.
**Methods:**
-#### `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, description: str | None = None, tags: set[str] | None = None, annotations: ToolAnnotations | None = None, exclude_args: list[str] | None = None, serializer: Callable[[Any], str] | None = None, enabled: bool | None = None) -> FunctionTool
@@ -38,17 +38,17 @@ from_function(fn: Callable[..., Any], name: str | None = None, description: str
Create a Tool from a function.
-#### `from_tool` ↗
+#### `from_tool`
```python
from_tool(cls, tool: Tool, transform_fn: Callable[..., Any] | None = None, name: str | None = None, transform_args: dict[str, ArgTransform] | None = None, description: str | None = None, tags: set[str] | None = None, annotations: ToolAnnotations | None = 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, description: str | None = None, tags: set[str] | None = None, annotations: ToolAnnotations | None = None, exclude_args: list[str] | None = None, serializer: Callable[[Any], str] | None = None, enabled: bool | None = None) -> FunctionTool
@@ -57,11 +57,11 @@ from_function(cls, fn: Callable[..., Any], name: str | None = None, description:
Create a Tool from a function.
-### `ParsedFunction` ↗
+### `ParsedFunction`
**Methods:**
-#### `from_function` ↗
+#### `from_function`
```python
from_function(cls, fn: Callable[..., Any], exclude_args: list[str] | None = None, validate: bool = True) -> ParsedFunction
diff --git a/docs/python-sdk/fastmcp-tools-tool_manager.mdx b/docs/python-sdk/fastmcp-tools-tool_manager.mdx
index a44178e0d89b601d118ca57dfa25951f104028c8..75328aca1a361b4b5f9b14394270014817782f1c 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.
-#### `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
@@ -33,7 +33,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
@@ -42,7 +42,7 @@ add_tool(self, tool: Tool) -> Tool
Register a tool with the server.
-#### `remove_tool` ↗
+#### `remove_tool`
```python
remove_tool(self, key: str) -> None
diff --git a/docs/python-sdk/fastmcp-tools-tool_transform.mdx b/docs/python-sdk/fastmcp-tools-tool_transform.mdx
index 66a319619afa5c79149bf85de9ded2eb2b739d4b..6a7ea8ceb93bc428a1233a8b5afffb0078e80320 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
## Classes
-### `ArgTransform` ↗
+### `ArgTransform`
Configuration for transforming a parent tool's argument.
@@ -18,38 +18,58 @@ descriptions, add default values, or hide them from clients while passing consta
**Examples:**
-# Rename argument 'old_name' to 'new_name'
+Rename argument 'old_name' to 'new_name'
+```python
ArgTransform(name="new_name")
+```
-# Change description only
+Change description only
+```python
ArgTransform(description="Updated description")
+```
-# Add a default value (makes argument optional)
+Add a default value (makes argument optional)
+```python
ArgTransform(default=42)
+```
-# Add a default factory (makes argument optional)
+Add a default factory (makes argument optional)
+```python
ArgTransform(default_factory=lambda: time.time())
+```
-# Change the type
+Change the type
+```python
ArgTransform(type=str)
+```
-# Hide the argument entirely from clients
+Hide the argument entirely from clients
+```python
ArgTransform(hide=True)
+```
-# Hide argument but pass a constant value to parent
+Hide argument but pass a constant value to parent
+```python
ArgTransform(hide=True, default="constant_value")
+```
-# Hide argument but pass a factory-generated value to parent
+Hide argument but pass a factory-generated value to parent
+```python
ArgTransform(hide=True, default_factory=lambda: uuid.uuid4().hex)
+```
-# Make an optional parameter required (removes any default)
+Make an optional parameter required (removes any default)
+```python
ArgTransform(required=True)
+```
-# Combine multiple transformations
+Combine multiple transformations
+```python
ArgTransform(name="new_name", description="New desc", default=None, type=int)
+```
-### `TransformedTool` ↗
+### `TransformedTool`
A tool that is transformed from another tool.
@@ -65,7 +85,7 @@ with transformed arguments.
**Methods:**
-#### `from_tool` ↗
+#### `from_tool`
```python
from_tool(cls, tool: Tool, name: str | None = None, description: str | None = None, tags: set[str] | None = None, transform_fn: Callable[..., Any] | None = None, transform_args: dict[str, ArgTransform] | None = None, annotations: ToolAnnotations | None = None, serializer: Callable[[Any], str] | None = None, enabled: bool | None = None) -> TransformedTool
@@ -81,9 +101,9 @@ argument names.
- `name`: New name for the tool. Defaults to parent tool's name.
- `transform_args`: Optional transformations for parent tool arguments.
Only specified arguments are transformed, others pass through unchanged\:
-- str\: Simple rename
-- ArgTransform\: Complex transformation (rename/description/default/drop)
-- None\: Drop the argument
+- Simple rename (str)
+- Complex transformation (rename/description/default/drop) (ArgTransform)
+- Drop the argument (None)
- `description`: New description. Defaults to parent's description.
- `tags`: New tags. Defaults to parent's tags.
- `annotations`: New annotations. Defaults to parent's annotations.
@@ -92,17 +112,28 @@ Only specified arguments are transformed, others pass through unchanged\:
**Returns:**
- TransformedTool with the specified transformations.
-Examples:
-- # Transform specific arguments only
-- Tool.from_tool(parent, transform_args={"old": "new"}) # Others unchanged
-- # Custom function with partial transforms
-- async def custom(x: int, y: int) -> str:
-result = await forward(x=x, y=y)
-return f"Custom: {result}"
-- Tool.from_tool(parent, transform_fn=custom, transform_args={"a": "x", "b": "y"})
-- # Using **kwargs (gets all args, transformed and untransformed)
-- async def flexible(**kwargs) -> str:
-result = await forward(**kwargs)
-return f"Got: {kwargs}"
-- Tool.from_tool(parent, transform_fn=flexible, transform_args={"a": "x"})
+**Examples:**
+
+# Transform specific arguments only
+```python
+Tool.from_tool(parent, transform_args={"old": "new"}) # Others unchanged
+```
+
+# Custom function with partial transforms
+```python
+async def custom(x: int, y: int) -> str:
+ result = await forward(x=x, y=y)
+ return f"Custom: {result}"
+
+Tool.from_tool(parent, transform_fn=custom, transform_args={"a": "x", "b": "y"})
+```
+
+# Using **kwargs (gets all args, transformed and untransformed)
+```python
+async def flexible(**kwargs) -> str:
+ result = await forward(**kwargs)
+ return f"Got: {kwargs}"
+
+Tool.from_tool(parent, transform_fn=flexible, transform_args={"a": "x"})
+```
diff --git a/docs/python-sdk/fastmcp-utilities-cache.mdx b/docs/python-sdk/fastmcp-utilities-cache.mdx
index e81db5b33f5bcb4a75e72cde067473f304c7c1e4..49b0794a246970a6298480f8b248fad80d1d864a 100644
--- a/docs/python-sdk/fastmcp-utilities-cache.mdx
+++ b/docs/python-sdk/fastmcp-utilities-cache.mdx
@@ -7,23 +7,23 @@ sidebarTitle: cache
## Classes
-### `TimedCache` ↗
+### `TimedCache`
**Methods:**
-#### `set` ↗
+#### `set`
```python
set(self, key: Any, value: Any) -> None
```
-#### `get` ↗
+#### `get`
```python
get(self, key: Any) -> Any
```
-#### `clear` ↗
+#### `clear`
```python
clear(self) -> None
diff --git a/docs/python-sdk/fastmcp-utilities-components.mdx b/docs/python-sdk/fastmcp-utilities-components.mdx
index 12cb11e5c31d5ba1c1b7d3590e9849ffcf20361c..8a27b2ac721a53c1c03b110e5ca3143a3cf4257e 100644
--- a/docs/python-sdk/fastmcp-utilities-components.mdx
+++ b/docs/python-sdk/fastmcp-utilities-components.mdx
@@ -7,7 +7,7 @@ sidebarTitle: components
## Classes
-### `FastMCPComponent` ↗
+### `FastMCPComponent`
Base class for FastMCP tools, prompts, resources, and resource templates.
@@ -15,7 +15,7 @@ Base class for FastMCP tools, prompts, resources, and resource templates.
**Methods:**
-#### `key` ↗
+#### `key`
```python
key(self) -> str
@@ -27,13 +27,13 @@ keys having a certain value, as the same tool loaded from different
hierarchies of servers may have different keys.
-#### `with_key` ↗
+#### `with_key`
```python
with_key(self, key: str) -> Self
```
-#### `enable` ↗
+#### `enable`
```python
enable(self) -> None
@@ -42,7 +42,7 @@ enable(self) -> None
Enable the component.
-#### `disable` ↗
+#### `disable`
```python
disable(self) -> None
diff --git a/docs/python-sdk/fastmcp-utilities-exceptions.mdx b/docs/python-sdk/fastmcp-utilities-exceptions.mdx
index d5e406b5e1f07140c614b5cd82afc0545bc2a834..6b33526dc13eb899f504b0781b3f2ab09c22b2fa 100644
--- a/docs/python-sdk/fastmcp-utilities-exceptions.mdx
+++ b/docs/python-sdk/fastmcp-utilities-exceptions.mdx
@@ -7,13 +7,13 @@ sidebarTitle: exceptions
## Functions
-### `iter_exc` ↗
+### `iter_exc`
```python
iter_exc(group: BaseExceptionGroup)
```
-### `get_catch_handlers` ↗
+### `get_catch_handlers`
```python
get_catch_handlers() -> Mapping[type[BaseException] | Iterable[type[BaseException]], Callable[[BaseExceptionGroup[Any]], Any]]
diff --git a/docs/python-sdk/fastmcp-utilities-http.mdx b/docs/python-sdk/fastmcp-utilities-http.mdx
index 55a5a2e920e1722c17f00edb2be0f67156f8255b..661f4e575ea41fcf363a97a6beedf2bfc4fa3667 100644
--- a/docs/python-sdk/fastmcp-utilities-http.mdx
+++ b/docs/python-sdk/fastmcp-utilities-http.mdx
@@ -7,7 +7,7 @@ sidebarTitle: http
## Functions
-### `find_available_port` ↗
+### `find_available_port`
```python
find_available_port() -> int
diff --git a/docs/python-sdk/fastmcp-utilities-inspect.mdx b/docs/python-sdk/fastmcp-utilities-inspect.mdx
index 860043529bb6271194cffedde4c63ff32e660ecb..f7b09c2293995674e5aad74df58c09ca5dc9f22b 100644
--- a/docs/python-sdk/fastmcp-utilities-inspect.mdx
+++ b/docs/python-sdk/fastmcp-utilities-inspect.mdx
@@ -10,31 +10,31 @@ Utilities for inspecting FastMCP instances.
## Classes
-### `ToolInfo` ↗
+### `ToolInfo`
Information about a tool.
-### `PromptInfo` ↗
+### `PromptInfo`
Information about a prompt.
-### `ResourceInfo` ↗
+### `ResourceInfo`
Information about a resource.
-### `TemplateInfo` ↗
+### `TemplateInfo`
Information about a resource template.
-### `FastMCPInfo` ↗
+### `FastMCPInfo`
Information extracted from a FastMCP instance.
diff --git a/docs/python-sdk/fastmcp-utilities-json_schema.mdx b/docs/python-sdk/fastmcp-utilities-json_schema.mdx
index c0b87d3c19eda491e7058f9adffb33b8a2861c2c..282c03745521703c97955e5bd72a087a6cfdc488 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-logging.mdx b/docs/python-sdk/fastmcp-utilities-logging.mdx
index 306d0b39fdd185e62dbe6597689cfd315ce221ac..03ca4a1bb5ce60204e89b9b385981cafa36ef31f 100644
--- a/docs/python-sdk/fastmcp-utilities-logging.mdx
+++ b/docs/python-sdk/fastmcp-utilities-logging.mdx
@@ -10,7 +10,7 @@ Logging utilities for FastMCP.
## Functions
-### `get_logger` ↗
+### `get_logger`
```python
get_logger(name: str) -> logging.Logger
@@ -26,7 +26,7 @@ Get a logger nested under FastMCP namespace.
- a configured logger instance
-### `configure_logging` ↗
+### `configure_logging`
```python
configure_logging(level: Literal['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'] | int = 'INFO', logger: logging.Logger | None = None, enable_rich_tracebacks: bool = True) -> None
diff --git a/docs/python-sdk/fastmcp-utilities-mcp_config.mdx b/docs/python-sdk/fastmcp-utilities-mcp_config.mdx
index 5731b656669cf58e86bc4bd24ffcdaa57a4300ed..fe1d6f1566bf9a650d207a356d1b9357439194af 100644
--- a/docs/python-sdk/fastmcp-utilities-mcp_config.mdx
+++ b/docs/python-sdk/fastmcp-utilities-mcp_config.mdx
@@ -7,7 +7,7 @@ sidebarTitle: mcp_config
## Functions
-### `infer_transport_type_from_url` ↗
+### `infer_transport_type_from_url`
```python
infer_transport_type_from_url(url: str | AnyUrl) -> Literal['http', 'sse']
@@ -19,31 +19,31 @@ Infer the appropriate transport type from the given URL.
## Classes
-### `StdioMCPServer` ↗
+### `StdioMCPServer`
**Methods:**
-#### `to_transport` ↗
+#### `to_transport`
```python
to_transport(self) -> StdioTransport
```
-### `RemoteMCPServer` ↗
+### `RemoteMCPServer`
**Methods:**
-#### `to_transport` ↗
+#### `to_transport`
```python
to_transport(self) -> StreamableHttpTransport | SSETransport
```
-### `MCPConfig` ↗
+### `MCPConfig`
**Methods:**
-#### `from_dict` ↗
+#### `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 942668c33c44d8b4fcb1dad99dfaa32a52c8aacd..e64157c681aa32ffe23a8b4df8e510815b4d80c4 100644
--- a/docs/python-sdk/fastmcp-utilities-openapi.mdx
+++ b/docs/python-sdk/fastmcp-utilities-openapi.mdx
@@ -7,7 +7,7 @@ sidebarTitle: openapi
## Functions
-### `parse_openapi_to_http_routes` ↗
+### `parse_openapi_to_http_routes`
```python
parse_openapi_to_http_routes(openapi_dict: dict[str, Any]) -> list[HTTPRoute]
@@ -20,7 +20,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
@@ -30,7 +30,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
@@ -41,7 +41,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
@@ -51,7 +51,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
@@ -76,31 +76,31 @@ including its description, whether it is required, and its content schema.
## 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.
@@ -108,7 +108,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 f19af5a2463872727e224e6d47e784cb0ff70b1a..78e0180c11ea7f3ed8ef05a5b4076a5f92bc0891 100644
--- a/docs/python-sdk/fastmcp-utilities-tests.mdx
+++ b/docs/python-sdk/fastmcp-utilities-tests.mdx
@@ -7,7 +7,7 @@ sidebarTitle: tests
## Functions
-### `temporary_settings` ↗
+### `temporary_settings`
```python
temporary_settings(**kwargs: Any)
@@ -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]
diff --git a/docs/python-sdk/fastmcp-utilities-types.mdx b/docs/python-sdk/fastmcp-utilities-types.mdx
index 662fd66b008743c4cafeaf5d740330ba1c7a8537..19a5b7b45eeb928a18ad05854d06fb6e740ee05c 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
@@ -60,13 +60,13 @@ Includes union types that contain the kwarg_type, as well as Annotated types.
## Classes
-### `FastMCPBaseModel` ↗
+### `FastMCPBaseModel`
Base model for FastMCP models.
-### `Image` ↗
+### `Image`
Helper class for returning images from tools.
@@ -74,7 +74,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) -> ImageContent
@@ -83,7 +83,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.
@@ -91,13 +91,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) -> AudioContent
```
-### `File` ↗
+### `File`
Helper class for returning audio from tools.
@@ -105,7 +105,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) -> EmbeddedResource
diff --git a/examples/mount_example.py b/examples/mount_example.py
index 7720f0eb2270103467c111a2e5abcb73c64daf13..b6061954f05e78baf448c3da45c1e8865a47213f 100644
--- a/examples/mount_example.py
+++ b/examples/mount_example.py
@@ -9,6 +9,7 @@ the ToolManager's import_tools functionality. It shows how to:
"""
import asyncio
+from urllib.parse import urlparse
from fastmcp import FastMCP
@@ -65,17 +66,17 @@ def check_app_status() -> dict[str, str]:
# Mount sub-applications
-app.mount("weather", weather_app)
+app.mount(server=weather_app, prefix="weather")
-app.mount("news", news_app)
+app.mount(server=news_app, prefix="news")
async def get_server_details():
"""Print information about mounted resources."""
# Print available tools
- tools = app._tool_manager.list_tools()
+ tools = await app.get_tools()
print(f"\nAvailable tools ({len(tools)}):")
- for tool in tools:
+ for _, tool in tools.items():
print(f" - {tool.name}: {tool.description}")
# Print available resources
@@ -83,18 +84,21 @@ async def get_server_details():
# Distinguish between native and imported resources
# Native resources would be those directly in the main app (not prefixed)
+
+ resources = await app.get_resources()
+
native_resources = [
uri
- for uri in app._resource_manager._resources
- if not (uri.startswith("weather+") or uri.startswith("news+"))
+ for uri, _ in resources.items()
+ if urlparse(uri).netloc not in ("weather", "news")
]
# Imported resources - categorized by source app
weather_resources = [
- uri for uri in app._resource_manager._resources if uri.startswith("weather+")
+ uri for uri, _ in resources.items() if urlparse(uri).netloc == "weather"
]
news_resources = [
- uri for uri in app._resource_manager._resources if uri.startswith("news+")
+ uri for uri, _ in resources.items() if urlparse(uri).netloc == "news"
]
print(f" - Native app resources: {native_resources}")
@@ -102,7 +106,7 @@ async def get_server_details():
print(f" - Imported from news app: {news_resources}")
# Let's try to access resources using the prefixed URI
- weather_data = await app.read_resource("weather+weather://forecast")
+ weather_data = await app._mcp_read_resource(uri="weather://weather/forecast")
print(f"\nWeather data from prefixed URI: {weather_data}")
diff --git a/src/fastmcp/prompts/prompt.py b/src/fastmcp/prompts/prompt.py
index bdc7f95b10b7ac6a796ab031c7205458aeca761d..09b27f63194ea18ccc136bf7726a0ad36aa3fe1e 100644
--- a/src/fastmcp/prompts/prompt.py
+++ b/src/fastmcp/prompts/prompt.py
@@ -355,6 +355,6 @@ class FunctionPrompt(Prompt):
raise PromptError("Could not convert prompt result to message.")
return messages
- except Exception as e:
- logger.exception(f"Error rendering prompt {self.name}: {e}")
+ except Exception:
+ logger.exception(f"Error rendering prompt {self.name}")
raise PromptError(f"Error rendering prompt {self.name}.")
diff --git a/src/fastmcp/prompts/prompt_manager.py b/src/fastmcp/prompts/prompt_manager.py
index 3436e71c4629817d4343dcbb058cd842ee972c57..0f7d216f80d2c9a7e7e3c8380db3cd9a2dbb4994 100644
--- a/src/fastmcp/prompts/prompt_manager.py
+++ b/src/fastmcp/prompts/prompt_manager.py
@@ -172,12 +172,12 @@ class PromptManager:
# Pass through PromptErrors as-is
except PromptError as e:
- logger.exception(f"Error rendering prompt {name!r}: {e}")
+ logger.exception(f"Error rendering prompt {name!r}")
raise e
# Handle other exceptions
except Exception as e:
- logger.exception(f"Error rendering prompt {name!r}: {e}")
+ logger.exception(f"Error rendering prompt {name!r}")
if self.mask_error_details:
# Mask internal details
raise PromptError(f"Error rendering prompt {name!r}") from e
diff --git a/src/fastmcp/resources/resource_manager.py b/src/fastmcp/resources/resource_manager.py
index 8741837baad9277c3d8952cff8d0dfba9f3501e8..8620d4114ee9b8bfd522a26d71edc5d604487456 100644
--- a/src/fastmcp/resources/resource_manager.py
+++ b/src/fastmcp/resources/resource_manager.py
@@ -422,12 +422,12 @@ class ResourceManager:
# raise ResourceErrors as-is
except ResourceError as e:
- logger.exception(f"Error reading resource {uri_str!r}: {e}")
+ logger.exception(f"Error reading resource {uri_str!r}")
raise e
# Handle other exceptions
except Exception as e:
- logger.exception(f"Error reading resource {uri_str!r}: {e}")
+ logger.exception(f"Error reading resource {uri_str!r}")
if self.mask_error_details:
# Mask internal details
raise ResourceError(f"Error reading resource {uri_str!r}") from e
@@ -445,12 +445,12 @@ class ResourceManager:
return await resource.read()
except ResourceError as e:
logger.exception(
- f"Error reading resource from template {uri_str!r}: {e}"
+ f"Error reading resource from template {uri_str!r}"
)
raise e
except Exception as e:
logger.exception(
- f"Error reading resource from template {uri_str!r}: {e}"
+ f"Error reading resource from template {uri_str!r}"
)
if self.mask_error_details:
raise ResourceError(
diff --git a/src/fastmcp/server/auth/providers/bearer.py b/src/fastmcp/server/auth/providers/bearer.py
index 6ffffa909f35125b3a0781c09703c4c0de076262..c6e9024bc371be9475d756bab0efb2e6431cb750 100644
--- a/src/fastmcp/server/auth/providers/bearer.py
+++ b/src/fastmcp/server/auth/providers/bearer.py
@@ -24,6 +24,7 @@ from fastmcp.server.auth.auth import (
OAuthProvider,
RevocationOptions,
)
+from fastmcp.utilities.logging import get_logger
class JWKData(TypedDict, total=False):
@@ -199,6 +200,7 @@ class BearerAuthProvider(OAuthProvider):
self.public_key = public_key
self.jwks_uri = jwks_uri
self.jwt = JsonWebToken(["RS256"])
+ self.logger = get_logger(__name__)
# Simple JWKS cache
self._jwks_cache: dict[str, str] = {}
@@ -265,6 +267,9 @@ class BearerAuthProvider(OAuthProvider):
# Select the appropriate key
if kid:
if kid not in self._jwks_cache:
+ self.logger.debug(
+ "JWKS key lookup failed: key ID '%s' not found", kid
+ )
raise ValueError(f"Key ID '{kid}' not found in JWKS")
return self._jwks_cache[kid]
else:
@@ -279,6 +284,7 @@ class BearerAuthProvider(OAuthProvider):
raise ValueError("No keys found in JWKS")
except Exception as e:
+ self.logger.debug("JWKS fetch failed: %s", str(e))
raise ValueError(f"Failed to fetch JWKS: {e}")
async def load_access_token(self, token: str) -> AccessToken | None:
@@ -298,15 +304,27 @@ class BearerAuthProvider(OAuthProvider):
# Decode and verify the JWT token
claims = self.jwt.decode(token, verification_key)
+ # Extract client ID early for logging
+ client_id = claims.get("client_id") or claims.get("sub") or "unknown"
+
# Validate expiration
exp = claims.get("exp")
if exp and exp < time.time():
+ self.logger.debug(
+ "Token validation failed: expired token for client %s", client_id
+ )
+ self.logger.info("Bearer token rejected for client %s", client_id)
return None
# Validate issuer - note we use issuer instead of issuer_url here because
# issuer is optional, allowing users to make this check optional
if self.issuer:
if claims.get("iss") != self.issuer:
+ self.logger.debug(
+ "Token validation failed: issuer mismatch for client %s",
+ client_id,
+ )
+ self.logger.info("Bearer token rejected for client %s", client_id)
return None
# Validate audience if configured
@@ -314,26 +332,33 @@ class BearerAuthProvider(OAuthProvider):
aud = claims.get("aud")
# Handle different combinations of audience types
+ audience_valid = False
if isinstance(self.audience, list):
# self.audience is a list - check if any expected audience is present
if isinstance(aud, list):
# Both are lists - check for intersection
- if not any(expected in aud for expected in self.audience):
- return None
+ audience_valid = any(
+ expected in aud for expected in self.audience
+ )
else:
# aud is a string - check if it's in our expected list
- if aud not in self.audience:
- return None
+ audience_valid = aud in self.audience
else:
# self.audience is a string - use original logic
if isinstance(aud, list):
- if self.audience not in aud:
- return None
- elif aud != self.audience:
- return None
+ audience_valid = self.audience in aud
+ else:
+ audience_valid = aud == self.audience
- # Extract claims - prefer client_id over sub for OAuth application identification
- client_id = claims.get("client_id") or claims.get("sub") or "unknown"
+ if not audience_valid:
+ self.logger.debug(
+ "Token validation failed: audience mismatch for client %s",
+ client_id,
+ )
+ self.logger.info("Bearer token rejected for client %s", client_id)
+ return None
+
+ # Extract scopes
scopes = self._extract_scopes(claims)
return AccessToken(
@@ -344,8 +369,10 @@ class BearerAuthProvider(OAuthProvider):
)
except JoseError:
+ self.logger.debug("Token validation failed: JWT signature/format invalid")
return None
- except Exception:
+ except Exception as e:
+ self.logger.debug("Token validation failed: %s", str(e))
return None
def _extract_scopes(self, claims: dict[str, Any]) -> list[str]:
diff --git a/src/fastmcp/server/server.py b/src/fastmcp/server/server.py
index c0080747502b3664cc18aeb8d28e32c522c908f6..199366e61792b8b27ed7d7581b9b5e7bd1308e8d 100644
--- a/src/fastmcp/server/server.py
+++ b/src/fastmcp/server/server.py
@@ -365,6 +365,7 @@ class FastMCP(Generic[LifespanResultT]):
return await self._resource_manager.get_resource_templates()
async def get_resource_template(self, key: str) -> ResourceTemplate:
+ """Get a registered resource template by key."""
templates = await self.get_resource_templates()
if key not in templates:
raise NotFoundError(f"Unknown resource template: {key}")
@@ -405,9 +406,12 @@ class FastMCP(Generic[LifespanResultT]):
include_in_schema: Whether to include in OpenAPI schema, defaults to True
Example:
+ Register a custom HTTP route for a health check endpoint:
+ ```python
@server.custom_route("/health", methods=["GET"])
async def health_check(request: Request) -> Response:
return JSONResponse({"status": "ok"})
+ ```
"""
def decorator(
@@ -834,15 +838,18 @@ class FastMCP(Generic[LifespanResultT]):
name: Optional name for the tool (keyword-only, alternative to name_or_fn)
description: Optional description of what the tool does
tags: Optional set of tags for categorizing the tool
- annotations: Optional annotations about the tool's behavior (e.g. {"is_async": True})
+ annotations: Optional annotations about the tool's behavior
exclude_args: Optional list of argument names to exclude from the tool schema
enabled: Optional boolean to enable or disable the tool
- Example:
+ Examples:
+ Register a tool with a custom name:
+ ```python
@server.tool
def my_tool(x: int) -> str:
return str(x)
+ # Register a tool with a custom name
@server.tool
def my_tool(x: int) -> str:
return str(x)
@@ -857,6 +864,7 @@ class FastMCP(Generic[LifespanResultT]):
# Direct function call
server.tool(my_function, name="custom_name")
+ ```
"""
if isinstance(annotations, dict):
annotations = ToolAnnotations(**annotations)
@@ -1029,7 +1037,9 @@ class FastMCP(Generic[LifespanResultT]):
tags: Optional set of tags for categorizing the resource
enabled: Optional boolean to enable or disable the resource
- Example:
+ Examples:
+ Register a resource with a custom name:
+ ```python
@server.resource("resource://my-resource")
def get_data() -> str:
return "Hello, world!"
@@ -1052,6 +1062,7 @@ class FastMCP(Generic[LifespanResultT]):
async def get_weather(city: str) -> str:
data = await fetch_weather(city)
return f"Weather for {city}: {data}"
+ ```
"""
# Check if user passed function directly instead of calling decorator
if inspect.isroutine(uri):
@@ -1185,7 +1196,9 @@ class FastMCP(Generic[LifespanResultT]):
tags: Optional set of tags for categorizing the prompt
enabled: Optional boolean to enable or disable the prompt
- Example:
+ Examples:
+
+ ```python
@server.prompt
def analyze_table(table_name: str) -> list[Message]:
schema = read_table_schema(table_name)
@@ -1229,6 +1242,7 @@ class FastMCP(Generic[LifespanResultT]):
# Direct function call
server.prompt(my_function, name="custom_name")
+ ```
"""
if isinstance(name_or_fn, classmethod):
@@ -1834,10 +1848,10 @@ class FastMCP(Generic[LifespanResultT]):
) -> FastMCPProxy:
"""Create a FastMCP proxy server for the given backend.
- The ``backend`` argument can be either an existing :class:`~fastmcp.client.Client`
- instance or any value accepted as the ``transport`` argument of
- :class:`~fastmcp.client.Client`. This mirrors the convenience of the
- ``Client`` constructor.
+ The `backend` argument can be either an existing `fastmcp.client.Client`
+ instance or any value accepted as the `transport` argument of
+ `fastmcp.client.Client`. This mirrors the convenience of the
+ `fastmcp.client.Client` constructor.
"""
from fastmcp.client.client import Client
from fastmcp.server.proxy import FastMCPProxy
@@ -1874,14 +1888,14 @@ class FastMCP(Generic[LifespanResultT]):
Given a component, determine if it should be enabled. Returns True if it should be enabled; False if it should not.
Rules:
- • If the component's enabled property is False, always return False.
- • If both include_tags and exclude_tags are None, return True.
- • If exclude_tags is provided, check each exclude tag:
+ - If the component's enabled property is False, always return False.
+ - If both include_tags and exclude_tags are None, return True.
+ - If exclude_tags is provided, check each exclude tag:
- If the exclude tag is a string, it must be present in the input tags to exclude.
- • If include_tags is provided, check each include tag:
+ - If include_tags is provided, check each include tag:
- If the include tag is a string, it must be present in the input tags to include.
- • If include_tags is provided and none of the include tags match, return False.
- • If include_tags is not provided, return True.
+ - If include_tags is provided and none of the include tags match, return False.
+ - If include_tags is not provided, return True.
"""
if not component.enabled:
return False
@@ -1922,12 +1936,21 @@ def add_resource_prefix(
The resource URI with the prefix added
Examples:
- >>> add_resource_prefix("resource://path/to/resource", "prefix")
- "resource://prefix/path/to/resource" # with new style
- >>> add_resource_prefix("resource://path/to/resource", "prefix")
- "prefix+resource://path/to/resource" # with legacy style
- >>> add_resource_prefix("resource:///absolute/path", "prefix")
- "resource://prefix//absolute/path" # with new style
+ With new style:
+ ```python
+ add_resource_prefix("resource://path/to/resource", "prefix")
+ "resource://prefix/path/to/resource"
+ ```
+ With legacy style:
+ ```python
+ add_resource_prefix("resource://path/to/resource", "prefix")
+ "prefix+resource://path/to/resource"
+ ```
+ With absolute path:
+ ```python
+ add_resource_prefix("resource:///absolute/path", "prefix")
+ "resource://prefix//absolute/path"
+ ```
Raises:
ValueError: If the URI doesn't match the expected protocol://path format
@@ -1973,12 +1996,21 @@ def remove_resource_prefix(
The resource URI with the prefix removed
Examples:
- >>> remove_resource_prefix("resource://prefix/path/to/resource", "prefix")
- "resource://path/to/resource" # with new style
- >>> remove_resource_prefix("prefix+resource://path/to/resource", "prefix")
- "resource://path/to/resource" # with legacy style
- >>> remove_resource_prefix("resource://prefix//absolute/path", "prefix")
- "resource:///absolute/path" # with new style
+ With new style:
+ ```python
+ remove_resource_prefix("resource://prefix/path/to/resource", "prefix")
+ "resource://path/to/resource"
+ ```
+ With legacy style:
+ ```python
+ remove_resource_prefix("prefix+resource://path/to/resource", "prefix")
+ "resource://path/to/resource"
+ ```
+ With absolute path:
+ ```python
+ remove_resource_prefix("resource://prefix//absolute/path", "prefix")
+ "resource:///absolute/path"
+ ```
Raises:
ValueError: If the URI doesn't match the expected protocol://path format
@@ -2031,12 +2063,21 @@ def has_resource_prefix(
True if the URI has the specified prefix, False otherwise
Examples:
- >>> has_resource_prefix("resource://prefix/path/to/resource", "prefix")
- True # with new style
- >>> has_resource_prefix("prefix+resource://path/to/resource", "prefix")
- True # with legacy style
- >>> has_resource_prefix("resource://other/path/to/resource", "prefix")
+ With new style:
+ ```python
+ has_resource_prefix("resource://prefix/path/to/resource", "prefix")
+ True
+ ```
+ With legacy style:
+ ```python
+ has_resource_prefix("prefix+resource://path/to/resource", "prefix")
+ True
+ ```
+ With other path:
+ ```python
+ has_resource_prefix("resource://other/path/to/resource", "prefix")
False
+ ```
Raises:
ValueError: If the URI doesn't match the expected protocol://path format
diff --git a/src/fastmcp/tools/tool_manager.py b/src/fastmcp/tools/tool_manager.py
index 0d51ba32ea3c5e6e232b62250fe49f8ea8b17ae2..fc8175d7f322a53225e562d574f3149cf1713338 100644
--- a/src/fastmcp/tools/tool_manager.py
+++ b/src/fastmcp/tools/tool_manager.py
@@ -186,12 +186,12 @@ class ToolManager:
# raise ToolErrors as-is
except ToolError as e:
- logger.exception(f"Error calling tool {key!r}: {e}")
+ logger.exception(f"Error calling tool {key!r}")
raise e
# Handle other exceptions
except Exception as e:
- logger.exception(f"Error calling tool {key!r}: {e}")
+ logger.exception(f"Error calling tool {key!r}")
if self.mask_error_details:
# Mask internal details
raise ToolError(f"Error calling tool {key!r}") from e
diff --git a/src/fastmcp/tools/tool_transform.py b/src/fastmcp/tools/tool_transform.py
index 149469a4c117c190143ff23af6f17c4fac0e66f9..c6145d80791411d47455483fe98f6c3b7bdda0f2 100644
--- a/src/fastmcp/tools/tool_transform.py
+++ b/src/fastmcp/tools/tool_transform.py
@@ -100,35 +100,55 @@ class ArgTransform:
examples: Examples for the argument. Use ... for no change.
Examples:
- # Rename argument 'old_name' to 'new_name'
+ Rename argument 'old_name' to 'new_name'
+ ```python
ArgTransform(name="new_name")
+ ```
- # Change description only
+ Change description only
+ ```python
ArgTransform(description="Updated description")
+ ```
- # Add a default value (makes argument optional)
+ Add a default value (makes argument optional)
+ ```python
ArgTransform(default=42)
+ ```
- # Add a default factory (makes argument optional)
+ Add a default factory (makes argument optional)
+ ```python
ArgTransform(default_factory=lambda: time.time())
+ ```
- # Change the type
+ Change the type
+ ```python
ArgTransform(type=str)
+ ```
- # Hide the argument entirely from clients
+ Hide the argument entirely from clients
+ ```python
ArgTransform(hide=True)
+ ```
- # Hide argument but pass a constant value to parent
+ Hide argument but pass a constant value to parent
+ ```python
ArgTransform(hide=True, default="constant_value")
+ ```
- # Hide argument but pass a factory-generated value to parent
+ Hide argument but pass a factory-generated value to parent
+ ```python
ArgTransform(hide=True, default_factory=lambda: uuid.uuid4().hex)
+ ```
- # Make an optional parameter required (removes any default)
+ Make an optional parameter required (removes any default)
+ ```python
ArgTransform(required=True)
+ ```
- # Combine multiple transformations
+ Combine multiple transformations
+ ```python
ArgTransform(name="new_name", description="New desc", default=None, type=int)
+ ```
"""
name: str | EllipsisType = NotSet
@@ -279,9 +299,9 @@ class TransformedTool(Tool):
name: New name for the tool. Defaults to parent tool's name.
transform_args: Optional transformations for parent tool arguments.
Only specified arguments are transformed, others pass through unchanged:
- - str: Simple rename
- - ArgTransform: Complex transformation (rename/description/default/drop)
- - None: Drop the argument
+ - Simple rename (str)
+ - Complex transformation (rename/description/default/drop) (ArgTransform)
+ - Drop the argument (None)
description: New description. Defaults to parent's description.
tags: New tags. Defaults to parent's tags.
annotations: New annotations. Defaults to parent's annotations.
@@ -290,23 +310,29 @@ class TransformedTool(Tool):
Returns:
TransformedTool with the specified transformations.
- Examples:
+ Examples:
# Transform specific arguments only
+ ```python
Tool.from_tool(parent, transform_args={"old": "new"}) # Others unchanged
+ ```
# Custom function with partial transforms
+ ```python
async def custom(x: int, y: int) -> str:
result = await forward(x=x, y=y)
return f"Custom: {result}"
Tool.from_tool(parent, transform_fn=custom, transform_args={"a": "x", "b": "y"})
+ ```
# Using **kwargs (gets all args, transformed and untransformed)
+ ```python
async def flexible(**kwargs) -> str:
result = await forward(**kwargs)
return f"Got: {kwargs}"
Tool.from_tool(parent, transform_fn=flexible, transform_args={"a": "x"})
+ ```
"""
transform_args = transform_args or {}
@@ -423,8 +449,8 @@ class TransformedTool(Tool):
Returns:
A tuple containing:
- - dict: The new JSON schema for the transformed tool
- - Callable: Async function that validates and forwards calls to the parent tool
+ - The new JSON schema for the transformed tool as a dictionary
+ - Async function that validates and forwards calls to the parent tool
"""
# Build transformed schema and mapping
diff --git a/src/fastmcp/utilities/openapi.py b/src/fastmcp/utilities/openapi.py
index 0cae85cb24ee577f12da0130a40b8cf7fd5064e7..c29b20661ceee5e041b3f1f7298f187fbf58b1a3 100644
--- a/src/fastmcp/utilities/openapi.py
+++ b/src/fastmcp/utilities/openapi.py
@@ -274,6 +274,12 @@ class OpenAPIParser(
result = {}
return _replace_ref_with_defs(result)
+ except ValueError as e:
+ # Re-raise ValueError for external reference errors and other validation issues
+ if "External or non-local reference not supported" in str(e):
+ raise
+ logger.error(f"Failed to extract schema as dict: {e}", exc_info=False)
+ return {}
except Exception as e:
logger.error(f"Failed to extract schema as dict: {e}", exc_info=False)
return {}
@@ -302,11 +308,17 @@ class OpenAPIParser(
# Extract parameter info - handle both 3.0 and 3.1 parameter models
param_in = parameter.param_in # Both use param_in
- param_location = self._convert_to_parameter_location(param_in)
+ # Handle enum or string parameter locations
+ from enum import Enum
+
+ param_in_str = (
+ param_in.value if isinstance(param_in, Enum) else param_in
+ )
+ param_location = self._convert_to_parameter_location(param_in_str)
param_schema_obj = parameter.param_schema # Both use param_schema
# Skip duplicate parameters (same name and location)
- param_key = (parameter.name, param_in)
+ param_key = (parameter.name, param_in_str)
if param_key in seen_params:
continue
seen_params[param_key] = True
@@ -400,12 +412,30 @@ class OpenAPIParser(
request_body_info.content_schema[media_type_str] = (
schema_dict
)
+ except ValueError as e:
+ # Re-raise ValueError for external reference errors
+ if "External or non-local reference not supported" in str(
+ e
+ ):
+ raise
+ logger.error(
+ f"Failed to extract schema for media type '{media_type_str}': {e}"
+ )
except Exception as e:
logger.error(
f"Failed to extract schema for media type '{media_type_str}': {e}"
)
return request_body_info
+ except ValueError as e:
+ # Re-raise ValueError for external reference errors
+ if "External or non-local reference not supported" in str(e):
+ raise
+ ref_name = getattr(request_body_or_ref, "ref", "unknown")
+ logger.error(
+ f"Failed to extract request body '{ref_name}': {e}", exc_info=False
+ )
+ return None
except Exception as e:
ref_name = getattr(request_body_or_ref, "ref", "unknown")
logger.error(
@@ -449,6 +479,17 @@ class OpenAPIParser(
media_type_obj.media_type_schema
)
resp_info.content_schema[media_type_str] = schema_dict
+ except ValueError as e:
+ # Re-raise ValueError for external reference errors
+ if (
+ "External or non-local reference not supported"
+ in str(e)
+ ):
+ raise
+ logger.error(
+ f"Failed to extract schema for media type '{media_type_str}' "
+ f"in response {status_code}: {e}"
+ )
except Exception as e:
logger.error(
f"Failed to extract schema for media type '{media_type_str}' "
@@ -456,6 +497,16 @@ class OpenAPIParser(
)
extracted_responses[str(status_code)] = resp_info
+ except ValueError as e:
+ # Re-raise ValueError for external reference errors
+ if "External or non-local reference not supported" in str(e):
+ raise
+ ref_name = getattr(resp_or_ref, "ref", "unknown")
+ logger.error(
+ f"Failed to extract response for status code {status_code} "
+ f"from reference '{ref_name}': {e}",
+ exc_info=False,
+ )
except Exception as e:
ref_name = getattr(resp_or_ref, "ref", "unknown")
logger.error(
@@ -556,6 +607,17 @@ class OpenAPIParser(
logger.info(
f"Successfully extracted route: {method_upper} {path_str}"
)
+ except ValueError as op_error:
+ # Re-raise ValueError for external reference errors
+ if "External or non-local reference not supported" in str(
+ op_error
+ ):
+ raise
+ op_id = getattr(operation, "operationId", "unknown")
+ logger.error(
+ f"Failed to process operation {method_upper} {path_str} (ID: {op_id}): {op_error}",
+ exc_info=True,
+ )
except Exception as op_error:
op_id = getattr(operation, "operationId", "unknown")
logger.error(
@@ -901,6 +963,12 @@ def _replace_ref_with_defs(
if ref_path.startswith("#/components/schemas/"):
schema_name = ref_path.split("/")[-1]
schema["$ref"] = f"#/$defs/{schema_name}"
+ elif not ref_path.startswith("#/"):
+ raise ValueError(
+ f"External or non-local reference not supported: {ref_path}. "
+ f"FastMCP only supports local schema references starting with '#/'. "
+ f"Please include all schema definitions within the OpenAPI document."
+ )
elif properties := schema.get("properties"):
if "$ref" in properties:
schema["properties"] = _replace_ref_with_defs(properties)
diff --git a/tests/server/openapi/test_openapi_path_parameters.py b/tests/server/openapi/test_openapi_path_parameters.py
index 078e61a583932711b9e26f7937986a6590bf6873..7f977ea509884173e3311715556ebeba0d2c3045 100644
--- a/tests/server/openapi/test_openapi_path_parameters.py
+++ b/tests/server/openapi/test_openapi_path_parameters.py
@@ -455,3 +455,31 @@ async def test_array_query_parameter_exploded_format(mock_client):
json=None,
timeout=None,
)
+
+
+def test_parameter_location_enum_handling():
+ """Test that ParameterLocation enum values are handled correctly (issue #950)."""
+ from enum import Enum
+
+ # Create a mock ParameterLocation enum like the one from openapi_pydantic
+ class MockParameterLocation(Enum):
+ PATH = "path"
+ QUERY = "query"
+ HEADER = "header"
+ COOKIE = "cookie"
+
+ # Test the enum handling logic directly (reproduces the fix in openapi.py)
+ test_cases = [
+ (MockParameterLocation.PATH, "path"),
+ (MockParameterLocation.QUERY, "query"),
+ (MockParameterLocation.HEADER, "header"),
+ (MockParameterLocation.COOKIE, "cookie"),
+ ("path", "path"), # Also test that strings work
+ ("query", "query"),
+ ]
+
+ for param_in, expected_str in test_cases:
+ # This is the enum handling logic from the fix
+ param_in_str = param_in.value if isinstance(param_in, Enum) else param_in
+ assert param_in_str == expected_str
+ assert isinstance(param_in_str, str)
diff --git a/tests/utilities/openapi/test_openapi_advanced.py b/tests/utilities/openapi/test_openapi_advanced.py
index 979ca9b28974b6900062c89a033eee590b1f56d4..58a03143d03b6014e55aaa516d5324897294f8e3 100644
--- a/tests/utilities/openapi/test_openapi_advanced.py
+++ b/tests/utilities/openapi/test_openapi_advanced.py
@@ -614,3 +614,52 @@ def test_http_trace_method_path(parsed_http_methods_routes):
assert trace_route is not None
assert trace_route.path == "/resource"
+
+
+@pytest.fixture
+def schema_with_external_reference() -> dict[str, Any]:
+ """Fixture that returns a schema with external schema references like in issue #926."""
+ return {
+ "openapi": "3.0.0",
+ "info": {"title": "External Reference API", "version": "1.0.0"},
+ "paths": {
+ "/products": {
+ "post": {
+ "summary": "Create a product",
+ "operationId": "createProduct",
+ "requestBody": {
+ "required": True,
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "obj": {
+ "$ref": "http://cyaninc.com/json-schemas/market-v1/product-constraints"
+ }
+ },
+ }
+ }
+ },
+ },
+ "responses": {"201": {"description": "Product created"}},
+ }
+ }
+ },
+ }
+
+
+# --- Tests for external schema reference handling --- #
+
+
+def test_external_reference_raises_clear_error(schema_with_external_reference):
+ """Test that external schema references raise a clear, helpful error message."""
+ with pytest.raises(ValueError) as exc_info:
+ parse_openapi_to_http_routes(schema_with_external_reference)
+
+ error_message = str(exc_info.value)
+ assert "External or non-local reference not supported" in error_message
+ assert (
+ "http://cyaninc.com/json-schemas/market-v1/product-constraints" in error_message
+ )
+ assert "FastMCP only supports local schema references" in error_message