We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/jaewilson07/comfy_mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
# FastMCP v2 to v3 Migration Guide
**Purpose**: Step-by-step guide for migrating existing FastMCP v2 servers to v3.
## Migration Overview
FastMCP v3 is **backward compatible** with v2. Your v2 code will continue to work in v3 without changes. However, v3 introduces powerful new patterns that can improve your server's architecture.
### Migration Philosophy
✅ **Recommended Approach**: Incremental migration
- Start by updating dependencies
- Test existing functionality
- Gradually adopt v3 patterns
- Refactor when beneficial, not because you "have to"
❌ **Not Recommended**: Big bang rewrite
- Don't rewrite everything at once
- Don't break working code for the sake of using new features
- Don't migrate just because it's new
## Migration Phases
### Phase 1: Update and Verify (Required)
**Goal**: Update to v3 and verify backward compatibility
#### Step 1.1: Update Dependencies
```bash
# Option 1: Install latest beta
pip install fastmcp==3.0.0b1
# Option 2: Stay on v2 for now
pip install 'fastmcp<3'
# With uv (recommended)
uv pip install fastmcp==3.0.0b1
```
#### Step 1.2: Run Existing Tests
```bash
# Run your test suite
pytest tests/
# Manual testing
python your_server.py
```
#### Step 1.3: Check for Warnings
Look for deprecation warnings in your logs:
```python
# v2 code that might show warnings
from fastmcp.server.auth.providers.google import GoogleProvider # Old import
# Update to v3 style
from fastmcp.auth import GoogleProvider # New import
```
#### Step 1.4: Verify Functionality
Test all critical paths:
- [ ] Server starts without errors
- [ ] All tools are discoverable
- [ ] Tools execute correctly
- [ ] Resources are accessible
- [ ] Authentication works (if used)
- [ ] Client connections work
### Phase 2: Adopt v3 Patterns (Optional)
**Goal**: Use v3 features to improve code organization
#### Step 2.1: Identify Opportunities
Look for these patterns in your v2 code:
**Opportunity 1: Monolithic servers**
```python
# v2: Everything in one file
@mcp.tool
def admin_tool():
pass
@mcp.tool
def user_tool():
pass
@mcp.tool
def guest_tool():
pass
```
→ **v3 Solution**: Server composition
**Opportunity 2: Repeated filtering logic**
```python
# v2: Manual filtering in tools
@mcp.tool
def restricted_tool(user_id: str):
user = get_user(user_id)
if not user.is_admin:
raise PermissionError()
# ... actual logic
```
→ **v3 Solution**: Auth transforms
**Opportunity 3: Multiple environments**
```python
# v2: If/else for different configs
if ENV == "prod":
@mcp.tool
def real_tool():
return real_api_call()
else:
@mcp.tool
def real_tool():
return "mocked"
```
→ **v3 Solution**: Provider system
#### Step 2.2: Apply v3 Patterns Incrementally
##### Example Migration 1: Monolithic → Modular
**Before (v2):**
```python
# server.py
from fastmcp import FastMCP
mcp = FastMCP("My Server")
@mcp.tool
def get_user(user_id: int):
return {"id": user_id, "name": "User"}
@mcp.tool
def create_user(name: str):
return {"id": 123, "name": name}
@mcp.tool
def delete_user(user_id: int):
return {"deleted": user_id}
@mcp.tool
def get_order(order_id: int):
return {"id": order_id, "status": "pending"}
@mcp.tool
def create_order(user_id: int, items: list):
return {"id": 456, "user_id": user_id, "items": items}
if __name__ == "__main__":
mcp.run()
```
**After (v3):**
```python
# users.py
from fastmcp import FastMCP
users = FastMCP("Users")
@users.tool
def get_user(user_id: int):
return {"id": user_id, "name": "User"}
@users.tool
def create_user(name: str):
return {"id": 123, "name": name}
@users.tool
def delete_user(user_id: int):
return {"deleted": user_id}
# orders.py
from fastmcp import FastMCP
orders = FastMCP("Orders")
@orders.tool
def get_order(order_id: int):
return {"id": order_id, "status": "pending"}
@orders.tool
def create_order(user_id: int, items: list):
return {"id": 456, "user_id": user_id, "items": items}
# server.py
from fastmcp import FastMCP
from users import users
from orders import orders
mcp = FastMCP("My Server")
# Compose servers
mcp.mount("/users", users)
mcp.mount("/orders", orders)
if __name__ == "__main__":
mcp.run()
```
**Benefits:**
- Clear separation of concerns
- Tools automatically namespaced (users_get_user, orders_get_order)
- Each module can be developed/tested independently
##### Example Migration 2: Manual Auth → Transform
**Before (v2):**
```python
from fastmcp import FastMCP
mcp = FastMCP("My Server")
def check_admin(user_id: str):
user = get_user(user_id)
if not user.is_admin:
raise PermissionError("Admin only")
@mcp.tool
def admin_action(user_id: str, data: dict):
check_admin(user_id)
return perform_admin_action(data)
@mcp.tool
def another_admin_action(user_id: str, data: dict):
check_admin(user_id)
return perform_another_action(data)
```
**After (v3):**
```python
from fastmcp import FastMCP
from fastmcp.transforms import AuthTransform
mcp = FastMCP("My Server")
# Define tools without auth logic
@mcp.tool
def admin_action(data: dict):
return perform_admin_action(data)
@mcp.tool
def another_admin_action(data: dict):
return perform_another_action(data)
# Apply auth at server level
mcp.add_transform(
AuthTransform(rules={
"admin": ["admin_*"], # Only admins can call admin_* tools
"user": []
})
)
```
**Benefits:**
- Cleaner tool code (focused on business logic)
- Centralized auth rules
- Easy to change auth requirements
- Can be tested separately
##### Example Migration 3: Environment-Specific Code → Providers
**Before (v2):**
```python
from fastmcp import FastMCP
import os
mcp = FastMCP("My Server")
ENV = os.getenv("ENV", "dev")
if ENV == "production":
@mcp.tool
def call_api(endpoint: str):
# Real API call
return requests.get(f"https://api.prod.com/{endpoint}").json()
else:
@mcp.tool
def call_api(endpoint: str):
# Mock response
return {"mocked": True, "endpoint": endpoint}
@mcp.tool
def another_tool():
return "common logic"
```
**After (v3):**
```python
# prod_tools.py
from fastmcp import FastMCP
prod = FastMCP("Production Tools")
@prod.tool
def call_api(endpoint: str):
return requests.get(f"https://api.prod.com/{endpoint}").json()
# dev_tools.py
from fastmcp import FastMCP
dev = FastMCP("Dev Tools")
@dev.tool
def call_api(endpoint: str):
return {"mocked": True, "endpoint": endpoint}
# server.py
from fastmcp import FastMCP
from fastmcp.providers import FileProvider
import os
mcp = FastMCP("My Server")
# Load environment-specific tools
ENV = os.getenv("ENV", "dev")
if ENV == "production":
mcp.add_provider(FileProvider("prod_tools.py"))
else:
mcp.add_provider(FileProvider("dev_tools.py"))
# Common tools
@mcp.tool
def another_tool():
return "common logic"
```
**Benefits:**
- Clear separation of prod vs dev code
- Can test each environment's tools independently
- Easy to add more environments
- No conditional decorators
### Phase 3: Advanced Refactoring (When Ready)
**Goal**: Leverage advanced v3 patterns for complex scenarios
#### Advanced Pattern 1: Custom Providers
Create providers that load components dynamically:
```python
from fastmcp import FastMCP
from fastmcp.providers import Provider
import yaml
class ConfigBasedProvider(Provider):
"""Load tools from YAML configuration"""
def __init__(self, config_path: str):
self.config_path = config_path
async def get_tools(self):
config = yaml.safe_load(Path(self.config_path).read_text())
tools = []
for tool_config in config["tools"]:
# Create tool from config
tool = self.create_tool_from_config(tool_config)
tools.append(tool)
return tools
def create_tool_from_config(self, config):
# Implement tool creation logic
pass
# Usage
mcp = FastMCP("Config-Driven Server")
mcp.add_provider(ConfigBasedProvider("./tools.yaml"))
```
#### Advanced Pattern 2: Custom Transforms
Create transforms for cross-cutting concerns:
```python
from fastmcp.transforms import Transform
class CachingTransform(Transform):
"""Cache tool results"""
def __init__(self, ttl: int = 3600):
self.cache = {}
self.ttl = ttl
async def transform_tool(self, tool):
original_fn = tool.fn
async def cached_fn(*args, **kwargs):
cache_key = self.make_key(tool.name, args, kwargs)
if cache_key in self.cache:
cached_value, timestamp = self.cache[cache_key]
if time.time() - timestamp < self.ttl:
return cached_value
result = await original_fn(*args, **kwargs)
self.cache[cache_key] = (result, time.time())
return result
tool.fn = cached_fn
return tool
class RateLimitTransform(Transform):
"""Rate limit tool calls"""
def __init__(self, calls_per_minute: int = 60):
self.calls_per_minute = calls_per_minute
self.calls = {}
async def transform_tool(self, tool):
original_fn = tool.fn
async def rate_limited_fn(*args, **kwargs):
now = time.time()
tool_calls = self.calls.get(tool.name, [])
# Remove old calls
tool_calls = [t for t in tool_calls if now - t < 60]
if len(tool_calls) >= self.calls_per_minute:
raise RateLimitError(f"Rate limit exceeded for {tool.name}")
result = await original_fn(*args, **kwargs)
tool_calls.append(now)
self.calls[tool.name] = tool_calls
return result
tool.fn = rate_limited_fn
return tool
# Usage
mcp = FastMCP("Advanced Server")
mcp.add_transform(CachingTransform(ttl=300))
mcp.add_transform(RateLimitTransform(calls_per_minute=100))
```
#### Advanced Pattern 3: Dynamic Server Architecture
Build servers that adapt at runtime:
```python
class AdaptiveServer:
"""Server that adapts based on load and config"""
def __init__(self):
self.mcp = FastMCP("Adaptive")
self.providers = {}
self.transforms = []
async def update_configuration(self, config: dict):
"""Dynamically update server configuration"""
# Clear existing
self.mcp.clear_providers()
self.mcp.clear_transforms()
# Load providers from config
for provider_config in config["providers"]:
provider = self.create_provider(provider_config)
self.mcp.add_provider(provider)
# Load transforms from config
for transform_config in config["transforms"]:
transform = self.create_transform(transform_config)
self.mcp.add_transform(transform)
async def monitor_and_adapt(self):
"""Monitor metrics and adapt"""
while True:
metrics = await self.get_metrics()
if metrics["load"] > 0.8:
# High load: add caching
self.mcp.add_transform(CachingTransform(ttl=60))
if metrics["error_rate"] > 0.1:
# High errors: add retry logic
self.mcp.add_transform(RetryTransform(max_retries=3))
await asyncio.sleep(60)
async def run(self):
"""Run with monitoring"""
asyncio.create_task(self.monitor_and_adapt())
await self.mcp.run()
```
## Breaking Changes Reference
### v3 Beta Breaking Changes
#### 1. Transform Rename
```python
# v2 (still works but deprecated)
from fastmcp.transforms import Enabled
# v3 (recommended)
from fastmcp.transforms import Visibility
```
#### 2. Import Path Changes
```python
# v2 style (deprecated)
from fastmcp.server.auth.providers.google import GoogleProvider
from fastmcp.client.transports import HttpTransport
# v3 style (recommended)
from fastmcp.auth import GoogleProvider
from fastmcp.transports import HttpTransport
```
#### 3. Internal API Changes
Most internal APIs are backwards compatible, but if you were using private/internal APIs (starting with `_`), they may have changed.
```python
# If you were using private APIs
from fastmcp._internal import something # May break
# Use public APIs instead
from fastmcp import something # Stable
```
### Deprecation Warnings
v3 will show warnings for deprecated patterns:
```
DeprecationWarning: Importing from 'fastmcp.server.auth' is deprecated.
Use 'from fastmcp.auth import ...' instead.
```
**Action**: Update imports when you see these warnings.
## Testing Your Migration
### Unit Tests
```python
import pytest
from fastmcp import FastMCP, Client
@pytest.fixture
def server():
"""Create test server"""
mcp = FastMCP("Test")
@mcp.tool
def test_tool(x: int) -> int:
return x * 2
return mcp
async def test_v3_compatibility(server):
"""Test that v2 code works in v3"""
async with Client(server) as client:
result = await client.call_tool("test_tool", {"x": 5})
assert int(result.content[0].text) == 10
async def test_new_features(server):
"""Test v3 features"""
from fastmcp.transforms import NamespaceTransform
server.add_transform(NamespaceTransform(prefix="api_"))
async with Client(server) as client:
tools = await client.list_tools()
assert any(t.name == "api_test_tool" for t in tools)
```
### Integration Tests
```python
async def test_full_stack():
"""Test complete v3 server"""
# Create modular server
users = FastMCP("Users")
orders = FastMCP("Orders")
main = FastMCP("Main")
main.mount("/users", users)
main.mount("/orders", orders)
# Test composition
async with Client(main) as client:
tools = await client.list_tools()
tool_names = [t.name for t in tools]
assert "users_get_user" in tool_names
assert "orders_get_order" in tool_names
```
### Manual Testing Checklist
- [ ] Server starts without errors
- [ ] Deprecation warnings addressed
- [ ] All tools discoverable via `list_tools()`
- [ ] All resources accessible via `list_resources()`
- [ ] Tool execution works
- [ ] Resource reading works
- [ ] Authentication works (if used)
- [ ] Transforms apply correctly
- [ ] Server composition works (if used)
- [ ] Client connections work
- [ ] Performance acceptable
- [ ] Error handling works
## Rollback Plan
If you encounter issues with v3:
### Step 1: Revert Dependencies
```bash
# Rollback to v2
pip install 'fastmcp<3'
# Or specific v2 version
pip install fastmcp==2.14.4
```
### Step 2: Check Git
```bash
# Revert code changes
git checkout <previous-commit>
# Or create fix branch
git checkout -b fix/v3-migration
```
### Step 3: Document Issues
If v3 doesn't work as expected:
1. Document the issue
2. Create minimal reproduction
3. Report to FastMCP Discord or GitHub
4. Stay on v2 until resolved
## Migration Success Criteria
Your migration is successful when:
- ✅ All existing functionality works
- ✅ No deprecation warnings
- ✅ Tests pass
- ✅ Performance is acceptable
- ✅ Team understands new patterns
- ✅ Documentation updated
- ✅ Monitoring shows no regressions
## Getting Help
- **Discord**: [FastMCP Community](https://discord.gg/uu8dJCgttd)
- **Docs**: [gofastmcp.com](https://gofastmcp.com/)
- **GitHub**: [Issues](https://github.com/jlowin/fastmcp/issues)
- **Internal**: Check your team's FastMCP v3 skill
## Quick Reference
### v2 → v3 Patterns
| v2 Pattern | v3 Pattern | Benefit |
|------------|------------|---------|
| Monolithic server | Server composition (mount/import) | Modularity |
| Manual auth checks | Auth transforms | Clean separation |
| Environment if/else | Provider system | Clear boundaries |
| Repeated filtering | Filter transforms | DRY principle |
| Ad-hoc namespacing | Namespace transforms | Consistency |
| Single server file | Multi-file + composition | Maintainability |
### Import Updates
```python
# v2 → v3 Import Changes
fastmcp.server.auth.providers → fastmcp.auth
fastmcp.client.transports → fastmcp.transports
fastmcp.server.FastMCP → fastmcp.FastMCP # (unchanged)
```
---
**Last Updated**: January 23, 2026
**Version**: 1.0.0