MCP Forge

How to build an MCP server in Python with FastMCP

A practical guide. Updated 2026.

The Model Context Protocol (MCP) lets a language model call your code through a small, typed interface. In Python the fastest way to ship one is FastMCP, the high-level API that now lives inside the official mcp SDK. You write plain functions, decorate them, and the SDK handles the protocol, the JSON-RPC plumbing, and the schema generation. This walkthrough builds a working server, runs it, connects it to Claude and Cursor, and wires in the security basics that matter before anyone else points a client at it.

Install the SDK

You need Python 3.10 or newer. Use uv if you have it, since it is what most MCP tooling assumes, but plain pip works fine too. The cli extra pulls in the dev runner and inspector.

uv add "mcp[cli]"
# or
pip install "mcp[cli]"

Define a tool

A tool is just a typed function. FastMCP reads your type hints and docstring and turns them into the JSON schema the model sees, so annotate everything. The docstring is not decoration, it is the description the model reads to decide when to call the tool. Keep it specific.

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("weather-tools")

@mcp.tool()
def convert_temp(value: float, to: str) -> str:
    """Convert a temperature. 'to' must be 'c' or 'f'."""
    to = to.lower()
    if to == "c":
        return f"{(value - 32) * 5 / 9:.1f} C"
    if to == "f":
        return f"{value * 9 / 5 + 32:.1f} F"
    raise ValueError("to must be 'c' or 'f'")

if __name__ == "__main__":
    mcp.run()

By default mcp.run() speaks over stdio, which is what desktop clients like Claude Desktop and Cursor launch and talk to directly. No port, no HTTP, just a subprocess.

Run and inspect it

Before touching any client, run the server against the MCP Inspector. It gives you a UI to list tools, see the generated schema, and call them by hand. This catches bad type hints and confusing descriptions early.

uv run mcp dev server.py

The inspector opens in your browser. Confirm convert_temp shows up with the right parameters, call it with a sample value, and check the result. If the schema looks wrong here, it will look wrong to the model too.

Connect it to Claude or Cursor

Both clients read a JSON config that tells them how to launch your server as a subprocess. For Claude Desktop, edit claude_desktop_config.json (Settings, Developer, Edit Config). Cursor uses ~/.cursor/mcp.json or a project-level .cursor/mcp.json. The shape is the same:

{
  "mcpServers": {
    "weather-tools": {
      "command": "uv",
      "args": ["run", "--directory", "/abs/path/to/project", "server.py"]
    }
  }
}

Use an absolute path, since the client does not run from your project directory. Restart the client, and the tool appears in the tool list. A few things to watch:

Bake in the security basics

An MCP tool is a function the model can be steered into calling by anything it reads, including a web page or a file. So treat every argument as hostile from the start, not as a later hardening pass.

When the server feels done, scan it before you publish. The free, open-source mcp-audit walks your server and flags the common failures: unbounded inputs, unguarded fetches, missing auth, and tools whose schemas leak more than they should. It is a fast sanity check that catches the mistakes this list is meant to prevent.

Next steps

From here you can add resources (read-only context the model can pull in) and prompts (reusable templates) with the same decorator style: @mcp.resource() and @mcp.prompt(). The pattern stays the same, typed functions in, protocol handled for you. Get one tool solid, audited, and connected first, then grow the surface deliberately.

Ship a production-ready Python MCP server faster

MCP Forge Kit gives you a FastMCP server with validated example tools, an SSRF-safe fetch utility, auth and rate limiting at the edge, tests, and CI already wired, so you build features instead of boilerplate.

Get MCP Forge Kit, €39

Related: Write a secure tool · Claude and Cursor setup · SSRF protection