Claude-skills fastmcp
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.
git clone https://github.com/secondsky/claude-skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/secondsky/claude-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/fastmcp/skills/fastmcp" ~/.claude/skills/secondsky-claude-skills-fastmcp && rm -rf "$T"
plugins/fastmcp/skills/fastmcp/SKILL.mdFastMCP - 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 # or: uv pip install fastmcp
Minimal Server
from fastmcp import FastMCP # MUST be at module level for FastMCP Cloud 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 # Local development fastmcp dev server.py # With FastMCP CLI python server.py --transport http --port 8000 # HTTP mode
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"]} # Dynamic resource with parameters @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 # Memory (default) - Development only mcp = FastMCP("Dev Server") # Disk - Single instance mcp = FastMCP( "Production Server", storage=FernetEncryptionWrapper( key_value=DiskStore(path="/var/lib/mcp/storage"), fernet=Fernet(os.getenv("STORAGE_ENCRYPTION_KEY")) ) ) # Redis - Multi-instance 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 ) # Order matters! 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) # MUST call next() print(f"After: {tool_name}") return result
Server Composition
Import Server (static, one-time copy):
main_server.import_server(vendor_server) # Static bundle
Mount Server (dynamic, runtime delegation):
main_server.mount(api_server, prefix="api") # Changes appear immediately
Cloud Deployment
FastMCP Cloud Requirements:
- Server MUST be at module level
- Use disk/Redis storage (not memory)
- No import-time execution
# ✅ Cloud-ready pattern mcp = FastMCP("My Server") # Module level @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:
# ❌ WRONG def create_server(): return FastMCP("server") # ✅ CORRECT mcp = FastMCP("server") # At module level
2. Async/Await Confusion
Error:
RuntimeError: no running event loop
Fix:
# ❌ WRONG: Sync function calling async @mcp.tool() def bad_tool(): result = await async_function() # Error! # ✅ CORRECT: Async tool @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 # ❌ WRONG: No type hint @mcp.tool() async def bad_tool(context): # Missing type! await context.report_progress(...) # ✅ CORRECT: Proper type hint @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:
# ❌ WRONG: Factory function creating circular dependency # shared/__init__.py def get_client(): from .api_client import APIClient # Circular! return APIClient() # ✅ CORRECT: Direct imports # shared/__init__.py from .api_client import APIClient from .cache import CacheManager # shared/monitoring.py 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 # Development mode with hot reload fastmcp run server.py # Production mode fastmcp deploy server.py # Deploy to FastMCP Cloud fastmcp test server.py # Run tests
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/):
- Complete CLI command reference (dev, run, deploy, test)cli-commands.md
- FastMCP Cloud deployment guide with module-level requirementscloud-deployment.md
- All 25 documented errors with solutions and preventioncommon-errors.md
- Progress tracking, user input, and Context API patternscontext-features.md
- Comprehensive error catalog with fixeserror-catalog.md
- Server composition (import/mount), OAuth Proxy, OpenAPIintegration-patterns.md
- Storage backends, lifespans, middleware, architecture patternsproduction-patterns.md
Templates (
templates/):
- Minimal MCP server with tools, resources, promptsbasic-server.py
- MCP client integration examplesclient-example.py
- API integration patternsapi-client-pattern.py
- Error handling best practiceserror-handling.py
- OpenAPI schema integrationopenapi-integration.py
- Prompt template patternsprompts-examples.py
- Resource URI patterns and examplesresources-examples.py
- Tool definition patternstools-examples.py
- Complete production-ready self-contained serverself-contained-server.py
- Environment variables template.env.example
- Python dependenciesrequirements.txt
- Python project configurationpyproject.toml
Dependencies
{ "dependencies": { "fastmcp": ">=2.13.0", "pydantic": ">=2.0.0" }, "optionalDependencies": { "py-key-value-aio": ">=0.1.0", // For storage backends "cryptography": ">=41.0.0", // For encryption "redis": ">=5.0.0" // For Redis storage } }
Official Documentation
- FastMCP GitHub: https://github.com/jlowin/fastmcp
- MCP Protocol: https://modelcontextprotocol.io
- FastMCP Cloud: https://fastmcp.com
Verification Checklist
- FastMCP installed (
)fastmcp>=2.13.0 - Server object at module level
- Tool docstrings comprehensive
- Context type hints for context parameters
- Resource URIs have schemes
- Storage backend configured (production)
- Lifespan pattern correct (v2.13.0+)
- Middleware order logical
- Client configuration tested
- Production deployment successful
Token Savings: 90-95% vs learning from scratch Errors Prevented: 25 documented issues Production Tested: ✅ Multiple deployments