Decorators return functions instead of component objects (#2856)

This commit is contained in:
Jeremiah Lowin 2026-01-12 21:58:07 -05:00 committed by GitHub
commit 1b723f302d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
38 changed files with 2406 additions and 1606 deletions

View file

@ -14,6 +14,45 @@ This guide provides migration instructions for breaking changes and major update
The deprecated `WSTransport` client transport has been removed. Use `StreamableHttpTransport` instead.
### Decorators Return Functions
<Warning>
**Breaking Change:** Decorators now return your original function instead of a component object. Code that treats the decorated function as a `FunctionTool`, `FunctionResource`, or `FunctionPrompt` will break.
</Warning>
Decorators (`@tool`, `@resource`, `@prompt`) now return the original function instead of transforming it into a component object:
<CodeGroup>
```python Before
@mcp.tool
def greet(name: str) -> str:
return f"Hello, {name}!"
isinstance(greet, FunctionTool) # True
greet.name # "greet"
```
```python After
@mcp.tool
def greet(name: str) -> str:
return f"Hello, {name}!"
isinstance(greet, FunctionTool) # False - it's your function now
greet("World") # "Hello, World!" - still callable
```
</CodeGroup>
**Why this changed:** Functions staying as functions means they're directly callable for testing, work naturally with instance methods, and match how Flask/FastAPI decorators behave.
**For v2 compatibility:**
```python
import fastmcp
fastmcp.settings.decorator_mode = "object"
```
Or set the environment variable `FASTMCP_DECORATOR_MODE=object`.
### Provider Architecture
FastMCP v3 introduces a unified provider architecture for sourcing components. All tools, resources, and prompts now flow through providers:

View file

@ -238,6 +238,38 @@ Requires Docket server for task scheduling and result polling.
---
## Decorators Return Functions
v3.0 changes what decorators (`@tool`, `@resource`, `@prompt`) return. Decorators now return the original function unchanged, rather than transforming it into a component object.
**v3 behavior (default):**
```python
@mcp.tool
def greet(name: str) -> str:
return f"Hello, {name}!"
# greet is still your function - call it directly
greet("World") # "Hello, World!"
```
**Why this matters:**
- Functions stay callable - useful for testing and reuse
- Instance methods just work: `mcp.add_tool(obj.method)`
- Matches how Flask, FastAPI, and Typer decorators behave
**For v2 compatibility:**
```python
import fastmcp
# v2 behavior: decorators return FunctionTool/FunctionResource/FunctionPrompt objects
fastmcp.settings.decorator_mode = "object"
```
Environment variable: `FASTMCP_DECORATOR_MODE=object`
---
## CLI Auto-Reload
The `--reload` flag enables file watching with automatic server restarts for development.
@ -361,6 +393,30 @@ The `tool_serializer` parameter on `FastMCP` is deprecated. Return `ToolResult`
The deprecated `WSTransport` client transport has been removed. Use `StreamableHttpTransport` instead.
### Decorators Return Functions
Decorators (`@tool`, `@resource`, `@prompt`) now return the original function instead of component objects. Code that treats the decorated function as a `FunctionTool`, `FunctionResource`, or `FunctionPrompt` will break.
```python
# v2.x
@mcp.tool
def greet(name: str) -> str:
return f"Hello, {name}!"
isinstance(greet, FunctionTool) # True
# v3.0
@mcp.tool
def greet(name: str) -> str:
return f"Hello, {name}!"
isinstance(greet, FunctionTool) # False
callable(greet) # True - it's still your function
greet("World") # "Hello, World!"
```
Set `FASTMCP_DECORATOR_MODE=object` or `fastmcp.settings.decorator_mode = "object"` for v2 behavior.
### Component Enable/Disable Moved to Server/Provider
The `enabled` field and `enable()`/`disable()` methods removed from component objects: