- Create a Python virtual environment
- Expose simple tools:
add,divide, andlong_process - Return structured errors via a custom
MCPErrorexception - Run and test the server locally with the MCP Inspector
- Add logging to capture server activity
- Setting up the project
- Minimal starter
main.py - Adding FastMCP and an
addtool - Run the dev server and use the Inspector
- Add error handling with
divide - Simulate long-running work (
long_process) - Transports and stdout warning
- Add logging
- Full consolidated example
- Wrap-up and references
Setting up the project
Create a project and a virtual environment. This example uses theuv helper shown in this guide, but you can substitute with python -m venv .venv if preferred.
Minimal starter main.py
Start with a simple script to validate your environment:Adding FastMCP and a simple add tool
Install FastMCP (example uses uv add):
main.py with a first MCP server that exposes a simple add tool:
http://localhost:6274). Open the Inspector and authenticate by appending the query parameter shown in the console, for example:
http://localhost:6274/?MCP_PROXY_AUTH_TOKEN=<token>#resources
(When copying, replace <token> with the value printed in your console.)
Using the Inspector you can list tools, view tool docstrings (used as descriptions), and call tools. For example:
- Calling
add(3, 5)returns:
Adding structured error handling with divide
Introduce a small MCPError exception and add a divide tool that returns structured errors to callers:
mcp dev main.py again. The Inspector now shows both add and divide. Example responses:
- Successful call
divide(24, 2):
- Error case
divide(12, 0)— the Inspector and client will show the structured error message similar to:
Simulating long-running work
Some tools need to perform long-running tasks. Addlong_process to simulate a multi-step job and show how STDIO behaves with longer processing times.
Warning: writing arbitrary text to stdout while using the STDIO transport can corrupt the MCP message stream. Use logging or the library’s streaming/event APIs for progress updates.
Avoid printing arbitrary text to stdout when using the STDIO transport — it can interfere with the MCP protocol and break communication. Use logging or FastMCP’s streaming features for progress reporting.
long_process that uses logging (preferred):
long_process(10) from the Inspector to see how the server performs a short job. Increasing steps (e.g., long_process(100)) may trigger client or server timeouts depending on configured timeouts; timeouts are configurable on the server side.
Transports and the Inspector
STDIO is convenient for local development and tooling. FastMCP and the MCP Inspector also support other transports (for example, SSE or HTTP) when you need to expose your MCP server to other processes or to a network.
Adding logging
Enable Python logging to capture server activity in a file and to emit progress or input/output info from tools. Top-level logging setup:mcp_server.log will include entries similar to:
Full consolidated example
A compactmain.py that combines the pieces:
Wrap-up
What you accomplished in this lesson:- Exposed functions as MCP tools using
@mcp.tool() - Used docstrings for tool descriptions and argument schemas
- Implemented structured errors with
MCPError - Simulated long-running tasks and accounted for timeouts
- Added logging to persist server events to a logfile
- Ran and inspected the server locally via the MCP Inspector (STDIO transport)
- FastMCP / MCP docs (check your installed package for local docs)
- Python venv documentation
- [MCP Inspector — local UI] — (open
http://localhost:6274when runningmcp dev)