Build Your First MCP Server in 30 Minutes
Step-by-step walkthrough of building a working MCP server using the Python SDK. Define tools and resources, expose them over stdio transport, register with Claude Desktop, and call them from Claude. Every line of code explained.
The fastest way to understand MCP is to build a server. This walkthrough takes you from zero to a working MCP server registered with Claude Desktop — with every line of code explained.
Step 1: Install the Python SDK
pip install mcp
Step 2: Define the server and expose a tool
from mcp.server import Server
from mcp.server.models import InitializationOptions
from mcp import types
import mcp.server.stdio
app = Server("my-tools")
@app.list_tools()
async def list_tools() -> list[types.Tool]:
return [
types.Tool(
name="get_weather",
description="Get current weather for a city",
inputSchema={
"type": "object",
"properties": {
"city": {"type": "string", "description": "City name"}
},
"required": ["city"]
}
)
]
@app.call_tool()
async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
if name == "get_weather":
city = arguments["city"]
# Your real API call here
return [types.TextContent(type="text", text=f"Weather in {city}: 22°C, partly cloudy")]
raise ValueError(f"Unknown tool: {name}")
Step 3: Add a resource
@app.list_resources()
async def list_resources() -> list[types.Resource]:
return [
types.Resource(
uri="weather://forecast/today",
name="Today's Forecast",
description="Current day weather summary",
mimeType="text/plain"
)
]
@app.read_resource()
async def read_resource(uri: str) -> str:
if uri == "weather://forecast/today":
return "Mostly sunny, high 24°C, low 15°C"
raise ValueError(f"Unknown resource: {uri}")
Step 4: Run the server
async def main():
async with mcp.server.stdio.stdio_server() as (read, write):
await app.run(read, write, InitializationOptions(
server_name="my-tools",
server_version="0.1.0",
capabilities=app.get_capabilities()
))
if __name__ == "__main__":
import asyncio
asyncio.run(main())
Step 5: Register with Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"my-tools": {
"command": "python",
"args": ["/absolute/path/to/your/server.py"]
}
}
}
Restart Claude Desktop. Claude now has access to your tool and can call it mid-conversation.
The full server is ~60 lines of Python. MCP is intentionally simple — the protocol complexity lives in the SDK, not your code.
Try it interactively
GenAI Systems Lab is a free platform for AI engineers — configure real failure modes, break things, and build the judgment that gets you hired.
Open GenAI Systems Lab →