Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/changelog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1234,7 +1234,7 @@ This release introduces completely new tools for generating and customizing MCP

## [v2.4.0: Config and Conquer](https://github.com/jlowin/fastmcp/releases/tag/v2.4.0)

**Note**: this release includes a backwards-incompatible change to how resources are prefixed when mounted in composed servers. However, it is only backwards-incompatible if users were running tests or manually loading resources by prefixed key; LLMs should not have any issue discovering the new route. See [Resource Prefix Formats](https://gofastmcp.com/servers/composition#resource-prefix-formats) for more.
**Note**: this release includes a backwards-incompatible change to how resources are prefixed when mounted in composed servers. However, it is only backwards-incompatible if users were running tests or manually loading resources by prefixed key; LLMs should not have any issue discovering the new route.

### New Features 🎉

Expand Down
1 change: 0 additions & 1 deletion docs/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,6 @@
"python-sdk/fastmcp-server-auth-providers-auth0",
"python-sdk/fastmcp-server-auth-providers-aws",
"python-sdk/fastmcp-server-auth-providers-azure",
"python-sdk/fastmcp-server-auth-providers-bearer",
"python-sdk/fastmcp-server-auth-providers-debug",
"python-sdk/fastmcp-server-auth-providers-descope",
"python-sdk/fastmcp-server-auth-providers-github",
Expand Down
13 changes: 0 additions & 13 deletions docs/python-sdk/fastmcp-server-auth-providers-bearer.mdx

This file was deleted.

6 changes: 0 additions & 6 deletions docs/python-sdk/fastmcp-server-server.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -723,12 +723,6 @@ Create a Starlette app using the specified HTTP transport.
- A Starlette application configured with the specified transport


#### `run_streamable_http_async` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2190" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>

```python
run_streamable_http_async(self, host: str | None = None, port: int | None = None, log_level: str | None = None, path: str | None = None, uvicorn_config: dict[str, Any] | None = None) -> None
```

#### `mount` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/server.py#L2215" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>

```python
Expand Down
65 changes: 5 additions & 60 deletions docs/servers/composition.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ FastMCP supports [MCP proxying](/servers/proxy), which allows you to mirror a lo

You can also create proxies from configuration dictionaries that follow the MCPConfig schema, which is useful for quickly connecting to one or more remote servers. See the [Proxy Servers documentation](/servers/proxy#configuration-based-proxies) for details on configuration-based proxying. Note that MCPConfig follows an emerging standard and its format may evolve over time.

Prefixing rules for tools, prompts, resources, and templates are identical across importing, mounting, and proxies.
Prefixing rules for tools, prompts, resources, and templates are identical across importing, mounting, and proxies. When prefixes are used, resource URIs are prefixed using path format (since 2.4.0): `resource://prefix/path/to/resource`.

## Importing (Static Composition)

Expand Down Expand Up @@ -207,6 +207,10 @@ The same prefixing rules apply as with `import_server` for naming tools, resourc
The `prefix` parameter is optional. If omitted, components are mounted without modification.
</Tip>

<Note>
When mounting servers, custom HTTP routes defined with `@server.custom_route()` are also forwarded to the parent server, making them accessible through the parent's HTTP application.
</Note>

#### Performance Considerations

Due to the "live link", operations like `list_tools()` on the parent server will be impacted by the speed of the slowest mounted server. In particular, HTTP-based mounted servers can introduce significant latency (300-400ms vs 1-2ms for local tools), and this slowdown affects the whole server, not just interactions with the HTTP-proxied tools. If performance is important, importing tools via [`import_server()`](#importing-static-composition) may be a more appropriate solution as it copies components once at startup rather than delegating requests at runtime.
Expand Down Expand Up @@ -320,62 +324,3 @@ This ensures that parent server tag policies act as a global policy for everythi
<Note>
This filtering applies to both **listing** (e.g., `list_tools()`) and **execution** (e.g., `call_tool()`). Filtered components are neither visible nor executable through the parent server.
</Note>

## Resource Prefix Formats

<VersionBadge version="2.4.0" />

When mounting or importing servers, resource URIs are usually prefixed to avoid naming conflicts. FastMCP supports two different formats for resource prefixes:

### Path Format (Default)

In path format, prefixes are added to the path component of the URI:

```
resource://prefix/path/to/resource
```

This is the default format since FastMCP 2.4. This format is recommended because it avoids issues with URI protocol restrictions (like underscores not being allowed in protocol names).

### Protocol Format (Legacy)

In protocol format, prefixes are added as part of the protocol:

```
prefix+resource://path/to/resource
```

This was the default format in FastMCP before 2.4. While still supported, it's not recommended for new code as it can cause problems with prefix names that aren't valid in URI protocols.

### Configuring the Prefix Format

You can configure the prefix format globally in code:

```python
import fastmcp
fastmcp.settings.resource_prefix_format = "protocol"
```

Or via environment variable:

```bash
FASTMCP_RESOURCE_PREFIX_FORMAT=protocol
```

Or per-server:

```python
from fastmcp import FastMCP

# Create a server that uses legacy protocol format
server = FastMCP("LegacyServer", resource_prefix_format="protocol")

# Create a server that uses new path format
server = FastMCP("NewServer", resource_prefix_format="path")
```

When mounting or importing servers, the prefix format of the parent server is used.

<Note>
When mounting servers, custom HTTP routes defined with `@server.custom_route()` are also forwarded to the parent server, making them accessible through the parent's HTTP application.
</Note>
3 changes: 0 additions & 3 deletions docs/servers/proxy.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -266,8 +266,6 @@ These rules apply uniformly whether you:
- Create a multi-server proxy from an `MCPConfig`
- Use `FastMCP.as_proxy()` directly

For resource URI prefix formats (path vs legacy protocol style) and configuration options, see Server Composition → Resource Prefix Formats.

## Mirrored Components

<VersionBadge version="2.10.5" />
Expand Down Expand Up @@ -317,7 +315,6 @@ proxy = FastMCPProxy(client_factory=create_client)

### Parameters

- **`client`**: **[DEPRECATED]** A `Client` instance. Use `client_factory` instead for explicit session management.
- **`client_factory`**: A callable that returns a `Client` instance when called. This gives you full control over session creation and reuse strategies.

### Explicit Session Management
Expand Down
3 changes: 0 additions & 3 deletions docs/servers/server.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -357,15 +357,13 @@ import fastmcp
# Access global settings
print(fastmcp.settings.log_level) # Default: "INFO"
print(fastmcp.settings.mask_error_details) # Default: False
print(fastmcp.settings.resource_prefix_format) # Default: "path"
print(fastmcp.settings.strict_input_validation) # Default: False
print(fastmcp.settings.include_fastmcp_meta) # Default: True
```

Common global settings include:
- **`log_level`**: Logging level ("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"), set with `FASTMCP_LOG_LEVEL`
- **`mask_error_details`**: Whether to hide detailed error information from clients, set with `FASTMCP_MASK_ERROR_DETAILS`
- **`resource_prefix_format`**: How to format resource prefixes ("path" or "protocol"), set with `FASTMCP_RESOURCE_PREFIX_FORMAT`
- **`strict_input_validation`**: Controls tool input validation mode (default: False for flexible coercion), set with `FASTMCP_STRICT_INPUT_VALIDATION`. See [Input Validation Modes](/servers/tools#input-validation-modes)
- **`include_fastmcp_meta`**: Whether to include FastMCP metadata in component responses (default: True), set with `FASTMCP_INCLUDE_FASTMCP_META`
- **`env_file`**: Path to the environment file to load settings from (default: ".env"), set with `FASTMCP_ENV_FILE`. Useful when your project uses a `.env` file with syntax incompatible with python-dotenv
Expand Down Expand Up @@ -399,7 +397,6 @@ Global FastMCP settings can be configured via environment variables (prefixed wi
# Configure global FastMCP behavior
export FASTMCP_LOG_LEVEL=DEBUG
export FASTMCP_MASK_ERROR_DETAILS=True
export FASTMCP_RESOURCE_PREFIX_FORMAT=protocol
export FASTMCP_STRICT_INPUT_VALIDATION=False
export FASTMCP_INCLUDE_FASTMCP_META=False
```
Expand Down
11 changes: 2 additions & 9 deletions examples/memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,8 @@
DEFAULT_LLM_MODEL = "openai:gpt-4o"
DEFAULT_EMBEDDING_MODEL = "text-embedding-3-small"

mcp = FastMCP(
"memory",
dependencies=[
"pydantic-ai-slim[openai]",
"asyncpg",
"numpy",
"pgvector",
],
)
# Dependencies are configured in memory.fastmcp.json
mcp = FastMCP("memory")

DB_DSN = "postgresql://postgres:postgres@localhost:54320/memory_db"
# reset memory by deleting the profile directory
Expand Down
7 changes: 6 additions & 1 deletion examples/screenshot.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# /// script
# dependencies = ["pyautogui", "Pillow", "fastmcp"]
# ///

"""
FastMCP Screenshot Example

Expand All @@ -10,7 +14,8 @@
from fastmcp.utilities.types import Image

# Create server
mcp = FastMCP("Screenshot Demo", dependencies=["pyautogui", "Pillow"])
# Dependencies are configured in screenshot.fastmcp.json
mcp = FastMCP("Screenshot Demo")


@mcp.tool
Expand Down
15 changes: 9 additions & 6 deletions examples/smart_home/src/smart_home/lights/server.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# /// script
# dependencies = [
# "smart_home@git+https://github.com/jlowin/fastmcp.git#subdirectory=examples/smart_home",
# "fastmcp",
# ]
# ///

from typing import Annotated, Any, Literal, TypedDict

from phue2.exceptions import PhueException
Expand Down Expand Up @@ -35,12 +42,8 @@ class HueAttributes(TypedDict, total=False):
transitiontime: NotRequired[Annotated[int, Field(description="deciseconds")]]


lights_mcp = FastMCP(
"Hue Lights Service (phue2)",
dependencies=[
"smart_home@git+https://github.com/jlowin/fastmcp.git#subdirectory=examples/smart_home",
],
)
# Dependencies are configured in lights.fastmcp.json
lights_mcp = FastMCP("Hue Lights Service (phue2)")


@lights_mcp.tool
Expand Down
20 changes: 0 additions & 20 deletions src/fastmcp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,26 +27,6 @@
warnings.simplefilter("default", DeprecationWarning)


def __getattr__(name: str):
"""
Used to deprecate the module-level Image class; can be removed once it is no longer imported to root.
"""
if name == "Image":
# Deprecated in 2.8.1
if settings.deprecation_warnings:
warnings.warn(
"The top-level `fastmcp.Image` import is deprecated "
"and will be removed in a future version. "
"Please use `fastmcp.utilities.types.Image` instead.",
DeprecationWarning,
stacklevel=2,
)
from fastmcp.utilities.types import Image

return Image
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")


__all__ = [
"Client",
"Context",
Expand Down
22 changes: 1 addition & 21 deletions src/fastmcp/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import fastmcp
from fastmcp.cli import run as run_module
from fastmcp.cli.install import install_app
from fastmcp.server.server import FastMCP
from fastmcp.utilities.cli import is_already_in_uv_subprocess, load_and_merge_config
from fastmcp.utilities.inspect import (
InspectFormat,
Expand All @@ -28,7 +27,6 @@
)
from fastmcp.utilities.logging import get_logger
from fastmcp.utilities.mcp_server_config import MCPServerConfig
from fastmcp.utilities.mcp_server_config.v1.environments.uv import UVEnvironment

logger = get_logger("cli")
console = Console()
Expand Down Expand Up @@ -224,29 +222,11 @@ async def dev(
)

try:
# Load server to check for deprecated dependencies
if not config:
logger.error("No configuration available")
sys.exit(1)
assert config is not None # For type checker
server: FastMCP = await config.source.load_server()
if server.dependencies:
import warnings

warnings.warn(
f"Server '{server.name}' uses deprecated 'dependencies' parameter (deprecated in FastMCP 2.11.4). "
"Please migrate to fastmcp.json configuration file. "
"See https://gofastmcp.com/docs/deployment/server-configuration for details.",
DeprecationWarning,
stacklevel=2,
)
# Merge server dependencies with environment dependencies
env_deps = config.environment.dependencies or []
all_deps = list(set(env_deps + server.dependencies))
if not config.environment:
config.environment = UVEnvironment(dependencies=all_deps)
else:
config.environment.dependencies = all_deps
await config.source.load_server()

env_vars = {}
if ui_port:
Expand Down
15 changes: 0 additions & 15 deletions src/fastmcp/cli/install/shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,21 +105,6 @@ async def process_common_args(
)
name = file.stem

# Get server dependencies if available
# TODO: Remove dependencies handling (deprecated in v2.11.4)
server_dependencies = getattr(server, "dependencies", []) if server else []
if server_dependencies:
import warnings

warnings.warn(
"Server uses deprecated 'dependencies' parameter (deprecated in FastMCP 2.11.4). "
"Please migrate to fastmcp.json configuration file. "
"See https://gofastmcp.com/docs/deployment/server-configuration for details.",
DeprecationWarning,
stacklevel=2,
)
with_packages = list(set(with_packages + server_dependencies))

# Process environment variables if provided
env_dict: dict[str, str] | None = None
if env_file or env_vars:
Expand Down
24 changes: 4 additions & 20 deletions src/fastmcp/contrib/component_manager/component_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,16 +105,8 @@ async def _enable_resource(self, key: str) -> Resource | ResourceTemplate:
# 2. Check mounted servers using the filtered protocol path.
for mounted in reversed(self._server._mounted_servers):
if mounted.prefix:
if has_resource_prefix(
key,
mounted.prefix,
mounted.resource_prefix_format,
):
key = remove_resource_prefix(
key,
mounted.prefix,
mounted.resource_prefix_format,
)
if has_resource_prefix(key, mounted.prefix):
key = remove_resource_prefix(key, mounted.prefix)
mounted_service = ComponentService(mounted.server)
mounted_resource: (
Resource | ResourceTemplate
Expand Down Expand Up @@ -148,16 +140,8 @@ async def _disable_resource(self, key: str) -> Resource | ResourceTemplate:
# 2. Check mounted servers using the filtered protocol path.
for mounted in reversed(self._server._mounted_servers):
if mounted.prefix:
if has_resource_prefix(
key,
mounted.prefix,
mounted.resource_prefix_format,
):
key = remove_resource_prefix(
key,
mounted.prefix,
mounted.resource_prefix_format,
)
if has_resource_prefix(key, mounted.prefix):
key = remove_resource_prefix(key, mounted.prefix)
mounted_service = ComponentService(mounted.server)
mounted_resource: (
Resource | ResourceTemplate
Expand Down
9 changes: 0 additions & 9 deletions src/fastmcp/server/auth/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,3 @@
"StaticTokenVerifier",
"TokenVerifier",
]


def __getattr__(name: str):
# Defer import because it raises a deprecation warning
if name == "BearerAuthProvider":
from .providers.bearer import BearerAuthProvider

return BearerAuthProvider
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
Loading
Loading