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
1. Clone and Setup
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):
source .venv/bin/activate && uv run python -m mcp_server
Backward Compatible:
source .venv/bin/activate && uv run python main.py
With Custom Transport:
# 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
# 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
# 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
# Install from source
uv install git+<your-repo-url>
# Or from local directory
uv install .
๐ง Available Tools
Arithmetic Tools
Weather Tools
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
# Standard streamable HTTP mode
source .venv/bin/activate && uv run python -m mcp_server
2. Streamable HTTP Server Mode
# 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
# 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
# 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
# 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):
{
"mcpServers": {
"mcp-server-template": {
"command": "uv",
"args": ["run", "python", "-m", "mcp_server"],
"cwd": "/path/to/your/mcp-server-template"
}
}
}
Streamable HTTP Mode:
{
"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:
# 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:
# 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:
# 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:
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
Create a new tool file in src/mcp_server/tools/
:
# 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!
The tool is automatically registered - no manual registration needed!
Advanced tool with validation:
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
Create a resource file in src/mcp_server/resources/
:
# 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
Create a prompt file in src/mcp_server/prompts/
:
# 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
# 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:
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:
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:
export MCP_ENVIRONMENT=development
export MCP_LOG_LEVEL=DEBUG
export MCP_TRANSPORT=streamable-http
Streamable HTTP Server Configuration:
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:
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:
# 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
Build the image:
docker build -t my-mcp-server .
Run with different transports:
# 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
Docker Compose:
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
System Service (systemd example):
# /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
Process Manager (PM2 example):
{
"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"
}
}
Kubernetes Deployment:
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
# 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
# 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
Fork and clone the repository
Create a feature branch: git checkout -b feature/my-feature
Set development environment: export MCP_ENVIRONMENT=development
Write tests for new functionality
Ensure all tests pass: source .venv/bin/activate && uv run pytest
Run linting: source .venv/bin/activate && uv run ruff check src tests --fix
Test different transports: Test streamable-http and sse modes
Commit changes: Follow conventional commits
Submit a pull request
Development Workflows
Testing Different Transports:
# 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:
# 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
Server not starting:
# 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
Transport-specific issues:
# 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
Components not registered:
# 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:
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:
# 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
# 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
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
# 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
# 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
Happy building with MCP and FastMCP! ๐