Skip to main content
Glama
rwxproject

MCP Server Template

by rwxproject

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

Related MCP server: Bootstrap MCP Server

🏃 Quick Start Guide

Prerequisites

  • Python 3.13+

  • uv (recommended package manager)

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

  • 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

# 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

  1. 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!
  1. The tool is automatically registered - no manual registration needed!

  2. 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

  1. 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

  1. 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

  1. Build the image:

docker build -t my-mcp-server .
  1. 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
  1. 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

  1. 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
  1. 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"
  }
}
  1. 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

  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:

# 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

  1. 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
  2. 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
  3. 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! 🚀

-
security - not tested
F
license - not found
-
quality - not tested

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/rwxproject/mcp-server-template'

If you have feedback or need assistance with the MCP directory API, please join our Discord server