fastmcp_dev_guide.md•7.11 kB
# FastMCP Server Development Guide - Best Practices
## Overview
This document provides steering context and best practices for developing Model Context Protocol (MCP) servers using FastMCP framework.
## Core Principles
### 1. Server Initialization
- Use `FastMCP` class as the main entry point
- Define server name and optional dependencies during initialization
- Keep server configuration minimal and focused
```python
from fastmcp import FastMCP
mcp = FastMCP("server-name")
```
### 2. Tool Definition
- Use `@mcp.tool()` decorator for exposing functions as tools
- Provide clear, descriptive docstrings (used as tool descriptions)
- Use type hints for all parameters
- Keep tools focused on single responsibilities
```python
@mcp.tool()
def tool_name(param: str, optional_param: int = 0) -> dict:
"""Clear description of what this tool does."""
return {"result": "value"}
```
### 3. Resource Management
- Use `@mcp.resource()` for exposing data resources
- Define URI patterns clearly
- Implement proper resource lifecycle management
- Return structured data formats
### 4. Prompts
- Use `@mcp.prompt()` for reusable prompt templates
- Include parameter validation
- Provide clear prompt descriptions
- Support dynamic prompt generation
### 5. Error Handling
- Implement comprehensive error handling in all tools
- Return meaningful error messages
- Use appropriate exception types
- Log errors for debugging
```python
@mcp.tool()
def safe_tool(param: str) -> dict:
"""Tool with proper error handling."""
try:
# Tool logic
return {"status": "success"}
except ValueError as e:
return {"error": str(e)}
```
### 6. Type Safety
- Always use type hints for parameters and return values
- Leverage Pydantic models for complex data structures
- Validate input data before processing
- Document expected types in docstrings
### 7. Async Operations
- Use async/await for I/O-bound operations
- Implement proper async context managers
- Handle concurrent requests appropriately
- Avoid blocking operations in async tools
```python
@mcp.tool()
async def async_tool(url: str) -> dict:
"""Async tool for I/O operations."""
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.json()
```
### 8. Configuration Management
- Use environment variables for sensitive data
- Implement configuration validation at startup
- Provide sensible defaults
- Document all configuration options
### 9. Testing
- Write unit tests for all tools
- Test error conditions
- Mock external dependencies
- Validate tool schemas
### 10. Documentation
- Document all tools with clear docstrings
- Include parameter descriptions
- Provide usage examples
- Maintain README with setup instructions
## Server Structure Best Practices
### Minimal Server Structure
```
project/
├── server.py # Main server implementation
├── requirements.txt # Dependencies
└── README.md # Documentation
```
### Modular Server Structure
```
project/
├── server.py # Server entry point
├── tools/ # Tool implementations
│ ├── __init__.py
│ └── tool_module.py
├── resources/ # Resource handlers
├── config.py # Configuration
├── requirements.txt
└── README.md
```
## Tool Design Patterns
### Single Responsibility
Each tool should do one thing well:
```python
@mcp.tool()
def get_user(user_id: str) -> dict:
"""Retrieve user by ID."""
return fetch_user(user_id)
@mcp.tool()
def update_user(user_id: str, data: dict) -> dict:
"""Update user information."""
return update_user_data(user_id, data)
```
### Parameter Validation
```python
@mcp.tool()
def process_data(value: int, mode: str = "default") -> dict:
"""Process data with validation."""
if value < 0:
raise ValueError("Value must be non-negative")
if mode not in ["default", "advanced"]:
raise ValueError("Invalid mode")
return {"processed": True}
```
### Structured Returns
```python
@mcp.tool()
def fetch_data(query: str) -> dict:
"""Return structured data."""
return {
"data": [...],
"metadata": {
"count": 10,
"timestamp": "2025-10-09T11:40:00Z"
}
}
```
## Security Best Practices
1. **Input Validation**: Validate all inputs before processing
2. **Secrets Management**: Never hardcode credentials
3. **Rate Limiting**: Implement rate limits for resource-intensive operations
4. **Access Control**: Validate permissions where applicable
5. **Sanitization**: Sanitize user inputs to prevent injection attacks
## Performance Optimization
1. **Caching**: Cache frequently accessed data
2. **Lazy Loading**: Load resources only when needed
3. **Connection Pooling**: Reuse connections for external services
4. **Batch Operations**: Support batch processing where applicable
5. **Timeouts**: Set appropriate timeouts for external calls
## Deployment Considerations
1. **Dependencies**: Pin dependency versions in requirements.txt
2. **Environment**: Support multiple environments (dev, staging, prod)
3. **Logging**: Implement structured logging
4. **Monitoring**: Add health check endpoints
5. **Graceful Shutdown**: Handle shutdown signals properly
## Common Patterns
### Context Manager Pattern
```python
class ResourceManager:
async def __aenter__(self):
# Setup
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
# Cleanup
pass
```
### Factory Pattern
```python
def create_tool_handler(config: dict):
"""Factory for creating tool handlers."""
return ToolHandler(config)
```
### Dependency Injection
```python
mcp = FastMCP("server", dependencies=["external-service"])
```
## Debugging Tips
1. Enable verbose logging during development
2. Use descriptive error messages
3. Implement request/response logging
4. Add debug tools for inspection
5. Use type checkers (mypy) during development
## Version Control
1. Use semantic versioning
2. Maintain CHANGELOG.md
3. Tag releases appropriately
4. Document breaking changes
## Example: Complete Minimal Server
```python
from fastmcp import FastMCP
mcp = FastMCP("example-server")
@mcp.tool()
def greet(name: str) -> dict:
"""Greet a user by name."""
return {"message": f"Hello, {name}!"}
@mcp.tool()
async def fetch_data(url: str) -> dict:
"""Fetch data from URL."""
# Implementation
return {"data": "..."}
if __name__ == "__main__":
mcp.run()
```
## Resources
- FastMCP Documentation: https://gofastmcp.com
- MCP Specification: https://modelcontextprotocol.io
- Python Type Hints: https://docs.python.org/3/library/typing.html
## Checklist for New Servers
- [ ] Clear server name and purpose
- [ ] All tools have type hints
- [ ] Comprehensive docstrings
- [ ] Error handling implemented
- [ ] Input validation in place
- [ ] Tests written
- [ ] README documentation
- [ ] Environment variables documented
- [ ] Dependencies pinned
- [ ] Security review completed