This tutorial walks you through building a complete MCP server in Python. For the TypeScript version, see our TypeScript tutorial.
Install
pip install mcp httpx
Create the server
from mcp.server import Server
from mcp.server.stdio import stdio_server
import httpx
server = Server("my-dev-tools")
@server.tool()
async def check_website(url: str) -> str:
"""Check if a website is responding and measure latency."""
try:
async with httpx.AsyncClient() as client:
response = await client.get(url, timeout=10)
return f"{url}: {response.status_code} ({response.elapsed.total_seconds():.2f}s)"
except Exception as e:
return f"{url}: UNREACHABLE — {str(e)}"
@server.tool()
async def count_lines(file_path: str) -> str:
"""Count lines in a file."""
try:
with open(file_path) as f:
count = sum(1 for _ in f)
return f"{file_path}: {count} lines"
except FileNotFoundError:
return f"File not found: {file_path}"
Add the transport
import asyncio
async def main():
async with stdio_server() as (read, write):
await server.run(read, write, server.create_initialization_options())
if __name__ == "__main__":
asyncio.run(main())
Connect to Claude Code
claude mcp add my-tools python /path/to/server.py
Connect to Claude Desktop
Add to config:
{
"mcpServers": {
"my-tools": {
"command": "python",
"args": ["/absolute/path/to/server.py"]
}
}
}
Using FastMCP (simpler API)
pip install fastmcp
from fastmcp import FastMCP
mcp = FastMCP("my-server")
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers."""
return a + b
mcp.run()
FastMCP handles transport, error handling, and type validation automatically.
Security
Always validate inputs and handle errors. See our MCP Security Checklist for production guidelines.
Related: Build MCP Server (TypeScript) · What is MCP? · Best MCP Servers · MCP Complete Guide