Tutorials
How to Build a Custom Model Context Protocol (MCP) Server in 30 Lines of Python (FastMCP Guide)
Build an MCP server with FastMCP in 30 lines of Python: two real tools, Inspector testing, and a Claude Desktop hookup.

Last updated: November 6, 2026 · 4-minute read
30 lines of Python is the whole distance between a local script and a tool an AI assistant can call. Large language models are brilliant at reasoning, but they operate inside a walled garden. Unless you give them a standardized bridge to the outside world, they cannot query your local SQLite database, check internal deployment metrics, or trigger private webhooks.
In late 2024, Anthropic open-sourced the Model Context Protocol (MCP) — pitched as a USB-C port for AI applications — and by late 2026 it has become the default bridge between models and tools. Instead of writing custom function-calling wrappers for every individual model, you write an MCP server once, and any compatible assistant—Claude Desktop, Claude Code, Cursor, or Gemini—can instantly discover and execute your tools.
The best part? You do not need to understand complex low-level JSON-RPC handshakes. Using Python's official FastMCP framework, you can build a fully functional, type-safe MCP server in under 30 lines of code.
Here is how to build your first server, test it with the interactive MCP Inspector, and connect it to your local AI workflow.
Two ways exist to write an MCP server in Python. The 50-line version on this site uses the raw SDK — explicit listtools and calltool handlers, full control over the protocol. This guide uses FastMCP, the framework layer in the same SDK: decorators instead of handlers, schemas generated from type hints. Read the raw version to understand the wire; use FastMCP to ship.
How FastMCP Works
An MCP server exposes three core capabilities to an AI client:
1. Tools: Executable functions that allow the model to take actions (e.g. querying a database, writing a file, checking system status). 2. Resources: Passive, read-only data that provide background context (like documentation files, schemas, or application logs). 3. Prompts: Reusable prompt templates with pre-configured parameters.
Under the hood, FastMCP uses Python type annotations and docstrings to automatically generate JSON Schema definitions for every parameter. When the model invokes a tool, FastMCP handles parameter parsing, validation, and error serialization.
Step 1: Install the MCP Python SDK
Start by installing the official MCP package with command-line support. If you use uv, it lands in seconds:
# Or using standard pip pip install "mcp[cli]"
Step 2: Write the Server in 30 Lines
Create a file named server.py. In this example, we'll build a developer operations server that checks local system disk space and runs safe SQL queries against a local database:
import shutil import sqlite3 from mcp.server.fastmcp import FastMCP
# Initialize the FastMCP server mcp = FastMCP("DevOps Assistant")
@mcp.tool() def getdiskusage(path: str = "/") - dict: """Get total, used, and free disk space in gigabytes for a given filesystem path.""" total, used, free = shutil.diskusage(path) return { "path": path, "totalgb": round(total / (230), 2), "usedgb": round(used / (230), 2), "freegb": round(free / (230), 2), }
@mcp.tool() def querylocaldb(query: str) - list[dict]: """Execute a read-only SELECT query against the local SQLite analytics database.""" if not query.strip().lower().startswith("select"): raise ValueError("Only read-only SELECT queries are permitted.")
with sqlite3.connect("analytics.db") as conn: conn.rowfactory = sqlite3.Row cursor = conn.cursor() cursor.execute(query) rows = cursor.fetchall() return [dict(row) for row in rows]
if name == "main": mcp.run()
Notice what happened here: The @mcp.tool() decorator exposes Python functions as remote tools. The function docstrings become the exact tool descriptions the model reads to decide when to call them. Type hints (path: str = "/") automatically define required vs. optional parameters in the tool's JSON schema.
Step 3: Test with MCP Inspector
Never connect an unverified server directly to your AI client. Test it first using the web-based MCP Inspector:
This launches a local dashboard in your browser (the terminal prints the local address). In the dashboard, you can: Inspect all discovered tools and verify their auto-generated JSON schemas. Manually execute getdiskusage and inspect the returned payload. Verify that passing a non-SELECT query to querylocaldb triggers the expected error response without crashing the server.
Step 4: Connect to Your AI Client
To give your local AI desktop assistant access to your new tools, add the server to your claudedesktopconfig.json:
- macOS: ~/Library/Application Support/Claude/claudedesktopconfig.json
- Windows: %APPDATA%\Claude\claudedesktopconfig.json
- Linux: ~/.config/Claude/claudedesktopconfig.json
Add your server under the mcpServers object:
Restart Claude Desktop. You will see a small hammer icon indicating that your tools are connected. You can now prompt Claude naturally:
"Check my free disk space on root and tell me if I have enough room to pull a 15GB Docker image."
Claude will autonomously call getdiskusage(path="/"), parse the structured output, and answer you directly based on your local machine's actual disk status.
Pro Tips for Production Servers
- Enforce Strict Read-Only Guards: When building database or filesystem tools, always sanitize inputs on the server side. Never trust the LLM to only write non-destructive queries.
- Keep Descriptions Focused: The model selects tools based entirely on your docstrings. State clearly what the tool does and what it does not do to prevent false activations.
- Use Stdio for Local, SSE for Remote: By default, mcp.run() uses standard input/output (stdio), which is fastest and most secure for local apps. If you want to host an MCP server in the cloud, FastMCP supports Server-Sent Events (sse) out of the box with mcp.run(transport="sse").
That is the whole pattern: write tools as functions, let FastMCP handle the protocol, and test in the Inspector before any client sees the server. For what to connect once this works, the ranked list of MCP servers for Claude Code is the next stop.