4Geeks chosen to deliver AI education in the Bahamas alongside Harvard, Oxford, and Columbia.See more

How to Build an MCP Server in Python (Step by Step)

By 4Geeks

Build an MCP server with the official Python SDK, test it and connect it to Claude Code so the AI can use your own Python functions.

7 min readLast updated
Build an MCP server in Python icon

How do you build an MCP server in Python?

Short answer: install the official SDK with uv add "mcp[cli]" (or pip install "mcp[cli]"), create an MCPServer, turn your Python functions into tools with @mcp.tool() and call mcp.run(). Then connect it to Claude Code with claude mcp add. A complete server fits in about 20 lines:

python
from mcp.server import MCPServer
 
mcp = MCPServer("Notes")
 
notes: dict[str, str] = {}
 
 
@mcp.tool()
def add_note(title: str, text: str) -> str:
    """Save a note with a title."""
    notes[title] = text
    return f"Saved note '{title}'"
 
 
@mcp.tool()
def search_notes(query: str) -> list[str]:
    """Return the titles of the notes that contain the query."""
    q = query.lower()
    return [t for t, body in notes.items() if q in t.lower() or q in body.lower()]
 
 
if __name__ == "__main__":
    mcp.run()

The type hints (title: str) become the tool's input schema and the docstring becomes its description: the AI reads both to decide when to call it. This code uses version 2 of the SDK (mcp 2.3.0, tested with Python 3.13).

Create the project, add the SDK, connect the server to Claude Code and check that it's connected.

What an MCP server is

MCP (Model Context Protocol) is an open standard that lets AI applications such as Claude Code, Claude Desktop or Cursor use your code. An MCP server can offer three things:

What it offersWhat it's forIn Python
ToolsActions the AI can run: search, save, call an API@mcp.tool()
ResourcesData the AI can read, by URI@mcp.resource("notes://{title}")
PromptsReusable prompt templates@mcp.prompt()

The AI app is the client: it starts your server, asks which tools it has and calls them when they help with the task. If you want the theory first, read what an MCP server is.

Step 1: create the project

You need Python 3.10 or later. The SDK recommends uv to manage the project:

bash
uv init mcp-notes
cd mcp-notes
uv add "mcp[cli]"

With pip, inside a virtual environment:

bash
python -m venv .venv
source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install "mcp[cli]"

The cli extra adds the mcp command (mcp dev, mcp run, mcp install). Check it with uv run mcp version:

MCP version 2.3.0

If you don't have Python yet, see how to install Python.

Step 2: write the server

Create server.py with the code from the top of this page. You can add a resource so the AI can read one note by its URI:

python
@mcp.resource("notes://{title}")
def read_note(title: str) -> str:
    """Read one note by its title."""
    return notes.get(title, "Note not found")

Three rules that make tools work well:

  • Type every parameter. Without types the AI doesn't know what to send.
  • Write a clear docstring. It's what the AI reads to choose the tool.
  • Return simple data: text, numbers, lists or dicts. The SDK turns them into the MCP result.

mcp.run() uses the stdio transport by default: the client starts server.py as a process and talks to it through stdin and stdout. Don't use print() in a stdio server, because it writes into that channel; use logging, which writes to stderr.

Career · AI Engineering for Developers

You can give AI your own tools, now build full AI agents

Use the coding skills you already have to build AI agents, RAG systems and LLM-powered apps, with mentors and real projects.

Step 3: test it before connecting it

The quickest test is the MCP Inspector, a web page where you see your tools and call them by hand:

bash
uv run mcp dev server.py

mcp dev launches the Inspector with npx, so it needs Node.js installed. Call add_note with a title and a text, then search_notes, and check the results.

You can also test it from Python with the SDK's own client. Create client.py:

python
import asyncio
 
from mcp import Client, StdioServerParameters
 
 
async def main() -> None:
    server = StdioServerParameters(command="uv", args=["run", "server.py"])
    async with Client(server) as client:
        tools = await client.list_tools()
        print([tool.name for tool in tools.tools])
        await client.call_tool("add_note", {"title": "mcp", "text": "MCP connects AI apps to tools"})
        result = await client.call_tool("search_notes", {"query": "tools"})
        print(result.structured_content)
 
 
asyncio.run(main())
bash
uv run client.py
['add_note', 'search_notes']
{'result': ['mcp']}

Step 4: connect it to Claude Code

Register the server in Claude Code from the project folder. Everything after -- is the command Claude Code runs to start it:

bash
claude mcp add notes -- uv run --directory /full/path/to/mcp-notes server.py
claude mcp list
notes: uv run --directory /full/path/to/mcp-notes server.py - ✓ Connected

Open a session with claude and ask "save a note called ideas that says test the MCP server". Claude Code asks permission the first time it uses the tool. Inside the session, /mcp shows the connected servers. If you don't have Claude Code yet, see how to install Claude Code.

For Claude Desktop there's a shortcut that writes the app's configuration for you:

bash
uv run mcp install server.py

Step 5: run it over HTTP

stdio is for servers that run on the same computer as the client. To share a server over the network, use the Streamable HTTP transport:

bash
uv run mcp run server.py --transport streamable-http

The server listens at http://localhost:8000/mcp. Connect it to Claude Code with:

bash
claude mcp add --transport http notes http://localhost:8000/mcp

Before you put it on a public server, add authentication: anyone who reaches the URL can call your tools.

Build MCP servers with AI

An assistant like Claude Code, ChatGPT or GitHub Copilot can write most of the server if you give it the right context. These prompts are ready to copy.

1. Turn your functions into tools

Turn these Python functions into tools of an MCP server with the mcp SDK version 2
(from mcp.server import MCPServer). Add types and clear docstrings:
[paste your functions]

2. Connect an API

Write an MCP server in Python with MCPServer that offers a tool to query [API name]
with httpx. Read the API key from an environment variable and handle the errors.

3. Migrate a v1 server

This MCP server uses FastMCP from mcp.server.fastmcp (SDK version 1).
Migrate it to version 2 with MCPServer and tell me what else changes:
[paste your code]
Learn with a mentor

From one MCP server to AI agents in production

In the 4Geeks AI Engineering for Developers program you add AI agents, RAG and production LLM apps to your portfolio.

Common errors when building an MCP server in Python

What you seeWhy it happensFix
ModuleNotFoundError: No module named 'mcp.server.fastmcp'Your code (or the tutorial you copied) is for version 1 of the SDK; in version 2 FastMCP is called MCPServerUse from mcp.server import MCPServer, or pin mcp<2 to keep v1 code
ModuleNotFoundError: No module named 'mcp'The package is installed in another environment, or not installedRun the server with uv run or activate the virtual environment where you installed it
Invalid JSON: expected value at line 1 column 1 in the clientThe server writes to stdout with print() and breaks the stdio channelUse logging (it writes to stderr) instead of print()
npx not found when running mcp devThe Inspector needs Node.jsInstall Node.js, or test with the Python client
Failed to connect in claude mcp listClaude Code can't start the command: wrong path or wrong PythonUse absolute paths and uv run --directory, and test the same command in the terminal
'Tool' object has no attribute 'inputSchema'In version 2 the client models use snake_caseUse input_schema, structured_content

v1 or v2 of the SDK?

Many tutorials still use version 1. These are the changes you'll notice first:

SDK version 1SDK version 2
from mcp.server.fastmcp import FastMCPfrom mcp.server import MCPServer
mcp = FastMCP("Notes")mcp = MCPServer("Notes")
tool.inputSchematool.input_schema
Client with stdio_client and ClientSessionasync with Client(...)

The decorators (@mcp.tool(), @mcp.resource(), @mcp.prompt()) and mcp.run() work the same way.

Free download

MCP servers in Python in a 2-page cheat sheet

Install the SDK, a complete server, tools, resources and prompts, testing, Claude Code, HTTP and the most common errors. Free, in PDF.

MCP server in Python cheat sheet

2 pages · PDF · 4Geeks

  • A complete, tested server you can copy
  • How to test it and connect it to Claude Code
  • SDK v1 vs v2 and the most common errors

Get it free

Your PDF right away

Frequently asked questions about MCP servers in Python

Want to go from one MCP server to building AI agents, with real projects and mentors?

See the AI Engineering for Developers program