| name | fastmcp |
| description | FastMCP Python framework for MCP servers with tools, resources, storage backends (memory/disk/Redis/DynamoDB). Use for Claude tool exposure, OAuth Proxy, cloud deployment, or encountering storage, lifespan, middleware, circular import, async errors. |
| license | MIT |
| metadata | {"version":"2.0.0","package_version":"fastmcp>=2.13.0","python_version":">=3.10","token_savings":"90-95%","errors_prevented":25,"production_tested":true,"last_updated":"2025-11-18","keywords":["FastMCP","MCP server Python","Model Context Protocol Python","fastmcp framework","mcp tools","mcp resources","mcp prompts","fastmcp storage","fastmcp memory storage","fastmcp disk storage","fastmcp redis","fastmcp dynamodb","fastmcp lifespan","fastmcp middleware","fastmcp oauth proxy","server composition mcp","fastmcp import","fastmcp mount","fastmcp cloud","fastmcp deployment","mcp authentication","fastmcp icons","openapi mcp","claude mcp server","fastmcp testing","storage misconfiguration","lifespan issues","middleware order","circular imports","module-level server","async await mcp"]} |
FastMCP - Build MCP Servers in Python
FastMCP is a Python framework for building Model Context Protocol (MCP) servers that expose tools, resources, and prompts to Large Language Models like Claude.
Quick Start
Installation
pip install fastmcp
Minimal Server
from fastmcp import FastMCP
mcp = FastMCP("My Server")
@mcp.tool()
async def hello(name: str) -> str:
"""Say hello to someone."""
return f"Hello, {name}!"
if __name__ == "__main__":
mcp.run()
Run:
python server.py
fastmcp dev server.py
python server.py --transport http --port 8000
Copy-Paste Template: See templates/basic-server.py
Core Concepts
Tools
Functions that LLMs can call:
@mcp.tool()
def calculate(operation: str, a: float, b: float) -> float:
"""Perform mathematical operations."""
operations = {
"add": lambda x, y: x + y,
"subtract": lambda x, y: x - y,
"multiply": lambda x, y: x * y,
"divide": lambda x, y: x / y if y != 0 else None
}
return operations.get(operation, lambda x, y: None)(a, b)
Best Practices:
- Clear, descriptive function names
- Comprehensive docstrings (LLMs read these!)
- Strong type hints (Pydantic validates automatically)
- Return structured data (dicts/lists)
- Handle errors gracefully
Resources
Expose static or dynamic data:
@mcp.resource("data://config")
def get_config() -> dict:
"""Provide application configuration."""
return {"version": "1.0.0", "features": ["auth", "api"]}
@mcp.resource("user://{user_id}/profile")
async def get_user_profile(user_id: str) -> dict:
"""Get user profile by ID."""
return {"id": user_id, "name": f"User {user_id}"}
URI Schemes: data://, file://, resource://, info://, api://, or custom
Prompts
Pre-configured prompts for LLMs:
@mcp.prompt("analyze")
def analyze_prompt(topic: str) -> str:
"""Generate analysis prompt."""
return f"""Analyze {topic} considering:
1. Current state
2. Challenges
3. Opportunities
4. Recommendations"""
Context Features
Progress Tracking:
from fastmcp import Context
@mcp.tool()
async def batch_process(items: list, context: Context) -> dict:
"""Process items with progress updates."""
for i, item in enumerate(items):
await context.report_progress(i + 1, len(items), f"Processing {item}")
await process_item(item)
return {"processed": len(items)}
User Input:
@mcp.tool()
async def confirm_action(action: str, context: Context) -> dict:
"""Perform action with user confirmation."""
confirmed = await context.request_elicitation(
prompt=f"Confirm {action}? (yes/no)",
response_type=str
)
return {"confirmed": confirmed.lower() == "yes"}
Storage Backends
Choose storage based on deployment:
from key_value.stores import DiskStore, RedisStore
from key_value.encryption import FernetEncryptionWrapper
from cryptography.fernet import Fernet
mcp = FastMCP("Dev Server")
mcp = FastMCP(
"Production Server",
storage=FernetEncryptionWrapper(
key_value=DiskStore(path="/var/lib/mcp/storage"),
fernet=Fernet(os.getenv("STORAGE_ENCRYPTION_KEY"))
)
)
mcp = FastMCP(
"Production Server",
storage=FernetEncryptionWrapper(
key_value=RedisStore(
host=os.getenv("REDIS_HOST"),
password=os.getenv("REDIS_PASSWORD")
),
fernet=Fernet(os.getenv("STORAGE_ENCRYPTION_KEY"))
)
)
Server Lifespans
Initialize resources on server startup:
from contextlib import asynccontextmanager
@asynccontextmanager
async def app_lifespan(server: FastMCP):
"""Runs ONCE when server starts (v2.13.0+)."""
db = await Database.connect()
print("Server starting")
try:
yield {"db": db}
finally:
await db.disconnect()
print("Server stopping")
mcp = FastMCP("My Server", lifespan=app_lifespan)
Critical: v2.13.0+ lifespans run per-server (not per-session). For per-session logic, use middleware.
Middleware System
8 built-in middleware types:
from fastmcp.middleware import (
LoggingMiddleware,
TimingMiddleware,
RateLimitingMiddleware,
ResponseCachingMiddleware
)
mcp.add_middleware(LoggingMiddleware())
mcp.add_middleware(TimingMiddleware())
mcp.add_middleware(RateLimitingMiddleware(max_requests=100, window_seconds=60))
mcp.add_middleware(ResponseCachingMiddleware(ttl_seconds=3600))
Custom Middleware:
from fastmcp.middleware import BaseMiddleware
class CustomMiddleware(BaseMiddleware):
async def on_call_tool(self, tool_name, arguments, context):
print(f"Before: {tool_name}")
result = await self.next(tool_name, arguments, context)
print(f"After: {tool_name}")
return result
Server Composition
Import Server (static, one-time copy):
main_server.import_server(vendor_server)
Mount Server (dynamic, runtime delegation):
main_server.mount(api_server, prefix="api")
Cloud Deployment
FastMCP Cloud Requirements:
- Server MUST be at module level
- Use disk/Redis storage (not memory)
- No import-time execution
mcp = FastMCP("My Server")
@mcp.tool()
async def my_tool(): pass
if __name__ == "__main__":
mcp.run()
Deploy:
fastmcp deploy server.py
Top 5 Critical Errors
1. Missing Server Object
Error: RuntimeError: No server object found at module level
Fix:
def create_server():
return FastMCP("server")
mcp = FastMCP("server")
2. Async/Await Confusion
Error: RuntimeError: no running event loop
Fix:
@mcp.tool()
def bad_tool():
result = await async_function()
@mcp.tool()
async def good_tool():
result = await async_function()
return result
3. Context Not Injected
Error: TypeError: missing 1 required positional argument: 'context'
Fix:
from fastmcp import Context
@mcp.tool()
async def bad_tool(context):
await context.report_progress(...)
@mcp.tool()
async def good_tool(context: Context):
await context.report_progress(0, 100, "Starting")
4. Storage Backend Not Configured
Error: RuntimeError: OAuth tokens lost on restart
Fix: Use disk or Redis storage in production (see Storage Backends section above)
5. Circular Import Errors
Error: ImportError: cannot import name 'X' from partially initialized module
Fix:
def get_client():
from .api_client import APIClient
return APIClient()
from .api_client import APIClient
from .cache import CacheManager
from .api_client import APIClient
client = APIClient()
See all 25 errors: references/error-catalog.md
Client Configuration
Claude Desktop
{
"mcpServers": {
"my-server": {
"command": "python",
"args": ["/path/to/server.py"]
}
}
}
Claude Code CLI
{
"mcpServers": {
"my-server": {
"command": "python",
"args": ["server.py"]
}
}
}
CLI Commands
fastmcp dev server.py
fastmcp run server.py
fastmcp deploy server.py
fastmcp test server.py
Best Practices
- Server Structure: Keep module-level server, organize tools in separate files
- Type Hints: Use Pydantic models for complex validation
- Documentation: Write detailed docstrings (LLMs read them!)
- Error Handling: Catch and return structured errors
- Storage: Use encrypted disk/Redis in production
- Lifespans: Initialize connections once per server
- Middleware: Order matters (error handling → timing → logging → rate limiting → caching)
- Testing: Unit test tools with
FastMCP.test_tool()
Bundled Resources
References (references/):
cli-commands.md - Complete CLI command reference (dev, run, deploy, test)
cloud-deployment.md - FastMCP Cloud deployment guide with module-level requirements
common-errors.md - All 25 documented errors with solutions and prevention
context-features.md - Progress tracking, user input, and Context API patterns
error-catalog.md - Comprehensive error catalog with fixes
integration-patterns.md - Server composition (import/mount), OAuth Proxy, OpenAPI
production-patterns.md - Storage backends, lifespans, middleware, architecture patterns
Templates (templates/):
basic-server.py - Minimal MCP server with tools, resources, prompts
client-example.py - MCP client integration examples
api-client-pattern.py - API integration patterns
error-handling.py - Error handling best practices
openapi-integration.py - OpenAPI schema integration
prompts-examples.py - Prompt template patterns
resources-examples.py - Resource URI patterns and examples
tools-examples.py - Tool definition patterns
self-contained-server.py - Complete production-ready self-contained server
.env.example - Environment variables template
requirements.txt - Python dependencies
pyproject.toml - Python project configuration
Dependencies
{
"dependencies": {
"fastmcp": ">=2.13.0",
"pydantic": ">=2.0.0"
},
"optionalDependencies": {
"py-key-value-aio": ">=0.1.0",
"cryptography": ">=41.0.0",
"redis": ">=5.0.0"
}
}
Official Documentation
Verification Checklist
Token Savings: 90-95% vs learning from scratch
Errors Prevented: 25 documented issues
Production Tested: ✅ Multiple deployments