Building Model Context Protocol (MCP) Servers: Complete Tutorial with FastMCP

December 9, 2025 marked something rare in tech: OpenAI, Anthropic, Google, Microsoft, AWS, Block, Bloomberg, and Cloudflare all showed up to the same party. The Linux Foundation announced the Agentic AI Foundation (AAIF)—a coalition to standardize how AI agents connect to the real world. At the center of it all: the Model Context Protocol (MCP), Anthropic’s open standard now powering 10,000+ active servers and racking up 97 million monthly SDK downloads.

Translation: MCP stuck. And if you’re building anything with AI agents, you need to know how to build MCP servers.

This tutorial walks you through building, deploying, and testing Model Context Protocol servers—from a simple calculator to a production-ready database connector. No hype, just working code.

What Is the Model Context Protocol (And Why It Matters)

Before MCP, every AI integration was custom code. Want Claude to query your database? Build a custom tool. Want ChatGPT to access your API? Another custom integration. Every chat platform, model, and tool needed its own connector—creating the classic N x M problem.

Here’s the math: If you have 3 AI models and 10 tools, you need 30 integrations. Add one more model, you need 10 more integrations. Scale that across an enterprise with dozens of internal APIs, and you’re looking at hundreds of bespoke connectors to maintain.

MCP solves this by providing a standardized protocol—think USB for AI integrations. Write once, connect anywhere. OpenAI adopted MCP in March 2025, Google followed in April, and by the time AAIF launched in December, the protocol had become the de facto standard for AI agent tool integration.

The architecture is straightforward:

  • Hosts: Applications running Claude, GPT, Gemini, or other models
  • Servers: Services exposing tools, resources, or prompts via MCP
  • Transport: JSON-RPC 2.0 over stdio (local) or HTTP with Server-Sent Events (cloud)

Instead of building N x M integrations, you build once to the MCP standard. Everyone’s compatible. That’s why the ecosystem now has 2,000+ protocol configurations in the official registry and developers are downloading the SDKs 97 million times per month.

Side-by-side comparison of traditional N x M integration problem versus MCP standardized solution reducing complexity

Real-World Use Cases: Who’s Actually Building MCP Servers

MCP isn’t theoretical. It’s in production across the AI ecosystem:

  • Database connectivity: Connect Claude or ChatGPT directly to PostgreSQL, MongoDB, or your data warehouse
  • API integrations: Stripe, Slack, and GitHub expose their APIs as MCP servers
  • Knowledge base access: Internal wikis and documentation become queryable by AI
  • Internal tools: Companies let their AI agents access proprietary systems securely

Why this matters: deployment time drops from weeks to days. You don’t need a 10-person platform team to add AI capabilities. Smaller companies can now integrate AI into their stack affordably because MCP democratizes what used to require specialized AI engineering.

Anthropic’s own Claude Code uses MCP servers for tool integration. So do the major AI platforms that joined AAIF. The standard’s sticking because it actually works.

Building Your First Model Context Protocol Server: Calculator Example

Let’s build something practical. We’ll start with a simple calculator server using FastMCP—the Python framework that makes MCP accessible to anyone who can write a function.

Step 1: Choose Your Framework

You have options: FastMCP for Python, the TypeScript SDK for Node.js, or raw JSON-RPC if you’re feeling adventurous. For this tutorial, we’re using FastMCP because it has minimal boilerplate and Python decorators make the code intuitive.

pip install fastmcp

Step 2: Set Up Your Project

Create a virtual environment and install FastMCP:

python3 -m venv mcp_env
source mcp_env/bin/activate
pip install fastmcp

Step 3: Create the Calculator Server

Here’s the complete calculator server—note how little code this takes:

from fastmcp import FastMCP

server = FastMCP(name="calculator", description="Basic calculator MCP server")

@server.tool()
def add(a: float, b: float) -> float:
    """Add two numbers together"""
    return a + b

@server.tool()
def multiply(a: float, b: float) -> float:
    """Multiply two numbers"""
    return a * b

@server.tool()
def divide(a: float, b: float) -> float:
    """Divide a by b with zero handling"""
    if b == 0:
        return None  # Graceful error handling
    return a / b

if __name__ == "__main__":
    server.run()

What’s happening here:

  • The @server.tool() decorator exposes a Python function as an MCP tool
  • Type hints tell the host what parameters are needed
  • Docstrings become the tool descriptions—critical for Claude and GPT to understand when to call each function
  • The server starts on stdio by default for local integrations

MCP servers can be this simple. A few decorated functions and you’re live.

Step 4: Run Your Server Locally

python3 calculator_server.py

The server starts, listens on stdio, and waits for a host to connect. To test it, you’ll need a host like MCP Inspector or Claude Code. But first, let’s build something more interesting.

Real-World Example: Building a Database MCP Server

Calculators are cute. Let’s build something that shows why MCP actually matters: a PostgreSQL connector that lets Claude query your database directly.

The architecture: Claude Code (host) connects to your Python FastMCP server, which wraps PostgreSQL connections and exposes three tools: query_database(), list_tables(), and get_table_schema().

from fastmcp import FastMCP
import psycopg2
import os

server = FastMCP(name="postgres-connector", description="Connect to PostgreSQL databases")

DB_URL = os.getenv("DATABASE_URL")

@server.tool()
def list_tables() -> list:
    """List all tables in the database"""
    conn = psycopg2.connect(DB_URL)
    cursor = conn.cursor()
    cursor.execute("""
        SELECT table_name
        FROM information_schema.tables
        WHERE table_schema = 'public'
    """)
    tables = [row[0] for row in cursor.fetchall()]
    cursor.close()
    conn.close()
    return tables

@server.tool()
def query_database(sql: str) -> dict:
    """Execute a SQL query safely (limited to SELECT)"""
    if not sql.strip().upper().startswith("SELECT"):
        return {"error": "Only SELECT queries allowed"}

    conn = psycopg2.connect(DB_URL)
    cursor = conn.cursor()
    try:
        cursor.execute(sql)
        rows = cursor.fetchall()
        columns = [desc[0] for desc in cursor.description]
        return {"columns": columns, "rows": rows}
    except Exception as e:
        return {"error": str(e)}
    finally:
        cursor.close()
        conn.close()

@server.tool()
def get_table_schema(table_name: str) -> dict:
    """Get column information for a specific table"""
    conn = psycopg2.connect(DB_URL)
    cursor = conn.cursor()
    cursor.execute(f"""
        SELECT column_name, data_type, is_nullable
        FROM information_schema.columns
        WHERE table_name = '{table_name}'
    """)
    schema = [{"name": row[0], "type": row[1], "nullable": row[2]} for row in cursor.fetchall()]
    cursor.close()
    conn.close()
    return schema

if __name__ == "__main__":
    server.run()

Security notes matter here:

  • Only allow SELECT queries—prevent destructive operations
  • Use parameterized queries in production to prevent SQL injection
  • Store credentials in environment variables, never hardcode
  • Log all queries for audit trails

The real impact: A business analyst can now ask Claude questions about their data and get insights without knowing SQL. Your database becomes conversationally accessible. That’s the power of MCP.

Deploying Your Model Context Protocol Server to Production

Local stdio transport works for development. Production needs something more robust. Here’s how to containerize and deploy your MCP server.

Step 1: Containerize with Docker

Docker provides a consistent environment across machines and integrates cleanly with cloud deployment platforms.

Dockerfile:

FROM python:3.12-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

ENV PORT=8000
EXPOSE 8000

CMD ["python", "-m", "fastmcp.server"]

requirements.txt:

fastmcp>=0.1.0
psycopg2-binary>=2.9.0
python-dotenv>=1.0.0

Build and run locally to test:

docker build -t my-mcp-server:latest .
docker run -p 8000:8000 --env-file .env my-mcp-server:latest

For production deployment, Docker’s MCP production guide covers everything from health checks to logging configuration.

Step 2: Deploy to the Cloud

You have options:

  • AWS ECS/Fargate: Container orchestration for enterprise scale
  • Railway or DigitalOcean: Simpler UX, affordable for small servers
  • Google Cloud Run: Serverless option that scales to zero
  • Heroku: Classic platform-as-a-service option

For beginners, Railway or DigitalOcean offer the easiest path—fewer moving parts, good documentation. Key configuration across all platforms:

  • Set environment variables (database credentials, API keys)
  • Expose HTTP endpoint if using Server-Sent Events transport
  • Configure health checks and automatic restarts on failure

Step 3: Test with MCP Inspector

Once deployed, use MCP Inspector to verify your server responds correctly. The Inspector shows available tools, parameter schemas, and raw JSON-RPC messages—essential for debugging.

npx mcp-inspector python -m my_mcp_server

Test each tool individually, verify parameter validation works, and check error handling before connecting your production AI agents.

Testing Your Model Context Protocol Server: Best Practices

Local Testing with Pytest

Unit tests catch bugs before they hit production:

import pytest
from calculator_server import server

def test_add():
    assert server.tools['add'](2, 3) == 5
    assert server.tools['add'](-1, 1) == 0

def test_divide_by_zero():
    result = server.tools['divide'](10, 0)
    assert result is None or "error" in str(result).lower()

def test_multiply():
    assert server.tools['multiply'](4, 5) == 20
    assert server.tools['multiply'](0, 100) == 0

Run tests with pytest test_calculator.py -v before every deployment.

Testing with a Real Host

Unit tests verify your code works. End-to-end tests verify Claude actually uses your tools correctly:

  1. Use MCP Inspector to manually test tools
  2. Connect to Claude Code and ask it to use the tools
  3. Verify parameter handling and response formatting
  4. Test error conditions and edge cases

Example test scenario: “Claude, calculate 1,542 divided by 3.14 using my calculator server.” Watch to see if the tool gets called correctly and the response comes back properly formatted.

Debugging Common Problems

Common issues and fixes:

  • Tools not appearing in host: Check if server is running and host can reach the endpoint
  • Parameter type mismatches: Verify type hints match actual types being passed
  • Timeouts: MCP calls have timeout limits—optimize slow tools or add progress notifications
  • Connection refused: Verify network access, firewall rules, and port configuration

What’s Next: Building Production-Grade MCP Servers

Publishing to the MCP Registry

Once your server is production-ready, submit it to the official registry. The community discovers and uses your server, and you contribute to an ecosystem that’s already at 2,000+ published servers and growing daily.

Registration requirements:

  • GitHub repository with proper documentation
  • README explaining what tools are exposed
  • Example configuration files
  • Clear installation instructions

Advanced Patterns for Complex Servers

As your servers get more sophisticated, explore advanced MCP features:

  • Resources: Expose documents, code files, or data for context beyond tool calls
  • Prompts: Provide pre-built prompts hosts can use for common workflows
  • Streaming: Handle long-running operations without timeouts
  • Sampling: Let the host provide input during tool execution for interactive workflows

These patterns power deeper AI integration. Check the official MCP documentation for implementation details.

The Future Is Standardized AI Integration

Key takeaways:

  1. Model Context Protocol solved the N x M integration problem that was holding back AI agent adoption
  2. Building MCP servers is surprisingly simple—FastMCP abstracts the protocol complexity
  3. Deployment is straightforward: Docker plus any cloud provider gets you production-ready
  4. Testing is essential—unit tests for your code, MCP Inspector for protocol validation, real hosts for behavior
  5. The registry is growing—your server could power the next AI-native product

As AI agents become more capable, MCP will become the standard way they access external systems. The early builders who publish quality servers will become the infrastructure layer of the AI era. The 10,000 active servers today are just the beginning.

Pick a tool or database your team uses. Wrap it in an MCP server. Try it with Claude Code. Share it with the community. The AI revolution isn’t just about better models—it’s about better integrations. MCP is how we’re standardizing those integrations. And you can be part of building that future.

Get the Daily Pulse

Sharp analysis on what's actually moving in AI. No hype, no filler, no weekly digest.

Get the Daily Pulse

Sharp AI analysis, daily. Two minutes, every morning.

Get the Daily PulseTwo minutes, every morning