README.mdโข26 kB
# MCP Server Template
A comprehensive, modular template for building Model Context Protocol (MCP) servers using FastMCP with professional architecture, auto-discovery, and flexible deployment options.
## ๐ Project Overview
This template provides a robust foundation for creating MCP servers with:
- **FastMCP Framework**: Built on FastMCP 2.11.3+ for rapid MCP server development
- **Modular Architecture**: Clean separation of tools, resources, prompts, and configuration
- **Auto-Discovery Registry**: Automatic component registration using registry pattern
- **Multiple Entry Points**: Backward compatibility with flexible deployment options
- **Transport Flexibility**: Supports streamable HTTP and Server-Sent Events (SSE) transports
- **Comprehensive Testing**: Unit and integration test suite structure
- **Development Template**: Docker support, structured logging, and configuration management
- **Type Safety**: Pydantic models and type hints throughout
- **Extensible Design**: Easy to add new tools, resources, and prompts
**Version**: 0.1.0
## ๐ Quick Start Guide
### Prerequisites
- Python 3.13+
- [uv](https://github.com/astral-sh/uv) (recommended package manager)
### 1. Clone and Setup
```bash
git clone <your-repo>
cd mcp-server-template
uv venv
source .venv/bin/activate
uv install
```
### 2. Run the Server
Choose your preferred method:
**New Modular Way (Recommended):**
```bash
source .venv/bin/activate && uv run python -m mcp_server
```
**Backward Compatible:**
```bash
source .venv/bin/activate && uv run python main.py
```
**With Custom Transport:**
```bash
# Streamable HTTP transport
export MCP_TRANSPORT=streamable-http
export MCP_PORT=8080
source .venv/bin/activate && uv run python -m mcp_server
# Server-Sent Events transport
export MCP_TRANSPORT=sse
export MCP_PORT=8081
source .venv/bin/activate && uv run python -m mcp_server
```
### 3. Test Connection
```bash
# Run diagnostic test
source .venv/bin/activate && uv run python diagnosis_test.py
# Run verification test
source .venv/bin/activate && uv run python verification_test.py
```
## ๐ฆ Installation Instructions
### Development Installation
```bash
# Clone the repository
git clone <your-repo-url>
cd mcp-server-template
# Create and activate virtual environment
uv venv
source .venv/bin/activate
# Install dependencies
uv install
# Install development dependencies
uv install --group dev
```
### Production Installation
```bash
# Install from source
uv install git+<your-repo-url>
# Or from local directory
uv install .
```
## ๐ง Available Tools
### Arithmetic Tools
- **add**: Add two integers together
- **subtract**: Subtract two integers
### Weather Tools
- **get_current_weather**: Get current weather information for a location
**Note**: Weather tool uses OpenWeatherMap API. Set `WEATHER_API_KEY` environment variable for real data, or it will use mock data for development.
## ๐ง Usage Examples
### 1. Default Mode
```bash
# Standard streamable HTTP mode
source .venv/bin/activate && uv run python -m mcp_server
```
### 2. Streamable HTTP Server Mode
```bash
# Run as streamable HTTP server
export MCP_TRANSPORT=streamable-http
export MCP_HOST=0.0.0.0
export MCP_PORT=8080
source .venv/bin/activate && uv run python -m mcp_server
```
### 3. Server-Sent Events (SSE) Mode
```bash
# Run as SSE server
export MCP_TRANSPORT=sse
export MCP_HOST=0.0.0.0
export MCP_PORT=8081
source .venv/bin/activate && uv run python -m mcp_server
```
### 4. Development Mode with Debug Logging
```bash
# Enable debug logging
export MCP_LOG_LEVEL=DEBUG
export MCP_ENVIRONMENT=development
source .venv/bin/activate && uv run python -m mcp_server
```
### 5. Docker Deployment
```bash
# Build image
docker build -t mcp-server .
# Run container (default mode)
docker run -it mcp-server
# Run container (Streamable HTTP mode)
docker run -e MCP_TRANSPORT=streamable-http -e MCP_PORT=8080 -p 8080:8080 mcp-server
# With custom configuration
docker run -e MCP_LOG_LEVEL=DEBUG -e MCP_ENVIRONMENT=production -it mcp-server
```
### 6. Integration with Claude Desktop
Add to your Claude Desktop MCP configuration:
**Default Mode (Recommended):**
```json
{
"mcpServers": {
"mcp-server-template": {
"command": "uv",
"args": ["run", "python", "-m", "mcp_server"],
"cwd": "/path/to/your/mcp-server-template"
}
}
}
```
**Streamable HTTP Mode:**
```json
{
"mcpServers": {
"mcp-server-template": {
"url": "http://localhost:8080/mcp",
"transport": "streamable-http"
}
}
}
```
## ๐๏ธ Architecture Overview
### Directory Structure
```
mcp-server-template/
โโโ src/mcp_server/ # Main package (v0.1.0)
โ โโโ __init__.py # Package initialization & lazy imports
โ โโโ __main__.py # Module entry point
โ โโโ server.py # Core FastMCP server implementation
โ โโโ config/ # Configuration management
โ โ โโโ __init__.py
โ โ โโโ settings.py # Pydantic settings with environment support
โ โ โโโ logging.py # Structured logging configuration
โ โโโ tools/ # MCP tools
โ โ โโโ __init__.py
โ โ โโโ base.py # Base tool class
โ โ โโโ arithmetic.py # Arithmetic tools (add, subtract)
โ โ โโโ weather.py # Weather tools (get_current_weather)
โ โ โโโ registry.py # Tool auto-discovery registry
โ โโโ resources/ # MCP resources
โ โ โโโ __init__.py
โ โ โโโ base.py # Base resource class
โ โ โโโ system.py # System information resources
โ โ โโโ registry.py # Resource auto-discovery registry
โ โโโ prompts/ # MCP prompts
โ โโโ __init__.py
โ โโโ base.py # Base prompt class
โ โโโ text_processing.py # Text processing prompts
โ โโโ registry.py # Prompt auto-discovery registry
โโโ tests/ # Test suite
โ โโโ conftest.py # Shared test fixtures
โ โโโ unit/ # Unit tests
โ โ โโโ test_tools.py
โ โโโ integration/ # Integration tests
โ โโโ test_client_interactions.py
โโโ main.py # Backward compatibility entry
โโโ Dockerfile # Container deployment
โโโ diagnosis_test.py # Server diagnostic tool
โโโ verification_test.py # Server verification tool
โโโ pyproject.toml # Project configuration
```
### Key Components
#### 1. Server Factory Pattern
Clean server creation with comprehensive configuration:
```python
# Server creation with auto-discovery
from mcp_server import create_server
server = create_server() # Automatically discovers and registers all components
```
#### 2. Registry Pattern with Auto-Discovery
All components are automatically discovered and registered:
```python
# Components are automatically found and registered
from mcp_server.tools.registry import register_all_tools
from mcp_server.resources.registry import register_all_resources
from mcp_server.prompts.registry import register_all_prompts
# Registration happens automatically in create_server()
register_all_tools(mcp)
register_all_resources(mcp)
register_all_prompts(mcp)
```
#### 3. Transport-Agnostic Design
Supports multiple transport methods:
```python
# Flexible transport configuration
await mcp.run_async(
transport=settings.transport, # streamable-http or sse
host=settings.host, # configurable host
port=settings.port # configurable port
)
```
#### 4. Comprehensive Configuration
Environment-based configuration with validation:
```python
from mcp_server.config.settings import get_settings
settings = get_settings() # Loads from environment with defaults
# Supports: transport, host, port, log_level, environment, etc.
```
## ๐จ Extension Guide
### Adding New Tools
1. **Create a new tool file** in `src/mcp_server/tools/`:
```python
# src/mcp_server/tools/my_tool.py
from typing import Any
from fastmcp import FastMCP
from .base import BaseTool
class MyTool(BaseTool):
"""Example tool that processes text input."""
def __init__(self):
super().__init__(name="my_tool")
def register_with_mcp(self, mcp: FastMCP) -> None:
"""Register tools with FastMCP instance."""
@mcp.tool()
async def process_text(text: str) -> str:
"""Process text input and return formatted result.
Args:
text: Input text to process
Returns:
Processed text in uppercase
"""
self._log_tool_call("process_text", text=text)
return f"Processed: {text.upper()}"
self.logger.info("Registered my_tool: process_text")
# The tool is automatically discovered by the registry!
```
2. **The tool is automatically registered** - no manual registration needed!
3. **Advanced tool with validation**:
```python
from typing import Dict, Any
from fastmcp import FastMCP
from .base import BaseTool
class ValidatedTool(BaseTool):
"""Example tool with validation using FastMCP decorators"""
def __init__(self):
super().__init__(name="validated")
def register_with_mcp(self, mcp: FastMCP) -> None:
@mcp.tool()
async def process_data(value: int, name: str) -> Dict[str, Any]:
"""Process data with validation.
Args:
value: Integer value to process
name: Name to include in result
Returns:
Processed data dictionary
"""
if not (0 <= value <= 100):
raise ValueError("Value must be between 0-100")
if not name or not name.strip():
raise ValueError("Name cannot be empty")
return {"value": value, "name": name.strip(), "processed": True}
self.logger.info("Registered validated tool: process_data")
```
### Adding New Resources
1. **Create a resource file** in `src/mcp_server/resources/`:
```python
# src/mcp_server/resources/my_resource.py
import json
from typing import Any
from .base import BaseResource
class MyResource(BaseResource):
"""Example resource that provides data."""
uri_template = "my://data/{category}"
name = "My Data Resource"
description = "Provides categorized data"
mime_type = "application/json"
async def read(self, category: str = "default") -> str:
"""Read resource data for the given category."""
data = {
"category": category,
"items": [f"item-{i}" for i in range(1, 6)],
"timestamp": "2024-01-01T00:00:00Z"
}
return json.dumps(data, indent=2)
# Automatically discovered by the registry!
```
### Adding New Prompts
1. **Create a prompt file** in `src/mcp_server/prompts/`:
```python
# src/mcp_server/prompts/my_prompt.py
from typing import Any, List
from fastmcp import FastMCP
from .base import BasePrompt
class MyPrompt(BasePrompt):
"""Example prompt for content generation."""
def __init__(self):
super().__init__(name="my_prompt")
def register_with_mcp(self, mcp: FastMCP) -> None:
"""Register prompts with FastMCP instance."""
@mcp.prompt()
async def generate_content(topic: str, format: str = "markdown") -> str:
"""Generate structured content about a topic.
Args:
topic: The topic to generate content about
format: Output format (markdown, text, etc.)
Returns:
Generated content in the specified format
"""
self._log_prompt_call("generate_content", topic=topic, format=format)
if format == "markdown":
return f"""# {topic}
## Overview
This is an overview of {topic}.
## Key Points
- Point 1 about {topic}
- Point 2 about {topic}
- Point 3 about {topic}
## Conclusion
Summary of {topic}.
"""
else:
return f"Content about {topic} in {format} format"
self.logger.info("Registered my_prompt: generate_content")
# Automatically discovered by the registry!
```
## ๐งช Testing
### Running Tests
```bash
# All tests
source .venv/bin/activate && uv run pytest
# Unit tests only
source .venv/bin/activate && uv run pytest tests/unit/ -v
# Integration tests only
source .venv/bin/activate && uv run pytest tests/integration/ -v
# Specific test file
source .venv/bin/activate && uv run pytest tests/unit/test_tools.py -v
# With coverage
source .venv/bin/activate && uv run pytest --cov=src/mcp_server --cov-report=html
# Parallel execution
source .venv/bin/activate && uv run pytest -n auto
```
### Test Structure
```
tests/
โโโ conftest.py # Shared test fixtures
โโโ unit/ # Unit tests
โ โโโ test_tools.py # Tool testing
โโโ integration/ # Integration tests
โโโ test_client_interactions.py # End-to-end tests
```
### Writing Tests
Example unit test for tools:
```python
import pytest
from mcp_server.tools.arithmetic import ArithmeticTools
@pytest.mark.asyncio
async def test_arithmetic_tools():
tools = ArithmeticTools()
# Test direct methods
assert tools.add_numbers(5, 3) == 8
assert tools.subtract_numbers(10, 4) == 6
@pytest.mark.asyncio
async def test_weather_tools():
from mcp_server.tools.weather import WeatherTools
tools = WeatherTools()
# Weather tool would require proper MCP setup for full testing
# This is a simplified example
assert tools._use_mock_data() == True # Default is mock data
```
Example integration test:
```python
import pytest
from mcp_server import create_server
@pytest.mark.asyncio
async def test_server_creation():
server = create_server()
assert server is not None
# Test component registration
# This would require proper async setup in real tests
assert server is not None
# Verify tools are available (actual implementation would vary)
# The server would have add, subtract, get_current_weather tools
```
## โ๏ธ Configuration
### Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `MCP_TRANSPORT` | `streamable-http` | Transport method (streamable-http, sse) |
| `MCP_HOST` | `0.0.0.0` | Server host for network transports |
| `MCP_PORT` | `8080` | Server port for network transports |
| `MCP_LOG_LEVEL` | `INFO` | Logging level (DEBUG, INFO, WARNING, ERROR) |
| `MCP_LOG_FORMAT` | `[%(levelname)s]: %(message)s` | Log format string |
| `MCP_ENVIRONMENT` | `development` | Environment (development, production, testing) |
| `MCP_SERVER_NAME` | `MCP Server Template` | Server identification name |
| `MCP_VERSION` | `0.1.0` | Server version |
| `PORT` | - | Cloud Run compatible port override |
### Configuration Examples
**Development Configuration:**
```bash
export MCP_ENVIRONMENT=development
export MCP_LOG_LEVEL=DEBUG
export MCP_TRANSPORT=streamable-http
```
**Streamable HTTP Server Configuration:**
```bash
export MCP_TRANSPORT=streamable-http
export MCP_HOST=0.0.0.0
export MCP_PORT=8080
export MCP_ENVIRONMENT=production
export MCP_LOG_LEVEL=INFO
```
**Server-Sent Events Configuration:**
```bash
export MCP_TRANSPORT=sse
export MCP_HOST=0.0.0.0
export MCP_PORT=8081
export MCP_ENVIRONMENT=production
```
### Advanced Configuration
The settings system supports complex configuration scenarios:
```python
# src/mcp_server/config/settings.py
from pydantic import BaseModel, Field
from typing import Literal
class Settings(BaseModel):
# Server Configuration
server_name: str = "MCP Server Template"
host: str = "0.0.0.0"
port: int = 8080
transport: Literal["streamable-http", "sse"] = "streamable-http"
# Logging Configuration
log_level: str = "INFO"
log_format: str = "[%(levelname)s]: %(message)s"
# Environment Configuration
environment: Literal["development", "production", "testing"] = "development"
version: str = "0.1.0"
model_config = {
"env_prefix": "MCP_",
"case_sensitive": False,
"env_file": ".env",
"env_file_encoding": "utf-8"
}
```
## ๐ Deployment
### Docker Deployment
1. **Build the image**:
```bash
docker build -t my-mcp-server .
```
2. **Run with different transports**:
```bash
# Default mode
docker run -it my-mcp-server
# Streamable HTTP mode
docker run -e MCP_TRANSPORT=streamable-http -e MCP_HOST=0.0.0.0 -e MCP_PORT=8080 -p 8080:8080 my-mcp-server
# Server-Sent Events mode
docker run -e MCP_TRANSPORT=sse -e MCP_HOST=0.0.0.0 -e MCP_PORT=8081 -p 8081:8081 my-mcp-server
# With custom environment
docker run -e MCP_LOG_LEVEL=DEBUG -e MCP_ENVIRONMENT=production -it my-mcp-server
```
3. **Docker Compose**:
```yaml
version: '3.8'
services:
mcp-server-default:
build: .
environment:
- MCP_TRANSPORT=streamable-http
- MCP_LOG_LEVEL=INFO
stdin_open: true
tty: true
mcp-server-http:
build: .
environment:
- MCP_TRANSPORT=streamable-http
- MCP_HOST=0.0.0.0
- MCP_PORT=8080
- MCP_LOG_LEVEL=INFO
ports:
- "8080:8080"
mcp-server-sse:
build: .
environment:
- MCP_TRANSPORT=sse
- MCP_HOST=0.0.0.0
- MCP_PORT=8081
- MCP_LOG_LEVEL=INFO
ports:
- "8081:8081"
```
### Production Deployment
1. **System Service** (systemd example):
```ini
# /etc/systemd/system/mcp-server.service
[Unit]
Description=MCP Server
After=network.target
[Service]
Type=simple
User=mcp
WorkingDirectory=/opt/mcp-server
Environment=MCP_TRANSPORT=streamable-http
Environment=MCP_HOST=0.0.0.0
Environment=MCP_PORT=8080
Environment=MCP_LOG_LEVEL=INFO
Environment=MCP_ENVIRONMENT=production
ExecStart=/opt/mcp-server/.venv/bin/python -m mcp_server
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
```
2. **Process Manager** (PM2 example):
```json
{
"name": "mcp-server",
"script": "python",
"args": ["-m", "mcp_server"],
"cwd": "/opt/mcp-server",
"interpreter": "/opt/mcp-server/.venv/bin/python",
"env": {
"MCP_TRANSPORT": "streamable-http",
"MCP_HOST": "0.0.0.0",
"MCP_PORT": "8080",
"MCP_LOG_LEVEL": "INFO",
"MCP_ENVIRONMENT": "production"
}
}
```
3. **Kubernetes Deployment**:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mcp-server
spec:
replicas: 3
selector:
matchLabels:
app: mcp-server
template:
metadata:
labels:
app: mcp-server
spec:
containers:
- name: mcp-server
image: my-mcp-server:latest
env:
- name: MCP_TRANSPORT
value: "streamable-http"
- name: MCP_HOST
value: "0.0.0.0"
- name: MCP_PORT
value: "8080"
- name: MCP_ENVIRONMENT
value: "production"
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: mcp-server-service
spec:
selector:
app: mcp-server
ports:
- port: 80
targetPort: 8080
type: LoadBalancer
```
## ๐ฅ Development
### Development Setup
```bash
# Clone and setup
git clone <repo-url>
cd mcp-server-template
uv venv
source .venv/bin/activate
uv install --group dev
# Set development environment
export MCP_ENVIRONMENT=development
export MCP_LOG_LEVEL=DEBUG
```
### Code Quality
```bash
# Format and lint code
source .venv/bin/activate && uv run ruff check src tests --fix
source .venv/bin/activate && uv run ruff format src tests
# Type checking (mypy not included in current dependencies)
# Add mypy to dev dependencies if type checking is needed
# Run all quality checks
source .venv/bin/activate && uv run pytest && uv run ruff check src tests
```
### Contributing Guidelines
1. **Fork and clone** the repository
2. **Create a feature branch**: `git checkout -b feature/my-feature`
3. **Set development environment**: `export MCP_ENVIRONMENT=development`
4. **Write tests** for new functionality
5. **Ensure all tests pass**: `source .venv/bin/activate && uv run pytest`
6. **Run linting**: `source .venv/bin/activate && uv run ruff check src tests --fix`
7. **Test different transports**: Test streamable-http and sse modes
8. **Commit changes**: Follow conventional commits
9. **Submit a pull request**
### Development Workflows
**Testing Different Transports:**
```bash
# Test default streamable HTTP mode
export MCP_TRANSPORT=streamable-http && source .venv/bin/activate && uv run python -m mcp_server
# Test SSE mode
export MCP_TRANSPORT=sse && export MCP_PORT=8081 && source .venv/bin/activate && uv run python -m mcp_server
```
**Component Development:**
```bash
# Verify tool registration
source .venv/bin/activate && uv run python -c "
from mcp_server.tools.registry import get_all_tools
print([tool.__class__.__name__ for tool in get_all_tools()])
"
# Test new components
source .venv/bin/activate && uv run python diagnosis_test.py
```
## ๐ Troubleshooting
### Common Issues
1. **Server not starting**:
```bash
# Check Python version
python --version # Should be 3.13+
# Check dependencies
source .venv/bin/activate && uv pip list
# Check with debug logging
export MCP_LOG_LEVEL=DEBUG
source .venv/bin/activate && uv run python -m mcp_server
```
2. **Transport-specific issues**:
```bash
# Streamable HTTP transport issues
export MCP_TRANSPORT=streamable-http
export MCP_HOST=localhost
export MCP_PORT=8080
curl http://localhost:8080/health # Test endpoint
# SSE transport issues
export MCP_TRANSPORT=sse
export MCP_PORT=8081
# Test with SSE client
```
3. **Components not registered**:
```bash
# Verify component discovery
source .venv/bin/activate && uv run python -c "
from mcp_server import create_server
server = create_server()
print('Server created successfully with all components')
"
```
4. **Docker issues**:
```bash
# Check container logs
docker logs <container-id>
# Interactive debugging
docker run -it --entrypoint /bin/bash my-mcp-server
# Test different transports
docker run -e MCP_TRANSPORT=streamable-http -e MCP_PORT=8080 -p 8080:8080 my-mcp-server
```
### Debug Mode
Enable comprehensive debugging:
```bash
export MCP_LOG_LEVEL=DEBUG
export MCP_ENVIRONMENT=development
source .venv/bin/activate && uv run python -m mcp_server
```
### Health Checks
Use the provided diagnostic tools:
```bash
# Basic functionality test
source .venv/bin/activate && uv run python diagnosis_test.py
# Full verification test
source .venv/bin/activate && uv run python verification_test.py
# Test specific transport
export MCP_TRANSPORT=streamable-http && source .venv/bin/activate && uv run python verification_test.py
```
## ๐ง FastMCP Features
This template leverages FastMCP's powerful capabilities:
### Multi-Transport Support
```python
# Automatic transport detection and configuration
await mcp.run_async(
transport="streamable-http", # Streamable HTTP server mode
transport="sse" # Server-Sent Events mode
)
```
### Automatic Type Validation
```python
from fastmcp import tool
@tool
async def validated_function(count: int, name: str) -> dict:
"""FastMCP handles automatic type conversion and validation."""
return {"count": count, "name": name}
```
### Built-in Error Handling
```python
# FastMCP provides comprehensive error handling
try:
result = await tool.execute(params)
except ValidationError as e:
logger.error(f"Validation error: {e}")
except Exception as e:
logger.error(f"Execution error: {e}")
```
### Lazy Loading for Performance
```python
# The template uses lazy imports for optimal startup
def create_server():
from .server import create_server as _create_server
return _create_server()
```
## ๐ Dependencies
### Core Dependencies
- **fastmcp** (>=2.11.3): FastMCP framework for rapid MCP server development
- **httpx** (>=0.28.1): HTTP client for external API integration
- **pydantic** (>=2.0.0): Data validation and settings management
### Development Dependencies
- **pytest** (>=8.4.1): Testing framework with async support
- **pytest-asyncio** (>=0.23.0): Async testing support for pytest
- **ruff** (>=0.12.10): Fast Python linter and formatter
- **ipykernel** (>=6.30.1): Jupyter kernel for interactive development
## ๐ What's New in v0.1.0
- **Multi-Transport Support**: Streamable HTTP and Server-Sent Events transport options
- **Environment-Based Configuration**: Comprehensive settings management with MCP_ prefixes
- **Registry Pattern**: Automatic component discovery and registration
- **Structured Logging**: Configurable logging formats with proper levels
- **Development Template**: Docker support with Python 3.13, structured for extension
- **FastMCP Integration**: Built on the latest FastMCP framework
- **Lazy Loading**: Optimized startup performance with lazy imports
- **Flexible Deployment**: Multiple deployment options and configurations
## ๐ License
[Your License Here]
## ๐ค Support
- **Issues**: [GitHub Issues](your-repo/issues)
- **Discussions**: [GitHub Discussions](your-repo/discussions)
- **Documentation**: This README and inline code documentation
- **FastMCP Docs**: [FastMCP Documentation](https://github.com/jlowin/fastmcp)
- **MCP Specification**: [Model Context Protocol](https://modelcontextprotocol.io/)
---
**Happy building with MCP and FastMCP! ๐**