How to Build a Custom MCP Server in Python for Claude: Step-by-Step Tutorial

TOC

What Is MCP (Model Context Protocol)?

MCP (Model Context Protocol) is an open standard developed by Anthropic that enables AI assistants like Claude to connect with external data sources and tools. Think of it as a universal plugin system — MCP servers expose capabilities (called “tools”) that Claude can call to interact with databases, APIs, file systems, and custom business logic.

Why Build a Custom MCP Server?

  • Connect Claude to your internal APIs — Let Claude query your company databases, CRM, or internal tools
  • Automate workflows — Give Claude the ability to trigger deployments, update tickets, or send notifications
  • Access private data — Connect Claude to data sources it can’t reach through the public internet
  • Custom business logic — Implement domain-specific calculations or transformations

Prerequisites

  • Python 3.10+
  • Claude Code or Claude Desktop installed
  • Basic familiarity with Python async/await

Step 1: Install the MCP Python SDK

pip install mcp

Step 2: Create Your Server

Create a new file called my_server.py:

from mcp.server.fastmcp import FastMCP

# Create an MCP server
mcp = FastMCP("My Custom Server")

# Define a tool
@mcp.tool()
def get_weather(city: str) -> str:
    """Get current weather for a city."""
    # Your implementation here
    return f"Weather in {city}: 72°F, Sunny"

# Define a resource
@mcp.resource("config://app")
def get_config() -> str:
    """Return application configuration."""
    return "App version: 1.0.0"

Step 3: Configure Claude to Use Your Server

Add your server to Claude’s MCP configuration:

{
  "mcpServers": {
    "my-server": {
      "command": "python",
      "args": ["path/to/my_server.py"]
    }
  }
}

Step 4: Advanced Features

Adding Database Access

import sqlite3

@mcp.tool()
def query_database(sql: str) -> str:
    """Execute a read-only SQL query."""
    conn = sqlite3.connect("mydb.sqlite")
    cursor = conn.execute(sql)
    results = cursor.fetchall()
    conn.close()
    return str(results)

Adding API Integration

import httpx

@mcp.tool()
async def fetch_api_data(endpoint: str) -> str:
    """Fetch data from an external API."""
    async with httpx.AsyncClient() as client:
        response = await client.get(f"https://api.example.com/{endpoint}")
        return response.text

Best Practices

  • Keep tools focused: Each tool should do one thing well
  • Write clear descriptions: Claude uses the docstring to understand when and how to call your tool
  • Handle errors gracefully: Return meaningful error messages, don’t let exceptions crash the server
  • Use type hints: They help Claude understand what parameters to pass
  • Implement read-only by default: Be cautious about giving write access to databases or APIs

Real-World MCP Server Ideas

  • Jira/Linear ticket management
  • Database query interface for analytics
  • CI/CD pipeline monitoring and triggering
  • Slack message sending and channel reading
  • Custom documentation search
  • Internal knowledge base access

Conclusion

Building MCP servers is one of the most powerful ways to extend Claude’s capabilities for your specific needs. Start with a simple tool, test it with Claude Code, and gradually add more functionality. The MCP ecosystem is growing rapidly, and custom servers let you stay at the forefront of AI-assisted development.

Let's share this post !

Author of this article

TOC