Understand the complete anatomy of an MCP Server—from imports to tool registration and the lifecycle of a request.
An MCP Server in Python with FastMCP is surprisingly simple. In just ~10 lines of code, you have a complete, functional server, ready to receive requests from any compatible MCP client. The structure follows a clear pattern: imports, creating the server instance, functions decorated with @mcp.tool() and the entry point. Each part has a specific and essential role in how the server works.
An MCP Server built with FastMCP has four fundamental components: Import — brings the FastMCP framework into your code; Instance — creates the server object with an identifying name; Tools — Python functions decorated with @mcp.tool() that the model can call; and Entry point — the block if __name__ == "__main__" that starts the server. With just these four pieces, you have a functional MCP server in ~10 lines of code.
The minimum structure of an MCP Server is: (1) from fastmcp import FastMCP — (2) mcp = FastMCP("meu-server") — (3) a function decorated with @mcp.tool() — (4) mcp.run() in the main block. Memorize this sequence: import → instantiate → decorate → run. Every MCP Server follows this pattern, from the simplest to the most complex.
It all starts with two lines of code: the FastMCP import and the creation of the server instance. These two lines establish the foundation on which everything else is built. The name you give the server matters—it’s how the MCP client identifies and displays the server to the user. Choose descriptive, consistent names.
Starting an MCP Server takes two steps: from fastmcp import FastMCP — imports the framework's main class — and mcp = FastMCP("nome-do-server") — creates the server instance with an identifying name. The name passed as an argument is what appears in the client (such as Claude Desktop) so the user knows which server is available. This name should be unique and descriptive of the server's purpose.
FastMCP is the official framework recommended by Anthropic for creating MCP Servers in Python. It abstracts away all the complexity of the MCP protocol (JSON-RPC, stdio/SSE transport, capability negotiation) behind a simple decorator-based API. With FastMCP, what once required hundreds of lines of low-level code now takes fewer than 10 lines. It’s the fastest and recommended way to create an MCP Server.
The heart of an MCP Server is its tools—Python functions the AI model can call. FastMCP uses the decorator @mcp.tool() to turn any regular Python function into an MCP tool the client can access. The function’s parameters become the tool’s parameters, the type hints define the schema, and the docstring becomes the description the model reads to decide when to use the tool.
The decorator @mcp.tool() is the bridge between Python and the MCP protocol. When you decorate a function with it, three things happen automatically: (1) The function name becomes the tool name; (2) Parameter type hints are converted into JSON Schema for validation; (3) The function’s docstring becomes the description the model uses to understand the tool’s purpose. No need to write a single line of configuration.
Think of the decorator @mcp.tool() as a publication badge: when you add the decorator to a function, you're saying "this function is available for the AI to use." Without the decorator, the function is just internal Python code. With it, the function becomes a server capability visible to any connected MCP client. Each decorated function is automatically registered in the server's tool list.
You write a regular Python function with type hints and a docstring—as you would in any Python project.
Add the decorator @mcp.tool() above the function—FastMCP detects and registers the tool automatically.
FastMCP extracts the name, parameters (via type hints), and description (via docstring), then generates the JSON Schema automatically.
When the client connects, the server sends the list of available tools — and the model knows exactly how to call them.
An MCP Server isn’t a program that runs and exits — it’s a process that stays active, waiting for connections and continuously processing requests. Understanding the server’s full lifecycle is essential for debugging issues, optimizing performance, and building robust servers that work reliably in production.
The lifecycle of an MCP Server follows a well-defined sequence: the server starts when the client executes it; registers its capabilities (tools, resources, prompts); waits for connections via stdio or SSE; receives requests from the client (tool calls); executes the logic of the tool call; returns the result to the client; and returns to wait the next request. This cycle repeats until the client closes the connection.
The client (e.g., Claude Desktop) runs the configured command. The Python process starts, and FastMCP loads all decorated tools.
The server sends the client a list of all available tools, resources, and prompts, along with their schemas and descriptions.
The server loops, waiting for messages from the client over the configured transport (stdio for local processes, SSE for remote ones).
When the model decides to use a tool, the client sends a JSON-RPC message with the tool name and arguments.
FastMCP locates the corresponding function, validates the parameters against the schema, and runs the Python function.
The result is serialized and sent back to the client. The server returns to a waiting state, ready for the next request.
An MCP Server can be as simple as a single Python file or as organized as a complete project with tests, documentation, and separate modules. The choice depends on the complexity of what you’re building. A minimal project is enough for learning and prototyping. For production, an organized structure makes all the difference in maintainability.
Minimal project — two files are enough: pyproject.toml (metadata and dependencies) and server.py (server code). That's all you need for a functional MCP Server. Complete project — for more robust servers, organize with: directory src/ for source code, tests/ for tests, README.md for documentation, and potentially multiple modules to separate responsibilities.
The file pyproject.toml is the configuration hub for your Python project. It defines dependencies (such as FastMCP), project metadata, and optionally entry points that make execution easier. The uv is the recommended project manager—it handles the virtual environment, dependencies, and execution quickly and reliably.
O pyproject.toml defines: the project name, the required Python version, the dependencies (including fastmcp), and optionally entry points with [project.scripts]. O uv manages everything: automatically creates the virtual environment, installs dependencies quickly, and lets you run the server with uv run server.py. Together, pyproject.toml and uv eliminate the complexity of configuring a Python environment.
Use uv init nome-do-projeto to create pyproject.toml automatically, and uv add fastmcp to add the dependency. uv will create the virtual environment, resolve dependencies, and update pyproject.toml — all in a single command. You never need to run pip install manually or manage virtualenvs by hand.
Make sure the uv is installed on your machine before you begin. Claude Desktop runs the server using the command uv run, so if uv isn’t available in PATH, the server simply won’t start — and the error may be silent. Check with uv --version before proceeding. If it isn’t installed, use curl -LsSf https://astral.sh/uv/install.sh | sh.
from fastmcp import FastMCP e mcp = FastMCP("nome") — the name identifies the server in the client.
@mcp.tool() turns Python functions into MCP tools, automatically extracting the name, parameters, and description.
uv init e uv add fastmcp to get started.
Next Module: 3.2 — Hello World MCP