Remove deprecated FastMCP() constructor kwargs (#3148)

Co-authored-by: marvin-context-protocol[bot] <225465937+marvin-context-protocol[bot]@users.noreply.github.com>
This commit is contained in:
Jeremiah Lowin 2026-02-11 11:39:34 -05:00 committed by GitHub
commit 25e2f4da32
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 285 additions and 800 deletions

View file

@ -66,6 +66,32 @@ async def get_emails(
Background tasks now use a distributed Redis notification queue for reliable delivery ([#2906](https://github.com/jlowin/fastmcp/pull/2906)). Elicitation switches from polling to BLPOP (single blocking call instead of ~7,200 round-trips/hour), and notification delivery retries up to 3x with TTL-based expiration.
### Breaking: Deprecated `FastMCP()` Constructor Kwargs Removed
Sixteen deprecated keyword arguments have been removed from `FastMCP.__init__`. Passing any of them now raises `TypeError` with a migration hint. Environment variables (e.g., `FASTMCP_HOST`) continue to work — only the constructor kwargs moved.
**Transport/server settings** (`host`, `port`, `log_level`, `debug`, `sse_path`, `message_path`, `streamable_http_path`, `json_response`, `stateless_http`): Pass to `run()`, `run_http_async()`, or `http_app()` as appropriate, or set via environment variables.
```python
# Before
mcp = FastMCP("server", host="0.0.0.0", port=8080)
mcp.run()
# After
mcp = FastMCP("server")
mcp.run(transport="http", host="0.0.0.0", port=8080)
```
**Duplicate handling** (`on_duplicate_tools`, `on_duplicate_resources`, `on_duplicate_prompts`): Use the unified `on_duplicate=` parameter.
**Tag filtering** (`include_tags`, `exclude_tags`): Use `server.enable(tags=..., only=True)` and `server.disable(tags=...)` after construction.
**Tool serializer** (`tool_serializer`): Return `ToolResult` from tools instead.
**Tool transformations** (`tool_transformations`): Use `server.add_transform(ToolTransform(...))` after construction.
The `_deprecated_settings` attribute and `.settings` property are also removed. `ExperimentalSettings` has been deleted (dead code).
### Breaking: `ui=` Renamed to `app=`
The MCP Apps decorator parameter has been renamed from `ui=ToolUI(...)` / `ui=ResourceUI(...)` to `app=AppConfig(...)` ([#3117](https://github.com/jlowin/fastmcp/pull/3117)). `ToolUI` and `ResourceUI` are consolidated into a single `AppConfig` class. Wire format is unchanged. See the MCP Apps section under beta2 for full details.
@ -1266,35 +1292,9 @@ main.mount(subserver, prefix="api")
main.mount(subserver, namespace="api")
```
#### Tag Filtering Init Parameters
#### Tag Filtering, Tool Serializer, Tool Transformations Init Parameters
`FastMCP(include_tags=..., exclude_tags=...)` deprecated. Use `enable()`/`disable()` methods:
```python
# Deprecated
mcp = FastMCP("server", exclude_tags={"internal"})
# New
mcp = FastMCP("server")
mcp.disable(tags={"internal"})
```
#### Tool Serializer Parameter
The `tool_serializer` parameter on `FastMCP` is deprecated. Return `ToolResult` for explicit serialization control.
#### Tool Transformation Methods
`add_tool_transformation()`, `remove_tool_transformation()`, and `tool_transformations` constructor parameter are deprecated. Use `add_transform(ToolTransform({...}))` instead:
```python
# Deprecated
mcp.add_tool_transformation("name", config)
# New
from fastmcp.server.transforms import ToolTransform
mcp.add_transform(ToolTransform({"name": config}))
```
These constructor parameters have been **removed** (not just deprecated) as of rc1. See "Breaking: Deprecated `FastMCP()` Constructor Kwargs Removed" in the rc1 section above. The `add_tool_transformation()` and `remove_tool_transformation()` methods remain as deprecated shims.
---

View file

@ -42,7 +42,7 @@ infer_transport_type_from_url(url: str | AnyUrl) -> Literal['http', 'sse']
Infer the appropriate transport type from the given URL.
### `update_config_file` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L321" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `update_config_file` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L324" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
update_config_file(file_path: Path, server_name: str, server_config: CanonicalMCPServerTypes) -> None
@ -57,7 +57,7 @@ worry about transforming server objects here.
## Classes
### `StdioMCPServer` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L131" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `StdioMCPServer` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L134" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
MCP server configuration for stdio transport.
@ -67,19 +67,19 @@ This is the canonical configuration format for MCP servers using stdio transport
**Methods:**
#### `to_transport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L164" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `to_transport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L167" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
to_transport(self) -> StdioTransport
```
### `TransformingStdioMCPServer` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L176" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `TransformingStdioMCPServer` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L179" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
A Stdio server with tool transforms.
### `RemoteMCPServer` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L180" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `RemoteMCPServer` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L183" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
MCP server configuration for HTTP/SSE transport.
@ -89,19 +89,19 @@ This is the canonical configuration format for MCP servers using remote transpor
**Methods:**
#### `to_transport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L216" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `to_transport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L219" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
to_transport(self) -> StreamableHttpTransport | SSETransport
```
### `TransformingRemoteMCPServer` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L241" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `TransformingRemoteMCPServer` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L244" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
A Remote server with tool transforms.
### `MCPConfig` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L252" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `MCPConfig` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L255" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
A configuration object for MCP Servers that conforms to the canonical MCP configuration format
@ -113,7 +113,7 @@ For an MCPConfig that is strictly canonical, see the `CanonicalMCPConfig` class.
**Methods:**
#### `wrap_servers_at_root` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L266" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `wrap_servers_at_root` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L269" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
wrap_servers_at_root(cls, values: dict[str, Any]) -> dict[str, Any]
@ -122,7 +122,7 @@ wrap_servers_at_root(cls, values: dict[str, Any]) -> dict[str, Any]
If there's no mcpServers key but there are server configs at root, wrap them.
#### `add_server` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L279" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_server` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L282" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_server(self, name: str, server: MCPServerTypes) -> None
@ -131,7 +131,7 @@ add_server(self, name: str, server: MCPServerTypes) -> None
Add or update a server in the configuration.
#### `from_dict` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L284" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `from_dict` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L287" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
from_dict(cls, config: dict[str, Any]) -> Self
@ -140,7 +140,7 @@ from_dict(cls, config: dict[str, Any]) -> Self
Parse MCP configuration from dictionary format.
#### `to_dict` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L288" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `to_dict` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L291" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
to_dict(self) -> dict[str, Any]
@ -149,7 +149,7 @@ to_dict(self) -> dict[str, Any]
Convert MCPConfig to dictionary format, preserving all fields.
#### `write_to_file` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L292" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `write_to_file` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L295" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
write_to_file(self, file_path: Path) -> None
@ -158,7 +158,7 @@ write_to_file(self, file_path: Path) -> None
Write configuration to JSON file.
#### `from_file` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L298" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `from_file` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L301" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
from_file(cls, file_path: Path) -> Self
@ -167,7 +167,7 @@ from_file(cls, file_path: Path) -> Self
Load configuration from JSON file.
### `CanonicalMCPConfig` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L306" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `CanonicalMCPConfig` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L309" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Canonical MCP configuration format.
@ -178,7 +178,7 @@ The format is designed to be client-agnostic and extensible for future use cases
**Methods:**
#### `add_server` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L316" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_server` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/mcp_config.py#L319" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_server(self, name: str, server: CanonicalMCPServerTypes) -> None

View file

@ -104,7 +104,7 @@ Run the server using HTTP transport.
- `stateless`: Alias for stateless_http for CLI consistency
#### `http_app` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/mixins/transport.py#L281" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `http_app` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/mixins/transport.py#L279" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
http_app(self: FastMCP, path: str | None = None, middleware: list[ASGIMiddleware] | None = None, json_response: bool | None = None, stateless_http: bool | None = None, transport: Literal['http', 'streamable-http', 'sse'] = 'http', event_store: EventStore | None = None, retry_interval: int | None = None) -> StarletteWithLifespan

View file

@ -10,7 +10,7 @@ FastMCP - A more ergonomic interface for MCP servers.
## Functions
### `default_lifespan` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L174" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `default_lifespan` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L168" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
default_lifespan(server: FastMCP[LifespanResultT]) -> AsyncIterator[Any]
@ -26,7 +26,7 @@ Default lifespan context manager that does nothing.
- An empty dictionary as the lifespan result.
### `create_proxy` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2179" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `create_proxy` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2049" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
create_proxy(target: Client[ClientTransportT] | ClientTransport | FastMCP[Any] | FastMCP1Server | AnyUrl | Path | MCPConfig | dict[str, Any] | str, **settings: Any) -> FastMCPProxy
@ -54,65 +54,59 @@ use `FastMCPProxy` or `ProxyProvider` directly from `fastmcp.server.providers.pr
## Classes
### `StateValue` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L210" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `StateValue` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L204" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Wrapper for stored context state values.
### `FastMCP` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L216" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `FastMCP` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L210" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
**Methods:**
#### `settings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L455" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
settings(self) -> Settings
```
#### `name` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L466" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `name` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L337" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
name(self) -> str
```
#### `instructions` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L470" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `instructions` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L341" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
instructions(self) -> str | None
```
#### `instructions` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L474" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `instructions` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L345" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
instructions(self, value: str | None) -> None
```
#### `version` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L478" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `version` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L349" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
version(self) -> str | None
```
#### `website_url` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L482" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `website_url` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L353" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
website_url(self) -> str | None
```
#### `icons` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L486" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `icons` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L357" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
icons(self) -> list[mcp.types.Icon]
```
#### `add_middleware` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L503" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_middleware` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L374" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_middleware(self, middleware: Middleware) -> None
```
#### `add_provider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L506" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_provider` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L377" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_provider(self, provider: Provider) -> None
@ -132,7 +126,7 @@ always take precedence over providers.
- Prompts become "namespace_promptname"
#### `get_tasks` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L528" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_tasks` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L399" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_tasks(self) -> Sequence[FastMCPComponent]
@ -144,7 +138,7 @@ Overrides AggregateProvider.get_tasks() to apply server-level transforms
after aggregation. AggregateProvider handles provider-level namespacing.
#### `add_transform` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L557" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_transform` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L428" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_transform(self, transform: Transform) -> None
@ -159,7 +153,7 @@ They transform tools, resources, and prompts from ALL providers.
- `transform`: The transform to add.
#### `add_tool_transformation` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L577" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_tool_transformation` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L448" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_tool_transformation(self, tool_name: str, transformation: ToolTransformConfig) -> None
@ -171,7 +165,7 @@ Add a tool transformation.
Use ``add_transform(ToolTransform({...}))`` instead.
#### `remove_tool_transformation` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L594" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `remove_tool_transformation` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L465" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
remove_tool_transformation(self, _tool_name: str) -> None
@ -183,7 +177,7 @@ Remove a tool transformation.
Tool transformations are now immutable. Use enable/disable controls instead.
#### `list_tools` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L609" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `list_tools` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L480" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
list_tools(self) -> Sequence[Tool]
@ -196,7 +190,7 @@ and middleware execution. Returns all versions (no deduplication).
Protocol handlers deduplicate for MCP wire format.
#### `get_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L679" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L550" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_tool(self, name: str, version: VersionSpec | None = None) -> Tool | None
@ -216,7 +210,7 @@ session transforms can override provider-level disables.
- The tool if found and enabled, None otherwise.
#### `list_resources` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L705" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `list_resources` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L576" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
list_resources(self) -> Sequence[Resource]
@ -229,7 +223,7 @@ and middleware execution. Returns all versions (no deduplication).
Protocol handlers deduplicate for MCP wire format.
#### `get_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L777" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L648" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_resource(self, uri: str, version: VersionSpec | None = None) -> Resource | None
@ -248,7 +242,7 @@ transforms (including session-level) have been applied.
- The resource if found and enabled, None otherwise.
#### `list_resource_templates` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L802" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `list_resource_templates` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L673" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
list_resource_templates(self) -> Sequence[ResourceTemplate]
@ -261,7 +255,7 @@ auth filtering, and middleware execution. Returns all versions (no deduplication
Protocol handlers deduplicate for MCP wire format.
#### `get_resource_template` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L876" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_resource_template` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L747" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_resource_template(self, uri: str, version: VersionSpec | None = None) -> ResourceTemplate | None
@ -280,7 +274,7 @@ all transforms (including session-level) have been applied.
- The template if found and enabled, None otherwise.
#### `list_prompts` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L901" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `list_prompts` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L772" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
list_prompts(self) -> Sequence[Prompt]
@ -293,7 +287,7 @@ and middleware execution. Returns all versions (no deduplication).
Protocol handlers deduplicate for MCP wire format.
#### `get_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L971" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L842" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_prompt(self, name: str, version: VersionSpec | None = None) -> Prompt | None
@ -312,19 +306,19 @@ transforms (including session-level) have been applied.
- The prompt if found and enabled, None otherwise.
#### `call_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L997" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `call_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L868" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
call_tool(self, name: str, arguments: dict[str, Any] | None = None) -> ToolResult
```
#### `call_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1008" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `call_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L879" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
call_tool(self, name: str, arguments: dict[str, Any] | None = None) -> mcp.types.CreateTaskResult
```
#### `call_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1018" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `call_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L889" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
call_tool(self, name: str, arguments: dict[str, Any] | None = None) -> ToolResult | mcp.types.CreateTaskResult
@ -354,19 +348,19 @@ return ToolResult.
- `ValidationError`: If arguments fail validation
#### `read_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1114" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `read_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L985" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
read_resource(self, uri: str) -> ResourceResult
```
#### `read_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1124" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `read_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L995" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
read_resource(self, uri: str) -> mcp.types.CreateTaskResult
```
#### `read_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1133" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `read_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1004" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
read_resource(self, uri: str) -> ResourceResult | mcp.types.CreateTaskResult
@ -395,19 +389,19 @@ return ResourceResult.
- `ResourceError`: If resource read fails
#### `render_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1267" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `render_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1138" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
render_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> PromptResult
```
#### `render_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1278" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `render_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1149" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
render_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> mcp.types.CreateTaskResult
```
#### `render_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1288" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `render_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1159" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
render_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> PromptResult | mcp.types.CreateTaskResult
@ -437,7 +431,7 @@ return PromptResult.
- `PromptError`: If prompt rendering fails
#### `add_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1364" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1235" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_tool(self, tool: Tool | Callable[..., Any]) -> Tool
@ -455,7 +449,7 @@ with the Context type annotation. See the @tool decorator for examples.
- The tool instance that was added to the server.
#### `remove_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1378" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `remove_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1249" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
remove_tool(self, name: str, version: str | None = None) -> None
@ -471,19 +465,19 @@ Remove tool(s) from the server.
- `NotFoundError`: If no matching tool is found.
#### `tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1398" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1269" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
tool(self, name_or_fn: AnyFunction) -> FunctionTool
```
#### `tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1419" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1290" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
tool(self, name_or_fn: str | None = None) -> Callable[[AnyFunction], FunctionTool]
```
#### `tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1439" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1310" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
tool(self, name_or_fn: str | AnyFunction | None = None) -> Callable[[AnyFunction], FunctionTool] | FunctionTool | partial[Callable[[AnyFunction], FunctionTool] | FunctionTool]
@ -539,7 +533,7 @@ server.tool(my_function, name="custom_name")
```
#### `add_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1539" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1409" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_resource(self, resource: Resource | Callable[..., Any]) -> Resource | ResourceTemplate
@ -554,7 +548,7 @@ Add a resource to the server.
- The resource instance that was added to the server.
#### `add_template` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1552" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_template` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1422" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_template(self, template: ResourceTemplate) -> ResourceTemplate
@ -569,7 +563,7 @@ Add a resource template to the server.
- The template instance that was added to the server.
#### `resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1563" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `resource` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1433" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
resource(self, uri: str) -> Callable[[AnyFunction], Resource | ResourceTemplate | AnyFunction]
@ -628,7 +622,7 @@ async def get_weather(city: str) -> str:
```
#### `add_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1685" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `add_prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1555" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
add_prompt(self, prompt: Prompt | Callable[..., Any]) -> Prompt
@ -643,19 +637,19 @@ Add a prompt to the server.
- The prompt instance that was added to the server.
#### `prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1697" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1567" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
prompt(self, name_or_fn: AnyFunction) -> FunctionPrompt
```
#### `prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1713" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1583" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
prompt(self, name_or_fn: str | None = None) -> Callable[[AnyFunction], FunctionPrompt]
```
#### `prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1728" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `prompt` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1598" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
prompt(self, name_or_fn: str | AnyFunction | None = None) -> Callable[[AnyFunction], FunctionPrompt] | FunctionPrompt | partial[Callable[[AnyFunction], FunctionPrompt] | FunctionPrompt]
@ -732,7 +726,7 @@ Decorator to register a prompt.
```
#### `mount` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1828" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `mount` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1698" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
mount(self, server: FastMCP[LifespanResultT], namespace: str | None = None, as_proxy: bool | None = None, tool_names: dict[str, str] | None = None, prefix: str | None = None) -> None
@ -779,7 +773,7 @@ mounted server.
- `prefix`: Deprecated. Use namespace instead.
#### `import_server` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1922" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `import_server` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1792" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
import_server(self, server: FastMCP[LifespanResultT], prefix: str | None = None) -> None
@ -820,7 +814,7 @@ templates, and prompts are imported with their original names.
objects are imported with their original names.
#### `from_openapi` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2022" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `from_openapi` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1892" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
from_openapi(cls, openapi_spec: dict[str, Any], client: httpx.AsyncClient | None = None, name: str = 'OpenAPI Server', route_maps: list[RouteMap] | None = None, route_map_fn: OpenAPIRouteMapFn | None = None, mcp_component_fn: OpenAPIComponentFn | None = None, mcp_names: dict[str, str] | None = None, tags: set[str] | None = None, validate_output: bool = True, **settings: Any) -> Self
@ -849,7 +843,7 @@ response structure while still returning structured JSON.
- A FastMCP server with an OpenAPIProvider attached.
#### `from_fastapi` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2073" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `from_fastapi` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1943" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```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) -> Self
@ -873,7 +867,7 @@ Use this to configure timeout and other client settings.
- A FastMCP server with an OpenAPIProvider attached.
#### `as_proxy` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2128" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `as_proxy` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L1998" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
as_proxy(cls, backend: Client[ClientTransportT] | ClientTransport | FastMCP[Any] | FastMCP1Server | AnyUrl | Path | MCPConfig | dict[str, Any] | str, **settings: Any) -> FastMCPProxy
@ -891,7 +885,7 @@ instance or any value accepted as the `transport` argument of
`fastmcp.client.Client` constructor.
#### `generate_name` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2165" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `generate_name` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2035" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
generate_name(cls, name: str | None = None) -> str

View file

@ -7,15 +7,13 @@ sidebarTitle: settings
## Classes
### `DocketSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L30" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `DocketSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L29" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
Docket worker configuration.
### `ExperimentalSettings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L118" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `Settings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L142" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
### `Settings` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L117" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
FastMCP settings.
@ -23,7 +21,7 @@ FastMCP settings.
**Methods:**
#### `get_setting` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L154" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `get_setting` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L129" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
get_setting(self, attr: str) -> Any
@ -33,7 +31,7 @@ Get a setting. If the setting contains one or more `__`, it will be
treated as a nested setting.
#### `set_setting` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L167" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `set_setting` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L142" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
set_setting(self, attr: str, value: Any) -> None
@ -43,7 +41,7 @@ Set a setting. If the setting contains one or more `__`, it will be
treated as a nested setting.
#### `normalize_log_level` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L189" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
#### `normalize_log_level` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/settings.py#L164" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
```python
normalize_log_level(cls, v)

View file

@ -109,10 +109,13 @@ class _TransformingMCPServerMixin(FastMCPBaseModel):
wrapped_mcp_server = create_proxy(
client,
name=server_name,
include_tags=self.include_tags,
exclude_tags=self.exclude_tags,
)
if self.include_tags is not None:
wrapped_mcp_server.enable(tags=self.include_tags, only=True)
if self.exclude_tags is not None:
wrapped_mcp_server.disable(tags=self.exclude_tags)
# Apply tool transforms if configured
if self.tools:
from fastmcp.server.transforms import ToolTransform

View file

@ -231,17 +231,15 @@ class TransportMixin:
# Resolve from settings/env var if not explicitly set
if stateless_http is None:
stateless_http = self._deprecated_settings.stateless_http
stateless_http = fastmcp.settings.stateless_http
# SSE doesn't support stateless mode
if stateless_http and transport == "sse":
raise ValueError("SSE transport does not support stateless mode")
host = host or self._deprecated_settings.host
port = port or self._deprecated_settings.port
default_log_level_to_use = (
log_level or self._deprecated_settings.log_level
).lower()
host = host or fastmcp.settings.host
port = port or fastmcp.settings.port
default_log_level_to_use = (log_level or fastmcp.settings.log_level).lower()
app = self.http_app(
path=path,
@ -311,31 +309,30 @@ class TransportMixin:
if transport in ("streamable-http", "http"):
return create_streamable_http_app(
server=self,
streamable_http_path=path
or self._deprecated_settings.streamable_http_path,
streamable_http_path=path or fastmcp.settings.streamable_http_path,
event_store=event_store,
retry_interval=retry_interval,
auth=self.auth,
json_response=(
json_response
if json_response is not None
else self._deprecated_settings.json_response
else fastmcp.settings.json_response
),
stateless_http=(
stateless_http
if stateless_http is not None
else self._deprecated_settings.stateless_http
else fastmcp.settings.stateless_http
),
debug=self._deprecated_settings.debug,
debug=fastmcp.settings.debug,
middleware=middleware,
)
elif transport == "sse":
return create_sse_app(
server=self,
message_path=self._deprecated_settings.message_path,
sse_path=path or self._deprecated_settings.sse_path,
message_path=fastmcp.settings.message_path,
sse_path=path or fastmcp.settings.sse_path,
auth=self.auth,
debug=self._deprecated_settings.debug,
debug=fastmcp.settings.debug,
middleware=middleware,
)
else:

View file

@ -10,8 +10,6 @@ from collections.abc import (
AsyncIterator,
Awaitable,
Callable,
Collection,
Mapping,
Sequence,
)
from contextlib import (
@ -79,7 +77,6 @@ from fastmcp.server.transforms import (
)
from fastmcp.server.transforms.visibility import apply_session_transforms, is_enabled
from fastmcp.settings import DuplicateBehavior as DuplicateBehaviorSetting
from fastmcp.settings import Settings
from fastmcp.tools.function_tool import FunctionTool
from fastmcp.tools.tool import AuthCheckCallable, Tool, ToolResult
from fastmcp.tools.tool_transform import ToolTransformConfig
@ -99,7 +96,6 @@ if TYPE_CHECKING:
from fastmcp.server.providers.openapi import RouteMap
from fastmcp.server.providers.openapi import RouteMapFn as OpenAPIRouteMapFn
from fastmcp.server.providers.proxy import FastMCPProxy
from fastmcp.tools.tool import ToolResultSerializerType
logger = get_logger(__name__)
@ -107,39 +103,37 @@ logger = get_logger(__name__)
DuplicateBehavior = Literal["warn", "error", "replace", "ignore"]
def _resolve_on_duplicate(
on_duplicate: DuplicateBehavior | None,
on_duplicate_tools: DuplicateBehavior | None,
on_duplicate_resources: DuplicateBehavior | None,
on_duplicate_prompts: DuplicateBehavior | None,
) -> DuplicateBehavior:
"""Resolve on_duplicate from deprecated per-type params.
_REMOVED_KWARGS: dict[str, str] = {
"host": "Pass `host` to `run_http_async()`, or set FASTMCP_HOST.",
"port": "Pass `port` to `run_http_async()`, or set FASTMCP_PORT.",
"sse_path": "Pass `path` to `run_http_async()` or `http_app()`, or set FASTMCP_SSE_PATH.",
"message_path": "Set FASTMCP_MESSAGE_PATH.",
"streamable_http_path": "Pass `path` to `run_http_async()` or `http_app()`, or set FASTMCP_STREAMABLE_HTTP_PATH.",
"json_response": "Pass `json_response` to `run_http_async()` or `http_app()`, or set FASTMCP_JSON_RESPONSE.",
"stateless_http": "Pass `stateless_http` to `run_http_async()` or `http_app()`, or set FASTMCP_STATELESS_HTTP.",
"debug": "Set FASTMCP_DEBUG.",
"log_level": "Pass `log_level` to `run_http_async()`, or set FASTMCP_LOG_LEVEL.",
"on_duplicate_tools": "Use `on_duplicate=` instead.",
"on_duplicate_resources": "Use `on_duplicate=` instead.",
"on_duplicate_prompts": "Use `on_duplicate=` instead.",
"tool_serializer": "Return ToolResult from your tools instead. See https://gofastmcp.com/servers/tools#custom-serialization",
"include_tags": "Use `server.enable(tags=..., only=True)` after creating the server.",
"exclude_tags": "Use `server.disable(tags=...)` after creating the server.",
"tool_transformations": "Use `server.add_transform(ToolTransform(...))` after creating the server.",
}
Takes the most strict value if multiple are provided.
Delete this function when removing deprecated params.
"""
strictness_order: list[DuplicateBehavior] = ["error", "warn", "replace", "ignore"]
deprecated_values: list[DuplicateBehavior] = []
deprecated_params: list[tuple[str, DuplicateBehavior | None]] = [
("on_duplicate_tools", on_duplicate_tools),
("on_duplicate_resources", on_duplicate_resources),
("on_duplicate_prompts", on_duplicate_prompts),
]
for name, value in deprecated_params:
if value is not None:
if fastmcp.settings.deprecation_warnings:
warnings.warn(
f"{name} is deprecated, use on_duplicate instead",
DeprecationWarning,
stacklevel=4,
)
deprecated_values.append(value)
if on_duplicate is None and deprecated_values:
return min(deprecated_values, key=lambda x: strictness_order.index(x))
return on_duplicate or "warn"
def _check_removed_kwargs(kwargs: dict[str, Any]) -> None:
"""Raise helpful TypeErrors for kwargs removed in v3."""
for key in kwargs:
if key in _REMOVED_KWARGS:
raise TypeError(
f"FastMCP() no longer accepts `{key}`. {_REMOVED_KWARGS[key]}"
)
if kwargs:
raise TypeError(
f"FastMCP() got unexpected keyword argument(s): {', '.join(repr(k) for k in kwargs)}"
)
Transport = Literal["stdio", "http", "sse", "streamable-http"]
@ -232,45 +226,23 @@ class FastMCP(
middleware: Sequence[Middleware] | None = None,
providers: Sequence[Provider] | None = None,
lifespan: LifespanCallable | Lifespan | None = None,
mask_error_details: bool | None = None,
tools: Sequence[Tool | Callable[..., Any]] | None = None,
tool_serializer: ToolResultSerializerType | None = None,
include_tags: Collection[str] | None = None,
exclude_tags: Collection[str] | None = None,
on_duplicate: DuplicateBehavior | None = None,
mask_error_details: bool | None = None,
strict_input_validation: bool | None = None,
list_page_size: int | None = None,
tasks: bool | None = None,
session_state_store: AsyncKeyValue | None = None,
# ---
# --- DEPRECATED parameters ---
# ---
on_duplicate_tools: DuplicateBehavior | None = None,
on_duplicate_resources: DuplicateBehavior | None = None,
on_duplicate_prompts: DuplicateBehavior | None = None,
log_level: str | None = None,
debug: bool | None = None,
host: str | None = None,
port: int | None = None,
sse_path: str | None = None,
message_path: str | None = None,
streamable_http_path: str | None = None,
json_response: bool | None = None,
stateless_http: bool | None = None,
sampling_handler: SamplingHandler | None = None,
sampling_handler_behavior: Literal["always", "fallback"] | None = None,
tool_transformations: Mapping[str, ToolTransformConfig] | None = None,
**kwargs: Any,
):
_check_removed_kwargs(kwargs)
# Initialize Provider (sets up _transforms)
super().__init__()
# Resolve on_duplicate from deprecated params (delete when removing deprecation)
self._on_duplicate: DuplicateBehaviorSetting = _resolve_on_duplicate(
on_duplicate,
on_duplicate_tools,
on_duplicate_resources,
on_duplicate_prompts,
)
self._on_duplicate: DuplicateBehaviorSetting = on_duplicate or "warn"
# Resolve server default for background task support
self._support_tasks_by_default: bool = tasks if tasks is not None else False
@ -312,16 +284,6 @@ class FastMCP(
raise ValueError("list_page_size must be a positive integer")
self._list_page_size: int | None = list_page_size
if tool_serializer is not None and fastmcp.settings.deprecation_warnings:
warnings.warn(
"The `tool_serializer` parameter is deprecated. "
"Return ToolResult from your tools for full control over serialization. "
"See https://gofastmcp.com/servers/tools#custom-serialization for migration examples.",
DeprecationWarning,
stacklevel=2,
)
self._tool_serializer: Callable[[Any], str] | None = tool_serializer
# Handle Lifespan instances (they're callable) or regular lifespan functions
if lifespan is not None:
self._lifespan: LifespanCallable[LifespanResultT] = lifespan
@ -349,38 +311,9 @@ class FastMCP(
if tools:
for tool in tools:
if not isinstance(tool, Tool):
tool = Tool.from_function(tool, serializer=self._tool_serializer)
tool = Tool.from_function(tool)
self.add_tool(tool)
# Handle deprecated include_tags and exclude_tags parameters
if include_tags is not None:
warnings.warn(
"include_tags is deprecated. Use server.enable(tags=..., only=True) instead.",
DeprecationWarning,
stacklevel=2,
)
# For backwards compatibility, initialize allowlist from include_tags
self.enable(tags=set(include_tags), only=True)
if exclude_tags is not None:
warnings.warn(
"exclude_tags is deprecated. Use server.disable(tags=...) instead.",
DeprecationWarning,
stacklevel=2,
)
# For backwards compatibility, initialize blocklist from exclude_tags
self.disable(tags=set(exclude_tags))
# Handle deprecated tool_transformations parameter
if tool_transformations:
if fastmcp.settings.deprecation_warnings:
warnings.warn(
"The tool_transformations parameter is deprecated. Use "
"server.add_transform(ToolTransform({...})) instead.",
DeprecationWarning,
stacklevel=2,
)
self._transforms.append(ToolTransform(dict(tool_transformations)))
self.strict_input_validation: bool = (
strict_input_validation
if strict_input_validation is not None
@ -397,71 +330,9 @@ class FastMCP(
sampling_handler_behavior or "fallback"
)
self._handle_deprecated_settings(
log_level=log_level,
debug=debug,
host=host,
port=port,
sse_path=sse_path,
message_path=message_path,
streamable_http_path=streamable_http_path,
json_response=json_response,
stateless_http=stateless_http,
)
def __repr__(self) -> str:
return f"{type(self).__name__}({self.name!r})"
def _handle_deprecated_settings(
self,
log_level: str | None,
debug: bool | None,
host: str | None,
port: int | None,
sse_path: str | None,
message_path: str | None,
streamable_http_path: str | None,
json_response: bool | None,
stateless_http: bool | None,
) -> None:
"""Handle deprecated settings. Deprecated in 2.8.0."""
deprecated_settings: dict[str, Any] = {}
for name, arg in [
("log_level", log_level),
("debug", debug),
("host", host),
("port", port),
("sse_path", sse_path),
("message_path", message_path),
("streamable_http_path", streamable_http_path),
("json_response", json_response),
("stateless_http", stateless_http),
]:
if arg is not None:
# Deprecated in 2.8.0
if fastmcp.settings.deprecation_warnings:
warnings.warn(
f"Providing `{name}` when creating a server is deprecated. Provide it when calling `run` or as a global setting instead.",
DeprecationWarning,
stacklevel=2,
)
deprecated_settings[name] = arg
combined_settings = fastmcp.settings.model_dump() | deprecated_settings
self._deprecated_settings = Settings(**combined_settings)
@property
def settings(self) -> Settings:
# Deprecated in 2.8.0
if fastmcp.settings.deprecation_warnings:
warnings.warn(
"Accessing `.settings` on a FastMCP instance is deprecated. Use the global `fastmcp.settings` instead.",
DeprecationWarning,
stacklevel=2,
)
return self._deprecated_settings
@property
def name(self) -> str:
return self._mcp_server.name
@ -1530,7 +1401,6 @@ class FastMCP(
meta=meta,
task=task if task is not None else self._support_tasks_by_default,
timeout=timeout,
serializer=self._tool_serializer,
auth=auth,
)

View file

@ -2,7 +2,6 @@ from __future__ import annotations as _annotations
import inspect
import os
import warnings
from datetime import timedelta
from pathlib import Path
from typing import Annotated, Any, Literal
@ -115,30 +114,6 @@ class DocketSettings(BaseSettings):
] = timedelta(seconds=5)
class ExperimentalSettings(BaseSettings):
model_config = SettingsConfigDict(
env_prefix="FASTMCP_EXPERIMENTAL_",
extra="ignore",
validate_assignment=True,
)
# Deprecated in 2.14 - the new OpenAPI parser is now the default and only parser
enable_new_openapi_parser: bool = False
@field_validator("enable_new_openapi_parser", mode="after")
@classmethod
def _warn_openapi_parser_deprecated(cls, v: bool) -> bool:
if v:
warnings.warn(
"enable_new_openapi_parser is deprecated. "
"The new OpenAPI parser is now the default (and only) parser. "
"You can remove this setting.",
DeprecationWarning,
stacklevel=2,
)
return v
class Settings(BaseSettings):
"""FastMCP settings."""
@ -191,8 +166,6 @@ class Settings(BaseSettings):
return v.upper()
return v
experimental: ExperimentalSettings = ExperimentalSettings()
docket: DocketSettings = DocketSettings()
enable_rich_logging: Annotated[

View file

@ -1,68 +1,25 @@
"""Tests for deprecated include_tags/exclude_tags parameters."""
"""Tests for removed include_tags/exclude_tags parameters."""
import pytest
from fastmcp import FastMCP
from fastmcp.server.transforms.visibility import Visibility
class TestIncludeExcludeTagsDeprecation:
"""Test that include_tags/exclude_tags emit deprecation warnings but still work."""
class TestIncludeExcludeTagsRemoved:
"""Test that include_tags/exclude_tags raise TypeError with migration hints."""
def test_exclude_tags_emits_warning(self):
"""exclude_tags parameter emits deprecation warning."""
with pytest.warns(DeprecationWarning, match="exclude_tags.*deprecated"):
def test_exclude_tags_raises_type_error(self):
with pytest.raises(TypeError, match="no longer accepts `exclude_tags`"):
FastMCP(exclude_tags={"internal"})
def test_include_tags_emits_warning(self):
"""include_tags parameter emits deprecation warning."""
with pytest.warns(DeprecationWarning, match="include_tags.*deprecated"):
def test_include_tags_raises_type_error(self):
with pytest.raises(TypeError, match="no longer accepts `include_tags`"):
FastMCP(include_tags={"public"})
def test_exclude_tags_still_works(self):
"""exclude_tags adds a Visibility transform that disables matching tags."""
with pytest.warns(DeprecationWarning):
mcp = FastMCP(exclude_tags={"internal"})
def test_exclude_tags_error_mentions_disable(self):
with pytest.raises(TypeError, match="server.disable"):
FastMCP(exclude_tags={"internal"})
# Should have added a Visibility transform that disables the tag
enabled_transforms = [t for t in mcp._transforms if isinstance(t, Visibility)]
assert len(enabled_transforms) == 1
e = enabled_transforms[0]
assert e._enabled is False
assert e.tags == {"internal"}
def test_include_tags_still_works(self):
"""include_tags adds Visibility transforms for allowlist mode."""
with pytest.warns(DeprecationWarning):
mcp = FastMCP(include_tags={"public"})
# Should have added Visibility transforms for allowlist mode
# (one to disable all, one to enable matching)
enabled_transforms = [t for t in mcp._transforms if isinstance(t, Visibility)]
assert len(enabled_transforms) == 2
# First should disable all (Visibility.all(False))
disable_all_transform = enabled_transforms[0]
assert disable_all_transform._enabled is False
assert disable_all_transform.match_all is True
# Second should enable matching tags
enable_transform = enabled_transforms[1]
assert enable_transform._enabled is True
assert enable_transform.tags == {"public"}
def test_exclude_and_include_both_create_transforms(self):
"""exclude_tags and include_tags both create transforms."""
with pytest.warns(DeprecationWarning):
mcp = FastMCP(include_tags={"public"}, exclude_tags={"deprecated"})
# Should have added transforms for both
# include_tags creates 2 (disable all + enable matching)
# exclude_tags creates 1 (disable matching)
enabled_transforms = [t for t in mcp._transforms if isinstance(t, Visibility)]
assert len(enabled_transforms) == 3
# Check we have both tag rules
tags_in_transforms = [t.tags for t in enabled_transforms if t.tags]
assert {"public"} in tags_in_transforms
assert {"deprecated"} in tags_in_transforms
def test_include_tags_error_mentions_enable(self):
with pytest.raises(TypeError, match="server.enable"):
FastMCP(include_tags={"public"})

View file

@ -68,37 +68,12 @@ class TestAddToolTransformationDeprecated:
assert "remove_tool_transformation is deprecated" in str(w[0].message)
assert "no effect" in str(w[0].message)
async def test_tool_transformations_constructor_emits_warning(self):
"""tool_transformations constructor param should emit deprecation warning."""
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
async def test_tool_transformations_constructor_raises_type_error(self):
"""tool_transformations constructor param should raise TypeError."""
import pytest
with pytest.raises(TypeError, match="no longer accepts `tool_transformations`"):
FastMCP(
"test",
tool_transformations={"my_tool": ToolTransformConfig(name="renamed")},
)
assert len(w) == 1
assert issubclass(w[0].category, DeprecationWarning)
assert "tool_transformations parameter is deprecated" in str(w[0].message)
async def test_tool_transformations_constructor_still_works(self):
"""tool_transformations constructor param should still apply transforms."""
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
mcp = FastMCP(
"test",
tool_transformations={
"my_tool": ToolTransformConfig(name="renamed_tool")
},
)
@mcp.tool
def my_tool() -> str:
return "result"
async with Client(mcp) as client:
tools = await client.list_tools()
tool_names = [t.name for t in tools]
assert "my_tool" not in tool_names
assert "renamed_tool" in tool_names

View file

@ -1,48 +1,23 @@
import warnings
import pytest
from starlette.applications import Starlette
from fastmcp import FastMCP
from fastmcp.utilities.tests import temporary_settings
# reset deprecation warnings for this module
pytestmark = pytest.mark.filterwarnings("default::DeprecationWarning")
class TestDeprecationWarningsSetting:
def test_deprecation_warnings_setting_true(self):
with temporary_settings(deprecation_warnings=True):
with pytest.warns(DeprecationWarning) as recorded_warnings:
# will warn once for providing deprecated arg
mcp = FastMCP(host="1.2.3.4")
# will warn once for accessing deprecated property
mcp.settings
class TestRemovedKwargs:
def test_host_kwarg_raises_type_error(self):
with pytest.raises(TypeError, match="no longer accepts `host`"):
FastMCP(host="1.2.3.4")
assert len(recorded_warnings) == 2
def test_deprecation_warnings_setting_false(self):
with temporary_settings(deprecation_warnings=False):
# will error if a warning is raised
with warnings.catch_warnings():
warnings.simplefilter("error")
# will warn once for providing deprecated arg
mcp = FastMCP(host="1.2.3.4")
# will warn once for accessing deprecated property
mcp.settings
def test_settings_property_removed(self):
mcp = FastMCP()
assert not hasattr(mcp, "_deprecated_settings")
with pytest.raises(AttributeError):
mcp.settings # noqa: B018 # ty: ignore[unresolved-attribute]
def test_http_app_with_sse_transport():
"""Test that http_app with SSE transport works (no warning)."""
"""Test that http_app with SSE transport works."""
server = FastMCP("TestServer")
# This should not raise a warning since we're using the new API
with warnings.catch_warnings(record=True) as recorded_warnings:
app = server.http_app(transport="sse")
assert isinstance(app, Starlette)
# Verify no deprecation warnings were raised for using transport parameter
deprecation_warnings = [
w for w in recorded_warnings if issubclass(w.category, DeprecationWarning)
]
assert len(deprecation_warnings) == 0
app = server.http_app(transport="sse")
assert isinstance(app, Starlette)

View file

@ -5,34 +5,9 @@ import warnings
import pytest
import fastmcp
pytestmark = pytest.mark.filterwarnings("default::DeprecationWarning")
class TestEnableNewOpenAPIParserDeprecation:
"""Test enable_new_openapi_parser setting deprecation."""
def test_setting_true_emits_warning(self):
"""Setting enable_new_openapi_parser=True should emit deprecation warning."""
with pytest.warns(
DeprecationWarning,
match=r"enable_new_openapi_parser is deprecated.*now the default",
):
fastmcp.settings.experimental.enable_new_openapi_parser = True
def test_setting_false_no_warning(self):
"""Setting enable_new_openapi_parser=False should not emit warning."""
with warnings.catch_warnings(record=True) as recorded:
warnings.simplefilter("always")
fastmcp.settings.experimental.enable_new_openapi_parser = False
deprecation_warnings = [
w for w in recorded if issubclass(w.category, DeprecationWarning)
]
assert len(deprecation_warnings) == 0
class TestExperimentalOpenAPIImportDeprecation:
"""Test experimental OpenAPI import path deprecations."""

View file

@ -1,319 +1,64 @@
import warnings
from unittest.mock import patch
import pytest
from fastmcp import FastMCP
# reset deprecation warnings for this module
pytestmark = pytest.mark.filterwarnings("default::DeprecationWarning")
class TestRemovedServerInitKwargs:
"""Test that removed server initialization keyword arguments raise TypeError."""
class TestDeprecatedServerInitKwargs:
"""Test deprecated server initialization keyword arguments."""
@pytest.mark.parametrize(
"kwarg, value, expected_message",
[
("host", "0.0.0.0", "run_http_async"),
("port", 8080, "run_http_async"),
("sse_path", "/custom-sse", "FASTMCP_SSE_PATH"),
("message_path", "/custom-message", "FASTMCP_MESSAGE_PATH"),
("streamable_http_path", "/custom-http", "run_http_async"),
("json_response", True, "run_http_async"),
("stateless_http", True, "run_http_async"),
("debug", True, "FASTMCP_DEBUG"),
("log_level", "DEBUG", "run_http_async"),
("on_duplicate_tools", "warn", "on_duplicate="),
("on_duplicate_resources", "error", "on_duplicate="),
("on_duplicate_prompts", "replace", "on_duplicate="),
("tool_serializer", lambda x: str(x), "ToolResult"),
("include_tags", {"public"}, "server.enable"),
("exclude_tags", {"internal"}, "server.disable"),
(
"tool_transformations",
{"my_tool": {"name": "renamed"}},
"server.add_transform",
),
],
)
def test_removed_kwarg_raises_type_error(self, kwarg, value, expected_message):
with pytest.raises(TypeError, match=f"no longer accepts `{kwarg}`"):
FastMCP("TestServer", **{kwarg: value})
def test_log_level_deprecation_warning(self):
"""Test that log_level raises a deprecation warning."""
with pytest.warns(
DeprecationWarning,
match=r"Providing `log_level` when creating a server is deprecated\. Provide it when calling `run` or as a global setting instead\.",
):
server = FastMCP("TestServer", log_level="DEBUG")
@pytest.mark.parametrize(
"kwarg, value, expected_message",
[
("host", "0.0.0.0", "run_http_async"),
("on_duplicate_tools", "warn", "on_duplicate="),
("include_tags", {"public"}, "server.enable"),
],
)
def test_removed_kwarg_error_includes_migration_hint(
self, kwarg, value, expected_message
):
with pytest.raises(TypeError, match=expected_message):
FastMCP("TestServer", **{kwarg: value})
# Verify the setting is still applied
assert server._deprecated_settings.log_level == "DEBUG"
def test_unknown_kwarg_raises_standard_type_error(self):
with pytest.raises(TypeError, match="unexpected keyword argument"):
FastMCP("TestServer", **{"totally_fake_param": True}) # ty: ignore[invalid-argument-type]
def test_debug_deprecation_warning(self):
"""Test that debug raises a deprecation warning."""
with pytest.warns(
DeprecationWarning,
match=r"Providing `debug` when creating a server is deprecated\. Provide it when calling `run` or as a global setting instead\.",
):
server = FastMCP("TestServer", debug=True)
# Verify the setting is still applied
assert server._deprecated_settings.debug is True
def test_host_deprecation_warning(self):
"""Test that host raises a deprecation warning."""
with pytest.warns(
DeprecationWarning,
match=r"Providing `host` when creating a server is deprecated\. Provide it when calling `run` or as a global setting instead\.",
):
server = FastMCP("TestServer", host="0.0.0.0")
# Verify the setting is still applied
assert server._deprecated_settings.host == "0.0.0.0"
def test_port_deprecation_warning(self):
"""Test that port raises a deprecation warning."""
with pytest.warns(
DeprecationWarning,
match=r"Providing `port` when creating a server is deprecated\. Provide it when calling `run` or as a global setting instead\.",
):
server = FastMCP("TestServer", port=8080)
# Verify the setting is still applied
assert server._deprecated_settings.port == 8080
def test_sse_path_deprecation_warning(self):
"""Test that sse_path raises a deprecation warning."""
with pytest.warns(
DeprecationWarning,
match=r"Providing `sse_path` when creating a server is deprecated\. Provide it when calling `run` or as a global setting instead\.",
):
server = FastMCP("TestServer", sse_path="/custom-sse")
# Verify the setting is still applied
assert server._deprecated_settings.sse_path == "/custom-sse"
def test_message_path_deprecation_warning(self):
"""Test that message_path raises a deprecation warning."""
with pytest.warns(
DeprecationWarning,
match=r"Providing `message_path` when creating a server is deprecated\. Provide it when calling `run` or as a global setting instead\.",
):
server = FastMCP("TestServer", message_path="/custom-message")
# Verify the setting is still applied
assert server._deprecated_settings.message_path == "/custom-message"
def test_streamable_http_path_deprecation_warning(self):
"""Test that streamable_http_path raises a deprecation warning."""
with pytest.warns(
DeprecationWarning,
match=r"Providing `streamable_http_path` when creating a server is deprecated\. Provide it when calling `run` or as a global setting instead\.",
):
server = FastMCP("TestServer", streamable_http_path="/custom-http")
# Verify the setting is still applied
assert server._deprecated_settings.streamable_http_path == "/custom-http"
def test_json_response_deprecation_warning(self):
"""Test that json_response raises a deprecation warning."""
with pytest.warns(
DeprecationWarning,
match=r"Providing `json_response` when creating a server is deprecated\. Provide it when calling `run` or as a global setting instead\.",
):
server = FastMCP("TestServer", json_response=True)
# Verify the setting is still applied
assert server._deprecated_settings.json_response is True
def test_stateless_http_deprecation_warning(self):
"""Test that stateless_http raises a deprecation warning."""
with pytest.warns(
DeprecationWarning,
match=r"Providing `stateless_http` when creating a server is deprecated\. Provide it when calling `run` or as a global setting instead\.",
):
server = FastMCP("TestServer", stateless_http=True)
# Verify the setting is still applied
assert server._deprecated_settings.stateless_http is True
def test_multiple_deprecated_kwargs_warnings(self):
"""Test that multiple deprecated kwargs each raise their own warning."""
with warnings.catch_warnings(record=True) as recorded_warnings:
warnings.simplefilter("always")
server = FastMCP(
"TestServer",
log_level="INFO",
debug=False,
host="127.0.0.1",
port=9999,
sse_path="/sse/",
message_path="/msg",
streamable_http_path="/http",
json_response=False,
stateless_http=False,
)
# Should have 9 deprecation warnings (one for each deprecated parameter)
deprecation_warnings = [
w for w in recorded_warnings if issubclass(w.category, DeprecationWarning)
]
assert len(deprecation_warnings) == 9
# Verify all expected parameters are mentioned in warnings
expected_params = {
"log_level",
"debug",
"host",
"port",
"sse_path",
"message_path",
"streamable_http_path",
"json_response",
"stateless_http",
}
mentioned_params = set()
for warning in deprecation_warnings:
message = str(warning.message)
for param in expected_params:
if f"Providing `{param}`" in message:
mentioned_params.add(param)
assert mentioned_params == expected_params
# Verify all settings are still applied
assert server._deprecated_settings.log_level == "INFO"
assert server._deprecated_settings.debug is False
assert server._deprecated_settings.host == "127.0.0.1"
assert server._deprecated_settings.port == 9999
assert server._deprecated_settings.sse_path == "/sse/"
assert server._deprecated_settings.message_path == "/msg"
assert server._deprecated_settings.streamable_http_path == "/http"
assert server._deprecated_settings.json_response is False
assert server._deprecated_settings.stateless_http is False
def test_non_deprecated_kwargs_no_warnings(self):
"""Test that non-deprecated kwargs don't raise warnings."""
with warnings.catch_warnings(record=True) as recorded_warnings:
warnings.simplefilter("always")
server = FastMCP(
name="TestServer",
instructions="Test instructions",
on_duplicate="warn", # New unified parameter
mask_error_details=True,
)
# Should have no deprecation warnings
deprecation_warnings = [
w for w in recorded_warnings if issubclass(w.category, DeprecationWarning)
]
assert len(deprecation_warnings) == 0
# Verify server was created successfully
def test_valid_kwargs_still_work(self):
server = FastMCP(
name="TestServer",
instructions="Test instructions",
on_duplicate="warn",
mask_error_details=True,
)
assert server.name == "TestServer"
assert server.instructions == "Test instructions"
def test_deprecated_duplicate_kwargs_raise_warnings(self):
"""Test that deprecated on_duplicate_* kwargs raise warnings."""
with warnings.catch_warnings(record=True) as recorded_warnings:
warnings.simplefilter("always")
FastMCP(
name="TestServer",
on_duplicate_tools="warn",
on_duplicate_resources="error",
on_duplicate_prompts="replace",
)
# Should have 3 deprecation warnings (one for each deprecated param)
deprecation_warnings = [
w for w in recorded_warnings if issubclass(w.category, DeprecationWarning)
]
assert len(deprecation_warnings) == 3
# Check warning messages
warning_messages = [str(w.message) for w in deprecation_warnings]
assert any("on_duplicate_tools" in msg for msg in warning_messages)
assert any("on_duplicate_resources" in msg for msg in warning_messages)
assert any("on_duplicate_prompts" in msg for msg in warning_messages)
def test_none_values_no_warnings(self):
"""Test that None values for deprecated kwargs don't raise warnings."""
with warnings.catch_warnings(record=True) as recorded_warnings:
warnings.simplefilter("always")
FastMCP(
"TestServer",
log_level=None,
debug=None,
host=None,
port=None,
sse_path=None,
message_path=None,
streamable_http_path=None,
json_response=None,
stateless_http=None,
)
# Should have no deprecation warnings for None values
deprecation_warnings = [
w for w in recorded_warnings if issubclass(w.category, DeprecationWarning)
]
assert len(deprecation_warnings) == 0
def test_deprecated_settings_inheritance_from_global(self):
"""Test that deprecated settings inherit from global settings when not provided."""
# Mock fastmcp.settings to test inheritance
with patch("fastmcp.settings") as mock_settings:
mock_settings.model_dump.return_value = {
"log_level": "WARNING",
"debug": True,
"host": "0.0.0.0",
"port": 3000,
"sse_path": "/events",
"message_path": "/messages",
"streamable_http_path": "/stream",
"json_response": True,
"stateless_http": True,
}
server = FastMCP("TestServer")
# Verify settings are inherited from global settings
assert server._deprecated_settings.log_level == "WARNING"
assert server._deprecated_settings.debug is True
assert server._deprecated_settings.host == "0.0.0.0"
assert server._deprecated_settings.port == 3000
assert server._deprecated_settings.sse_path == "/events"
assert server._deprecated_settings.message_path == "/messages"
assert server._deprecated_settings.streamable_http_path == "/stream"
assert server._deprecated_settings.json_response is True
assert server._deprecated_settings.stateless_http is True
def test_deprecated_settings_override_global(self):
"""Test that deprecated settings override global settings when provided."""
# Mock fastmcp.settings to test override behavior
with patch("fastmcp.settings") as mock_settings:
mock_settings.model_dump.return_value = {
"log_level": "WARNING",
"debug": True,
"host": "0.0.0.0",
"port": 3000,
"sse_path": "/events",
"message_path": "/messages",
"streamable_http_path": "/stream",
"json_response": True,
"stateless_http": True,
}
with warnings.catch_warnings():
warnings.simplefilter("ignore") # Ignore warnings for this test
server = FastMCP(
"TestServer",
log_level="ERROR",
debug=False,
host="127.0.0.1",
port=8080,
)
# Verify provided settings override global settings
assert server._deprecated_settings.log_level == "ERROR"
assert server._deprecated_settings.debug is False
assert server._deprecated_settings.host == "127.0.0.1"
assert server._deprecated_settings.port == 8080
# Non-overridden settings should still come from global
assert server._deprecated_settings.sse_path == "/events"
assert server._deprecated_settings.message_path == "/messages"
assert server._deprecated_settings.streamable_http_path == "/stream"
assert server._deprecated_settings.json_response is True
assert server._deprecated_settings.stateless_http is True
def test_stacklevel_points_to_constructor_call(self):
"""Test that deprecation warnings point to the FastMCP constructor call."""
with warnings.catch_warnings(record=True) as recorded_warnings:
warnings.simplefilter("always")
FastMCP("TestServer", log_level="DEBUG")
# Should have exactly one deprecation warning
deprecation_warnings = [
w for w in recorded_warnings if issubclass(w.category, DeprecationWarning)
]
assert len(deprecation_warnings) == 1
# The warning should point to the server.py file where FastMCP.__init__ is called
# This verifies the stacklevel is working as intended (pointing to constructor)
warning = deprecation_warnings[0]
assert "server.py" in warning.filename

View file

@ -143,15 +143,14 @@ class TestSerializerDeprecationWarnings:
with pytest.warns(DeprecationWarning, match="serializer.*deprecated"):
provider.tool(my_tool, serializer=custom_serializer)
def test_fastmcp_tool_serializer_parameter_warning(self):
"""Test that FastMCP tool_serializer parameter warns."""
def test_fastmcp_tool_serializer_parameter_raises_type_error(self):
"""Test that FastMCP tool_serializer parameter raises TypeError."""
def custom_serializer(data) -> str:
return f"Custom: {data}"
with temporary_settings(deprecation_warnings=True):
with pytest.warns(DeprecationWarning, match="tool_serializer.*deprecated"):
FastMCP("TestServer", tool_serializer=custom_serializer)
with pytest.raises(TypeError, match="no longer accepts `tool_serializer`"):
FastMCP("TestServer", tool_serializer=custom_serializer)
def test_transformed_tool_from_tool_serializer_warning(self):
"""Test that TransformedTool.from_tool warns when serializer is provided."""

View file

@ -11,7 +11,8 @@ class TestParentTagFiltering:
async def test_parent_include_tags_filters_mounted_tools(self):
"""Test that parent include_tags filters out non-matching mounted tools."""
parent = FastMCP("Parent", include_tags={"allowed"})
parent = FastMCP("Parent")
parent.enable(tags={"allowed"}, only=True)
mounted = FastMCP("Mounted")
@mounted.tool(tags={"allowed"})
@ -38,7 +39,8 @@ class TestParentTagFiltering:
async def test_parent_exclude_tags_filters_mounted_tools(self):
"""Test that parent exclude_tags filters out matching mounted tools."""
parent = FastMCP("Parent", exclude_tags={"blocked"})
parent = FastMCP("Parent")
parent.disable(tags={"blocked"})
mounted = FastMCP("Mounted")
@mounted.tool(tags={"production"})
@ -58,7 +60,8 @@ class TestParentTagFiltering:
async def test_parent_filters_apply_to_mounted_resources(self):
"""Test that parent tag filters apply to mounted resources."""
parent = FastMCP("Parent", include_tags={"allowed"})
parent = FastMCP("Parent")
parent.enable(tags={"allowed"}, only=True)
mounted = FastMCP("Mounted")
@mounted.resource("resource://allowed", tags={"allowed"})
@ -78,7 +81,8 @@ class TestParentTagFiltering:
async def test_parent_filters_apply_to_mounted_prompts(self):
"""Test that parent tag filters apply to mounted prompts."""
parent = FastMCP("Parent", exclude_tags={"blocked"})
parent = FastMCP("Parent")
parent.disable(tags={"blocked"})
mounted = FastMCP("Mounted")
@mounted.prompt(tags={"allowed"})

View file

@ -40,7 +40,7 @@ class PersonDataclass:
class TestToolTags:
def create_server(self, include_tags=None, exclude_tags=None):
mcp = FastMCP(include_tags=include_tags, exclude_tags=exclude_tags)
mcp = FastMCP()
@mcp.tool(tags={"a", "b"})
def tool_1() -> int:
@ -50,6 +50,11 @@ class TestToolTags:
def tool_2() -> int:
return 2
if include_tags:
mcp.enable(tags=include_tags, only=True)
if exclude_tags:
mcp.disable(tags=exclude_tags)
return mcp
async def test_include_tags_all_tools(self):

View file

@ -415,7 +415,7 @@ class TestPromptEnabled:
class TestPromptTags:
def create_server(self, include_tags=None, exclude_tags=None):
mcp = FastMCP(include_tags=include_tags, exclude_tags=exclude_tags)
mcp = FastMCP()
@mcp.prompt(tags={"a", "b"})
def prompt_1() -> str:
@ -425,6 +425,11 @@ class TestPromptTags:
def prompt_2() -> str:
return "2"
if include_tags:
mcp.enable(tags=include_tags, only=True)
if exclude_tags:
mcp.disable(tags=exclude_tags)
return mcp
async def test_include_tags_all_prompts(self):

View file

@ -676,7 +676,7 @@ class TestTemplateDecorator:
class TestResourceTags:
def create_server(self, include_tags=None, exclude_tags=None):
mcp = FastMCP(include_tags=include_tags, exclude_tags=exclude_tags)
mcp = FastMCP()
@mcp.resource("resource://1", tags={"a", "b"})
def resource_1() -> str:
@ -686,6 +686,11 @@ class TestResourceTags:
def resource_2() -> str:
return "2"
if include_tags:
mcp.enable(tags=include_tags, only=True)
if exclude_tags:
mcp.disable(tags=exclude_tags)
return mcp
async def test_include_tags_all_resources(self):
@ -823,7 +828,7 @@ class TestResourceEnabled:
class TestResourceTemplatesTags:
def create_server(self, include_tags=None, exclude_tags=None):
mcp = FastMCP(include_tags=include_tags, exclude_tags=exclude_tags)
mcp = FastMCP()
@mcp.resource("resource://1/{param}", tags={"a", "b"})
def template_resource_1(param: str) -> str:
@ -833,6 +838,11 @@ class TestResourceTemplatesTags:
def template_resource_2(param: str) -> str:
return f"Template resource 2: {param}"
if include_tags:
mcp.enable(tags=include_tags, only=True)
if exclude_tags:
mcp.disable(tags=exclude_tags)
return mcp
async def test_include_tags_all_resources(self):

View file

@ -211,9 +211,9 @@ class TestAbstractCollectionTypes:
"test",
middleware=(), # Empty tuple
tools=(Tool.from_function(dummy_tool),), # Tuple of tools
include_tags={"tag1", "tag2"}, # Set
exclude_tags={"tag3"}, # Set
)
mcp.enable(tags={"tag1", "tag2"}, only=True)
mcp.disable(tags={"tag3"})
assert mcp is not None
assert mcp.name == "test"
assert isinstance(mcp.middleware, list) # Should be converted to list

View file

@ -281,10 +281,8 @@ class TestGetFastMCPInfo:
components weren't actually available to clients.
"""
# Create server with include_tags that will filter out untagged components
mcp = FastMCP(
"FilteredServer",
include_tags={"fetch", "analyze", "create"},
)
mcp = FastMCP("FilteredServer")
mcp.enable(tags={"fetch", "analyze", "create"}, only=True)
# Add tools with and without matching tags
@mcp.tool(tags={"fetch"})
@ -396,7 +394,8 @@ class TestGetFastMCPInfo:
return [{"role": "user", "content": "blocked"}]
# Create parent server with tag filtering
parent = FastMCP("ParentServer", include_tags={"allowed"})
parent = FastMCP("ParentServer")
parent.enable(tags={"allowed"}, only=True)
parent.mount(mounted)
# Get inspect info
@ -448,7 +447,8 @@ class TestGetFastMCPInfo:
return "untagged"
# Create parent with exclude_tags - should filter mounted components
parent = FastMCP("ParentServer", exclude_tags={"development"})
parent = FastMCP("ParentServer")
parent.disable(tags={"development"})
parent.mount(mounted)
# Get inspect info