MCP Template Deep Dive

A comprehensive exploration of the enterprise MCP template architecture, directory structure, and design decisions including FastAPI vs FastMCP, containerization, and testing strategies.

This deep dive explores the enterprise MCP template’s architecture, walking through each directory and file to understand the design decisions that make it production-ready. You’ll learn why we chose FastAPI over FastMCP, how the modular structure supports enterprise deployments, and the reasoning behind each component.

Template Structure Overview

template-mcp-server/
├── template_mcp_server/              # Main package (nested structure)
│   ├── src/                         # Source code
│   │   ├── __init__.py
│   │   ├── main.py                  # Application entry point
│   │   ├── api.py                   # FastAPI application
│   │   ├── mcp.py                   # MCP server integration
│   │   ├── settings.py              # Configuration management
│   │   ├── tools/                   # MCP tools (tools-first architecture)
│   │   │   ├── multiply_tool.py    # Example CPU-bound tool
│   │   │   ├── code_review_tool.py # Example I/O-bound tool
│   │   │   └── logo_tool.py        # Example resource-as-tool
│   │   └── utils/
│   │       └── pylogger.py          # Structured logging
├── tests/                           # Comprehensive test suite
├── examples/                        # Usage examples
├── kubernetes/                      # Kubernetes deployment configs
├── pyproject.toml                   # Python project configuration
├── Containerfile                    # Container build instructions
└── README.md

Info Info

Repository: template-mcp-server

This template implements a “tools-first” architecture where all functionality is exposed as MCP tools.

Key Architectural Decisions

FastAPI vs FastMCP: Why FastAPI?

The template uses FastAPI instead of the simpler FastMCP framework for several enterprise reasons:

FastAPI Advantages

  • Production Scale: Handles thousands of concurrent connections with async/await
  • Enterprise Security: Built-in OAuth2, JWT, CORS, rate limiting, input validation
  • Transport Flexibility: Native support for HTTP, WebSockets, Server-Sent Events (SSE)
  • API Documentation: Automatic OpenAPI/Swagger documentation generation
  • Ecosystem Integration: Works with enterprise tools like Prometheus, Jaeger, etc.
  • Type Safety: Full Python type hints with runtime validation via Pydantic
  • Testing Framework: Comprehensive testing tools with dependency injection

FastMCP Trade-offs

  • Simplicity: FastMCP is simpler for basic MCP servers
  • MCP Focus: More opinionated about MCP patterns
  • Enterprise Features: Fewer built-in enterprise integrations
# FastAPI approach (template uses this)
from fastapi import FastAPI
from fastmcp import FastMCP

app = FastAPI(title="Enterprise MCP Server")
mcp = FastMCP("enterprise-server")

@app.get("/health")
async def health():
    return {"status": "healthy"}

Nested Package Structure

The template uses template_mcp_server/src/ instead of flat src/ for enterprise benefits:

Container Isolation

  • Clean builds: Only the package gets copied to containers
  • Layer optimization: Better container layer caching and smaller images
  • Security: Excludes development artifacts from production deployments

Package Management

  • Namespace protection: Prevents naming conflicts
  • Import clarity: Clear package imports
  • Distribution ready: Proper structure for package repositories

When to Use This Template

Use the Enterprise MCP Template when you need:

  • Production deployment on Kubernetes
  • Enterprise security and compliance requirements
  • Comprehensive testing and CI/CD pipelines
  • Modular architecture for complex integrations
  • Multiple transport protocols (HTTP, SSE, Streamable-HTTP)
  • Professional development workflow with pre-commit hooks

Architecture

graph TD A[Client Request] --> B[FastAPI App] B --> C{Transport Protocol} C -->|HTTP| D[HTTP Handler] C -->|SSE| E[SSE Handler] D --> G[MCP Server] E --> G G --> H[Tools Registry] H --> I[CPU-Bound Tools] H --> J[I/O-Bound Tools] H --> K[Resource-as-Tools] I --> L["multiply()
(def)"] J --> M["code_review()
(async def)"] K --> N["get_logo()
(async def)"] style G fill:#e1f5fe style H fill:#f3e5f5

def vs async def: The Complete Guide

One of the most critical decisions in tool development is choosing between synchronous (def) and asynchronous (async def) functions.

When to Use def (Synchronous)

✅ CPU-Bound Operations:

  • Mathematical calculations
  • Data processing and transformations
  • Algorithms and sorting
  • In-memory operations
def multiply_numbers(a: float, b: float) -> dict:
    """CPU-bound calculation - uses def (synchronous)."""
    try:
        result = a * b
        return {"status": "success", "result": result}
    except Exception as e:
        return {"status": "error", "message": str(e)}

When to Use async def (Asynchronous)

✅ I/O-Bound Operations:

  • Database queries
  • HTTP API calls
  • File uploads/downloads
  • Network operations
async def code_review_tool(code: str, language: str = "python") -> dict:
    """I/O-bound operation - uses async def for external API calls."""
    try:
        async with httpx.AsyncClient() as client:
            response = await client.post(
                "https://ai-review-service.example.com/analyze",
                json={"code": code, "language": language},
                timeout=30.0
            )
            analysis = response.json()

        return {"status": "success", "analysis": analysis}
    except httpx.TimeoutException:
        return {"status": "error", "message": "AI service timeout"}

Decision Matrix

Operation TypeExampleUseReason
Math/LogicCalculations, sortingdefCPU-bound, no I/O benefit
DatabaseSQL queriesasync defI/O-bound, wait for network
HTTP CallsAPI requestsasync defI/O-bound, network latency
File I/OReading filesasync defI/O-bound, disk operations
External ServicesAI APIs, cloud servicesasync defI/O-bound, service latency

Tip Tip

Rule of Thumb: If your tool waits for something external (network, disk, database), use async def. If it only uses CPU and memory, use def.

Testing Strategy

The template includes comprehensive tests across multiple categories:

Test Categories

  • test_api.py: FastAPI integration tests
  • test_container.py: Kubernetes deployment tests
  • test_mcp.py: MCP server and tools-first architecture tests
  • test_tools.py: Individual tool functionality tests
  • test_settings.py: Configuration validation tests

Example Test

def test_container_startup_and_health(self):
    """Test that container starts and responds to HTTP requests."""
    build_cmd = ["podman", "build", "-t", image_name, "."]
    run_cmd = ["podman", "run", "-d", "--name", container_name,
               "-p", "3001:3000", image_name]

    # Build, run, test, cleanup
    assert build_result.returncode == 0
    assert health_response.status_code == 200

Kubernetes Deployment

Production-ready Kubernetes configurations:

# deployment.yaml - Core deployment
apiVersion: apps/v1
kind: Deployment
spec:
  replicas: 3
  template:
    spec:
      containers:
      - name: mcp-server
        image: "registry.example.com/mcp-server:latest"
        resources:
          requests:
            memory: "256Mi"
            cpu: "100m"
          limits:
            memory: "512Mi"
            cpu: "500m"

Production Features:

  • High availability: Multi-replica deployment
  • Resource management: CPU/memory limits and requests
  • Health checks: Liveness and readiness probes
  • Security: Pod security contexts and service accounts

Getting Started with the Template

Info Info

Ready to Start Building?

For step-by-step setup instructions, transformation guide, and your first tool implementation, see the Quick Start guide.

This Deep Dive focuses on understanding the architecture and design decisions behind the template.

Summary

This template represents a production-ready foundation for enterprise MCP servers, carefully designed around three core principles:

  1. Tools-First Architecture - Universal client compatibility
  2. Enterprise Scalability - FastAPI foundation with async/await patterns
  3. Production Readiness - Comprehensive testing and Kubernetes deployment

Tip Tip

Ready to implement? The Quick Start guide provides step-by-step instructions, while Taking Your MCP Server to Production covers deployment and operational considerations.