This chapter gets a minimal MCP server running from scratch. By the end you will have a working server you can test locally, before connecting it to any AI client.
The official MCP Python SDK is the mcp package. Install it with:
pip install mcp
For development, also install the CLI tool that ships with it:
pip install "mcp[cli]"
This gives you the mcp command, which includes the dev subcommand for running an interactive inspector against your server.
Python version: 3.11 or newer is required. The SDK makes heavy use of modern type annotations and async features.
The SDK provides two APIs:
This book uses FastMCP for all examples. It covers the vast majority of use cases and produces clean, readable code. The low-level API is only needed for edge cases not covered here.
Here is the simplest possible MCP server:
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("hello-server")
@mcp.tool()
def greet(name: str) -> str:
"""Return a greeting for the given name."""
return f"Hello, {name}!"
if __name__ == "__main__":
mcp.run()
Full example: code/01_hello_server.py
That is the complete server. Let us break down what each part does.
mcp = FastMCP("hello-server")
FastMCP takes a name string. This name is reported to clients during the initialization handshake. Choose something descriptive.
@mcp.tool()
def greet(name: str) -> str:
"""Return a greeting for the given name."""
return f"Hello, {name}!"
The @mcp.tool() decorator registers the function as an MCP tool. The SDK automatically:
greet) as the tool nameif __name__ == "__main__":
mcp.run()
mcp.run() starts the server using stdio transport by default. This means the server reads JSON-RPC messages from stdin and writes responses to stdout. The host process manages the connection.
The mcp dev command launches a web-based inspector that lets you test your server interactively without a full AI client.
mcp dev code/01_hello_server.py
This starts your server and opens an inspector UI in your browser. From there you can:
The inspector is your primary development and debugging tool. Use it whenever you make changes to your server.
You can also run the server directly:
python code/01_hello_server.py
The server starts and waits for JSON-RPC input on stdin. It will not produce any output until a client connects and sends messages. This is normal — the server is waiting for the host to initiate the connection.
FastMCP supports both sync and async functions:
import httpx
@mcp.tool()
async def fetch_url(url: str) -> str:
"""Fetch the content of a URL."""
async with httpx.AsyncClient() as client:
response = await client.get(url)
return response.text
Use async when your tool does I/O (HTTP requests, database queries, file reads). The FastMCP event loop handles the async plumbing.
You can pass additional metadata when creating the server:
mcp = FastMCP(
"my-server",
version="1.0.0",
dependencies=["httpx", "sqlalchemy"],
)
The dependencies list is used by the mcp install command (covered in Chapter 7) to automatically set up the required packages in Claude Desktop’s environment.
For anything beyond a single tool, organize your server as a proper Python project:
my-mcp-server/
├── pyproject.toml
├── README.md
└── src/
└── my_server/
├── __init__.py
├── server.py # FastMCP instance + tool/resource/prompt definitions
└── tools/
├── __init__.py
├── search.py
└── files.py
The server.py entry point creates the FastMCP instance and imports the tool modules. Each module registers its tools against the shared instance.
pip install "mcp[cli]"FastMCP is the recommended API — decorator-based and minimal boilerplate@mcp.tool() — docstring becomes the description, type hints become the schemamcp dev server.py to test interactively with the MCP inspector| ← Chapter 1: MCP Architecture | Table of Contents | Chapter 3: Defining Tools → |