Python MCP server met FastMCP

Definitie

FastMCP is de decorator-gebaseerde Python API uit de mcp SDK (Anthropic) waarmee een Python-functie in drie regels een volwaardige MCP tool wordt. De server communiceert via stdio transport en is registreerbaar in Claude Code naast andere MCP servers.

Context

Relevant wanneer een bestaande Python-tool of CLI (met zuivere functies en geen GUI-koppeling) beschikbaar gemaakt moet worden voor Claude Code of Atelier, zonder FastAPI of web server. Eerste toepassing: pdfcraft-python (PyMuPDF, Tesseract OCR, pikepdf) als lokale PDF-toolkit.

Kernpunten

FastMCP decorator pattern

from mcp.server.fastmcp import FastMCP
 
mcp = FastMCP("tool-naam")
 
@mcp.tool()
def mijn_functie(pad: str, kwaliteit: int = 80) -> dict:
    """Beschrijving die de LLM ziet als tool-beschrijving.
 
    Args:
        pad: Absolute path naar het bestand.
        kwaliteit: JPEG kwaliteit 1-95. Default: 80.
    """
    # implementatie
    return {"result": ..., "ok": True}
 
def main():
    mcp.run(transport="stdio")

FastMCP genereert automatisch JSON Schema vanuit Python type-annotaties. De docstring wordt de description. Args:-regels worden de parameter-beschrijvingen.

Installatie en venv

/opt/homebrew/bin/python3.13 -m venv .venv
.venv/bin/pip install mcp

Python 3.13 heeft stabielere binary wheels (PyMuPDF, pikepdf, Pillow) dan 3.14 op macOS. Altijd een venv gebruiken — systeempython heeft de deps niet.

Registratie in Claude Code

In ~/.claude.json (root-level, niet ~/.claude/settings.local.json) onder mcpServers:

"tool-naam": {
  "type": "stdio",
  "command": "/absoluut/pad/naar/.venv/bin/python",
  "args": ["-m", "pakket.mcp_server"],
  "env": {}
}

Het command-pad moet absoluut zijn naar de venv Python. python3 resolveert naar systeempython zonder de benodigde packages. cwd is niet nodig: de venv-Python laadt modules relatief aan zichzelf, niet aan de werkdirectory. Zie wiki-claude-code-mcp-configuratie voor uitleg over welk configuratiebestand Claude Code leest.

MCP handshake volgorde

Bij handmatige smoke tests via stdio:

  1. Stuur initialize (met id)
  2. Stuur notifications/initialized (zonder id — dit is een notificatie, geen request)
  3. Stuur tools/list of tools/call

Zonder stap 2 reageert de server niet op tools/list.

printf '%s\n%s\n%s\n' \
  '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1"}}}' \
  '{"jsonrpc":"2.0","method":"notifications/initialized","params":{}}' \
  '{"jsonrpc":"2.0","id":3,"method":"tools/list","params":{}}' \
  | .venv/bin/python -m pakket.mcp_server 2>/dev/null

Foutafhandeling

FastMCP vangt exceptions op en converteert ze naar MCP error responses — de server crasht niet. Een FileNotFoundError of ValueError in een tool geeft een nette foutmelding terug aan de client. Geen extra try/except nodig rondom de kern-aanroep.

Input/output patroon voor bestandstools

def _resolve_input(path: str) -> Path:
    p = Path(path).expanduser().resolve()
    if not p.exists():
        raise FileNotFoundError(f"Niet gevonden: {p}")
    return p
 
def _prepare_output(path: str) -> Path:
    p = Path(path).expanduser().resolve()
    p.parent.mkdir(parents=True, exist_ok=True)
    return p

Altijd expanduser().resolve() voor paden zodat ~-expansie en relatieve paden correct werken.

pyproject.toml entry point

[project.scripts]
tool-naam-mcp = "pakket.mcp_server:main"

Na pip install -e . is het commando beschikbaar als tool-naam-mcp in de venv. Handig als alternatief voor -m pakket.mcp_server.

Verbanden

  • Zie ook: wiki-vault-mcp-architectuur (TypeScript MCP server, dezelfde stdio-principes)
  • Gerelateerd project: pdfcraft (~/Claude/projects/pdfcraft/)

Bronnen

Anthropic. (2025). Model Context Protocol Python SDK. https://github.com/modelcontextprotocol/python-sdk

Sessie-herkomst