mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-15 01:59:10 +02:00
Replace tool timeout parameter with Docket's native Timeout dependency. Components declaring Docket deps (Timeout, Retry, etc.) are now: - Registered with Docket at startup - Auto-routed through Docket even for foreground calls Known limitations to discuss: - Context not available in Docket workers - Registration bug: register_with_docket still checks supports_tasks() - Error propagation: ToolError wrapped in McpError - Performance: every call goes through Redis+worker
250 lines
6 KiB
Text
250 lines
6 KiB
Text
---
|
|
title: Upgrade Guide
|
|
sidebarTitle: Upgrade Guide
|
|
description: Migration instructions for upgrading between FastMCP versions
|
|
icon: up
|
|
---
|
|
|
|
This guide covers breaking changes and migration steps when upgrading FastMCP.
|
|
|
|
## v3.0.0
|
|
|
|
Most servers need only one change: update your import from `from mcp.server.fastmcp import FastMCP` to `from fastmcp import FastMCP`. The sections below cover less common breaking changes.
|
|
|
|
### Breaking Changes
|
|
|
|
#### WSTransport Removed
|
|
|
|
Use `StreamableHttpTransport` instead.
|
|
|
|
#### Auth Provider Environment Variables Removed
|
|
|
|
Auth providers no longer auto-load configuration. Read them explicitly:
|
|
|
|
```python
|
|
import os
|
|
|
|
auth = GitHubProvider(
|
|
client_id=os.environ["GITHUB_CLIENT_ID"],
|
|
client_secret=os.environ["GITHUB_CLIENT_SECRET"],
|
|
)
|
|
```
|
|
|
|
#### Component enable()/disable() Moved to Server
|
|
|
|
These methods moved from component objects to the server:
|
|
|
|
```python
|
|
# Before
|
|
tool = await server.get_tool("my_tool")
|
|
tool.disable()
|
|
|
|
# After
|
|
server.disable(names={"my_tool"}, components=["tool"])
|
|
```
|
|
|
|
#### Listing Methods Return Lists
|
|
|
|
`get_tools()`, `get_resources()`, `get_prompts()`, and `get_resource_templates()` now return lists instead of dicts:
|
|
|
|
```python
|
|
# Before
|
|
tools = await server.get_tools()
|
|
tool = tools["my_tool"]
|
|
|
|
# After
|
|
tools = await server.get_tools()
|
|
tool = next((t for t in tools if t.name == "my_tool"), None)
|
|
```
|
|
|
|
#### Prompts Use Message Class
|
|
|
|
Use `Message` instead of `mcp.types.PromptMessage`:
|
|
|
|
```python
|
|
# Before
|
|
from mcp.types import PromptMessage, TextContent
|
|
|
|
@mcp.prompt
|
|
def my_prompt() -> PromptMessage:
|
|
return PromptMessage(role="user", content=TextContent(type="text", text="Hello"))
|
|
|
|
# After
|
|
from fastmcp.prompts import Message
|
|
|
|
@mcp.prompt
|
|
def my_prompt() -> Message:
|
|
return Message("Hello")
|
|
```
|
|
|
|
#### Context State Methods Are Async
|
|
|
|
`ctx.set_state()` and `ctx.get_state()` are now async. State persists across the session:
|
|
|
|
```python
|
|
# Before
|
|
ctx.set_state("key", "value")
|
|
value = ctx.get_state("key")
|
|
|
|
# After
|
|
await ctx.set_state("key", "value")
|
|
value = await ctx.get_state("key")
|
|
```
|
|
|
|
#### Server Banner Environment Variable Renamed
|
|
|
|
`FASTMCP_SHOW_CLI_BANNER` is now `FASTMCP_SHOW_SERVER_BANNER`.
|
|
|
|
#### Metadata Namespace Renamed
|
|
|
|
The FastMCP metadata namespace changed from `_fastmcp` to `fastmcp`, and metadata is now always included. The `include_fastmcp_meta` parameter has been removed from `FastMCP()` and `to_mcp_tool()`—remove any usage of this parameter.
|
|
|
|
```python
|
|
# Before
|
|
tags = tool.meta.get("_fastmcp", {}).get("tags", [])
|
|
|
|
# After
|
|
tags = tool.meta.get("fastmcp", {}).get("tags", [])
|
|
```
|
|
|
|
### Behavior Changes
|
|
|
|
#### Decorators Return Functions
|
|
|
|
Decorators now return your original function instead of a component object. This means functions stay callable for testing:
|
|
|
|
```python
|
|
@mcp.tool
|
|
def greet(name: str) -> str:
|
|
return f"Hello, {name}!"
|
|
|
|
greet("World") # Works! Returns "Hello, World!"
|
|
```
|
|
|
|
If you relied on the old behavior (treating `greet` as a `FunctionTool`), set `FASTMCP_DECORATOR_MODE=object` for v2 compatibility.
|
|
|
|
### Deprecated Features
|
|
|
|
These still work but emit warnings. Update when convenient.
|
|
|
|
#### mount() prefix → namespace
|
|
|
|
```python
|
|
# Deprecated
|
|
main.mount(subserver, prefix="api")
|
|
|
|
# New
|
|
main.mount(subserver, namespace="api")
|
|
```
|
|
|
|
#### include_tags/exclude_tags → enable()/disable()
|
|
|
|
```python
|
|
# Deprecated
|
|
mcp = FastMCP("server", exclude_tags={"internal"})
|
|
|
|
# New
|
|
mcp = FastMCP("server")
|
|
mcp.disable(tags={"internal"})
|
|
```
|
|
|
|
#### tool_serializer → ToolResult
|
|
|
|
Return `ToolResult` from your tools for explicit serialization control instead of using the `tool_serializer` parameter.
|
|
|
|
#### add_tool_transformation() → add_transform()
|
|
|
|
```python
|
|
# Deprecated
|
|
mcp.add_tool_transformation("name", config)
|
|
|
|
# New
|
|
from fastmcp.server.transforms import ToolTransform
|
|
mcp.add_transform(ToolTransform({"name": config}))
|
|
```
|
|
|
|
#### FastMCP.as_proxy() → create_proxy()
|
|
|
|
```python
|
|
# Deprecated
|
|
proxy = FastMCP.as_proxy("http://example.com/mcp")
|
|
|
|
# New
|
|
from fastmcp.server import create_proxy
|
|
proxy = create_proxy("http://example.com/mcp")
|
|
```
|
|
|
|
## v3.0.0b2 (from v3.0.0b1)
|
|
|
|
### Breaking Changes
|
|
|
|
#### Tool `timeout` Parameter Removed
|
|
|
|
The `timeout` parameter on `@mcp.tool()` has been removed. Use Docket's `Timeout` dependency instead:
|
|
|
|
```python
|
|
# Before (v3.0.0b1)
|
|
@mcp.tool(timeout=30.0)
|
|
async def fetch_data(url: str) -> dict:
|
|
...
|
|
|
|
# After (v3.0.0b2)
|
|
from datetime import timedelta
|
|
from docket import Timeout
|
|
|
|
@mcp.tool
|
|
async def fetch_data(
|
|
url: str,
|
|
timeout: Timeout = Timeout(timedelta(seconds=30)),
|
|
) -> dict:
|
|
...
|
|
```
|
|
|
|
Benefits of the new approach:
|
|
|
|
- **Unified execution**: Timeouts work identically for foreground and background tasks
|
|
- **Additional capabilities**: Access to `Retry`, `ExponentialRetry`, `ConcurrencyLimit`
|
|
- **Auto-routing**: Components with Docket dependencies automatically route through Docket
|
|
|
|
Note: This is only breaking from beta 1 → beta 2. The `timeout` parameter didn't exist before beta 1.
|
|
|
|
## v2.14.0
|
|
|
|
### OpenAPI Parser Promotion
|
|
|
|
The experimental OpenAPI parser is now standard. Update imports:
|
|
|
|
```python
|
|
# Before
|
|
from fastmcp.experimental.server.openapi import FastMCPOpenAPI
|
|
|
|
# After
|
|
from fastmcp.server.openapi import FastMCPOpenAPI
|
|
```
|
|
|
|
### Removed Deprecated Features
|
|
|
|
- `BearerAuthProvider` → use `JWTVerifier`
|
|
- `Context.get_http_request()` → use `get_http_request()` from dependencies
|
|
- `from fastmcp import Image` → use `from fastmcp.utilities.types import Image`
|
|
- `FastMCP(dependencies=[...])` → use `fastmcp.json` configuration
|
|
- `FastMCPProxy(client=...)` → use `client_factory=lambda: ...`
|
|
- `output_schema=False` → use `output_schema=None`
|
|
|
|
## v2.13.0
|
|
|
|
### OAuth Token Key Management
|
|
|
|
The OAuth proxy now issues its own JWT tokens. For production, provide explicit keys:
|
|
|
|
```python
|
|
auth = GitHubProvider(
|
|
client_id=os.environ["GITHUB_CLIENT_ID"],
|
|
client_secret=os.environ["GITHUB_CLIENT_SECRET"],
|
|
base_url="https://your-server.com",
|
|
jwt_signing_key=os.environ["JWT_SIGNING_KEY"],
|
|
client_storage=RedisStore(host="redis.example.com"),
|
|
)
|
|
```
|
|
|
|
See [OAuth Token Security](/deployment/http#oauth-token-security) for details.
|