Generated using AI. Be aware that everything might not be accurate.



Chapter 2: Your First MCP Server


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.


Installing the Python SDK

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.


FastMCP: The High-Level API

The SDK provides two APIs:

  • Low-level API — gives you full control over the protocol, requires more boilerplate
  • FastMCP — a decorator-based API similar to FastAPI, handles boilerplate automatically

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.


Hello World Server

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.


Breaking Down the Code

Creating the server

mcp = FastMCP("hello-server")

FastMCP takes a name string. This name is reported to clients during the initialization handshake. Choose something descriptive.

Defining a tool

@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:

  • Uses the function name (greet) as the tool name
  • Uses the docstring as the tool description (shown to the AI model)
  • Derives the input schema from the type annotations
  • Wraps the return value in the appropriate MCP response format

Running the server

if __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.


Testing With the MCP Inspector

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:

  • See the list of tools your server exposes
  • Call tools with custom arguments and inspect the response
  • Browse resources and prompts (covered in later chapters)

The inspector is your primary development and debugging tool. Use it whenever you make changes to your server.


Running the Server Directly

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.


Async Support

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.


Server Metadata and Dependencies

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.


Project Structure

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.


Key Takeaways

  • Install the SDK with pip install "mcp[cli]"
  • FastMCP is the recommended API — decorator-based and minimal boilerplate
  • Define tools with @mcp.tool() — docstring becomes the description, type hints become the schema
  • Use mcp dev server.py to test interactively with the MCP inspector
  • Both sync and async functions are supported

← Chapter 1: MCP Architecture Table of Contents Chapter 3: Defining Tools →


>> You can subscribe to my mailing list here for a monthly update. <<