Your first MCP server in Python — Commented code
Curso MCP Engineering · M2
This is the complete version, ready to print and keep next to you, of the server we built in the lesson. It's meant to be read top to bottom: first you prepare the environment, then you write the server.py file line by line, and finally you run it and connect it to a real client to test it. You don't need to know MCP by heart: each block explains itself. Copy each snippet exactly as it is and you won't run into surprises.
The goal is deliberately minimal: a calculator with two tools (multiply and add). Once you understand this example, you understand the pattern behind any MCP server in Python.
Step 0 — What is FastMCP and why do we use it?
FastMCP is a Python library that implements the MCP protocol for you. Without it, you'd have to write all the "plumbing" by hand: the initial handshake between client and server, the exact message format, the list of tools shown to the model, the validation of incoming data… That's a lot of repetitive code and easy to get wrong. With FastMCP you focus on just one thing: what your server does. You write normal Python functions; the library exposes them as MCP tools.
Step 1 — Prepare the environment and install FastMCP
Always work inside a virtual environment (.venv). A virtual environment is a folder that isolates this project's packages from the rest of your system, so versions don't get mixed up and nothing breaks elsewhere. If you're coming from Module 0, you already have one created; activate it. If not, create it with python -m venv .venv.
# (If you don't have it yet) create the virtual environment once:
python -m venv .venv
# Activate the virtual environment
# macOS / Linux:
source .venv/bin/activate
# Windows (PowerShell):
# .venv\Scripts\Activate.ps1
# Install FastMCP inside the environment
pip install fastmcp
When the environment is active, you'll see (.venv) at the start of your terminal line. That's your signal that pip install will install the package inside the project and not system-wide. pip is Python's package installer: it downloads FastMCP from PyPI (the official repository) and leaves it ready to import.
Step 2 — The complete server.py file
Create a file called server.py in the same folder and paste this. Below the code I explain it block by block.
# server.py
# A minimal MCP server: a calculator with two tools.
# 1) We import FastMCP, the library that implements the MCP protocol for us.
from fastmcp import FastMCP
# 2) We create the server and give it a name.
# That name ("calculator") is how the client will identify it.
mcp = FastMCP("calculator")
# 3) We define a tool.
# - The decorator @mcp.tool publishes it as a tool.
# - The type hints (a: float, b: float -> float) describe inputs and output.
# - The docstring is what THE AGENT READS to decide when to use it.
@mcp.tool
def multiply(a: float, b: float) -> float:
"""Multiply two numbers."""
return a * b
# 4) A second tool, so you can see the pattern repeated.
@mcp.tool
def add(a: float, b: float) -> float:
"""Add two numbers."""
return a + b
# 5) We start the server.
# mcp.run() uses stdio by default: client and server talk through the terminal.
if __name__ == "__main__":
mcp.run()
What each block does
from fastmcp import FastMCP— brings in the library's main class. It's the only import you need for a basic server.mcp = FastMCP("calculator")— creates your server and stores it in the variablemcp. You'll "hang" all your tools on this object. The text"calculator"is the name the server presents itself with to the client.@mcp.tool— this is a decorator: a label that goes right above a function and tells FastMCP "publish this function as a tool". Without the decorator,multiplywould be an ordinary function the agent would never see.def multiply(a: float, b: float) -> float:— the type hints (a: float,-> float) declare that two decimal numbers come in and one comes out. FastMCP uses them to automatically build the tool's schema: that's how the model knows what it has to send."""Multiply two numbers."""— the docstring. It's not decorative: it's the description the model reads to decide when to call your tool. A clear, one-sentence docstring is the difference between a tool the agent uses well and one it ignores. Write it thinking "how would I explain to another person what this is for?".return a * b— the real logic. This is where your tool does its thing.if __name__ == "__main__": mcp.run()— this Python pattern means "run this only if I execute the file directly".mcp.run()sets the server listening using stdio (standard input/output) by default: client and server talk through the same terminal, ideal for running on your machine.
Remember: the docstring (the text between """...""") is what the agent reads to understand what the tool does. Write one for every tool, always.
Step 3 — Run the server
From the folder where server.py is, with the environment activated:
python server.py
If no error appears, the server is running and waiting for a client. It's normal not to see any output: a stdio server stays quiet, listening. To stop it, press Ctrl+C.
Step 4 — Connect it to Claude Code and test it
A server on its own does nothing visible: it needs a client to talk to it. The quickest way is to register it in Claude Code, pointing to the command that starts it.
# Register the server in Claude Code
claude mcp add calculator -- python server.py
# Verify it was registered
claude mcp list
# Then, inside Claude Code, try something like:
# "multiply 6 by 7" -> uses the multiply tool and returns 42
# "add 10 and 5" -> uses the add tool and returns 15
The agent will discover your tools on its own, decide which one to use, pass it the numbers and return the result to you. That back-and-forth is the MCP lifecycle, now with your own server.
Common errors (and how to fix them)
ModuleNotFoundError: No module named 'fastmcp'→ you didn't activate the environment, orpip install fastmcpran somewhere else. Activate the.venv(look for(.venv)on the line) and reinstall.command not found: python→ trypython3 server.py(andpython3 -m venv).- Claude doesn't see the tools → confirm that
claude mcp listshowscalculatorand restart the Claude Code session. If you moved the file, register it again with the correct path. - The server "does nothing" → that's expected: a stdio server sits waiting in silence. To see its tools without a client, try it with the MCP Inspector.
Checklist
- [ ] I activated the virtual environment and saw
(.venv)on the line. - [ ]
pip install fastmcpfinished without errors. - [ ] I created
server.pywith the two tools and their docstrings. - [ ]
python server.pystarts without errors. - [ ] I registered the server with
claude mcp addand the agent used my tools.
The pattern you take away
Create the server → hang tools with @mcp.tool → mcp.run(). That's the skeleton of any MCP server in Python. The rest of the course is variations on this same thing.
FastMCP is installed from PyPI with pip install fastmcp. Always work inside your virtual environment.