Zum Inhalt springen
sobolewski.proKI heute, jeden AbendAbonnieren

Einmal täglich. Abmelden mit einem Klick. Datenschutz

MCP-Server bauen mit Python: Anleitung Schritt für Schritt

Einen MCP-Server bauen: Wir schreiben eigene Tools in Python mit dem SDK 2.0, testen sie im MCP Inspector und binden sie an Claude Code und Claude Desktop an.

7 Min. Lesezeit

Dieser Artikel in anderen Sprachen:العربيةEnglishEspañolFrançaisItaliano日本語Polski简体中文

In diesem Artikel
  1. Was brauchen wir?
  2. Schritt 1: Wie richten wir das Projekt ein?
  3. Schritt 2: Wie kann man einen MCP-Server bauen und das erste Tool schreiben?
  4. Schritt 3: Warum ist print() tabu?
  5. Schritt 4: Wie testen wir den Server im MCP Inspector?
  6. Schritt 5: Wie binden wir den Server an Claude Code an?
  7. Schritt 6: Wie fügen wir den Server in Claude Desktop hinzu?
  8. Schritt 7: Wie starten wir den MCP-Server über HTTP?
  9. Worauf solltest du achten?
  10. FAQ

Wie kann man einen MCP-Server bauen? In Python reichen eine Datei und das offizielle MCP Python SDK: Wir schreiben eine gewöhnliche Funktion mit Typangaben und Docstring, setzen den Dekorator @mcp.tool() davor, und das SDK macht daraus ein Tool, das Claude, ChatGPT oder Cursor aufrufen können. Der komplette Server aus dem Beispiel in der Dokumentation ist keine zwanzig Zeilen lang.

In dieser Anleitung schreiben wir einen Server von Grund auf, testen ihn im MCP Inspector und binden ihn an Claude Code und Claude Desktop an. Befehle und Code stammen aus dem offiziellen Tutorial „Build an MCP server“, dem README des SDK und der Dokumentation von Claude Code.

Was brauchen wir?

Ich gehe davon aus, dass du schon weißt, was MCP ist, also Host, Client, Server und Tools (falls nicht, fang mit der Anleitung Was ist MCP an). Für die Arbeit brauchen wir:

  1. Python 3.11+ (so viel verlangt das README des aktuellen SDK),
  2. den Paketmanager uv, den das offizielle Tutorial verwendet,
  3. Node.js 22.19.0 oder neuer, wenn wir den Server im MCP Inspector testen wollen,
  4. einen MCP-Host, um das Ganze auszuprobieren, zum Beispiel Claude Code oder Claude Desktop.

Ein wichtiger Hinweis vorab: In Version 2.0 des SDK heißt die Hauptklasse anders. Laut der Übersicht der Änderungen in v2 wird aus dem früheren from mcp.server.fastmcp import FastMCP jetzt from mcp.server import MCPServer. Viele Anleitungen im Netz zeigen noch die alte Version, das offizielle Tutorial verlangt aber SDK 2.0.0 oder neuer.

Schritt 1: Wie richten wir das Projekt ein?

Zuerst installieren wir uv (macOS und Linux):

curl -LsSf https://astral.sh/uv/install.sh | sh

Unter Windows in der PowerShell:

powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

Nach der Installation starten wir das Terminal neu, damit der Befehl uv gefunden wird. Dann legen wir das Projekt an und installieren das SDK:

uv init mein-server
cd mein-server
uv venv
source .venv/bin/activate
uv add "mcp[cli]"
touch server.py

Der Zusatz [cli] installiert den Befehl mcp (mit den Unterbefehlen mcp dev, mcp run und mcp install), den wir später zum Testen brauchen (unter Windows aktivieren wir die Umgebung mit .venv\Scripts\activate).

Schritt 2: Wie kann man einen MCP-Server bauen und das erste Tool schreiben?

In die Datei server.py kommt das Beispiel aus dem README des SDK, und ans Ende schreiben wir den Start des Servers, so wie im offiziellen Tutorial:

from mcp.server import MCPServer

mcp = MCPServer("Demo")


@mcp.tool()
def add(a: int, b: int) -> int:
    """Add two numbers."""
    return a + b


@mcp.resource("greeting://{name}")
def greeting(name: str) -> str:
    """Greet someone by name."""
    return f"Hello, {name}!"


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

Das ist ein vollständiger MCP-Server: ein Tool (add) und eine Ressource mit einer Adressvorlage (greeting://{name}). Spannend finde ich, dass wir kein JSON Schema schreiben. Laut README ist die Signatur a: int, b: int das Schema, und der Docstring wird zur Beschreibung des Tools, die das Modell liest. Das Parsen der Anfragen, die Validierung und das Protokoll übernimmt das SDK.

Deshalb lohnt sich Sorgfalt bei den Docstrings. Das Modell wählt ein Tool anhand von Name und Beschreibung aus, „Add two numbers.“ ist also das Minimum. Bei echten Tools beschreiben wir auch die Argumente, so wie im offiziellen Wetterbeispiel:

@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:
    """Get weather forecast for a location.

    Args:
        latitude: Latitude of the location
        longitude: Longitude of the location
    """

(dieses Beispiel nutzt die API des US-Wetterdienstes NWS und funktioniert deshalb nur für Orte in den USA)

Schritt 3: Warum ist print() tabu?

Das ist der häufigste Fehler beim ersten Server. Ein lokaler Server spricht mit dem Host über die Standardein- und -ausgabe (stdio), und die Nachrichten haben das Format JSON-RPC. Die Dokumentation warnt ausdrücklich: Wer nach stdout schreibt, beschädigt die JSON-RPC-Nachrichten und legt den Server lahm, und print() schreibt standardmäßig genau dorthin.

Stattdessen nehmen wir das Modul logging, das nach stderr schreibt:

import logging

logger = logging.getLogger(__name__)

logger.info("Processing request")  # landet auf stderr

Bei HTTP-Servern gibt es das Problem nicht, weil sich Logs auf stdout nicht mit den HTTP-Antworten vermischen.

Schritt 4: Wie testen wir den Server im MCP Inspector?

Der MCP Inspector ist das offizielle Werkzeug zum Testen von Servern. Mit dem SDK starten wir ihn mit einem einzigen Befehl:

uv run mcp dev server.py

Es öffnet sich der Browser mit dem Inspector. Laut README liefert der Aufruf von add mit den Argumenten a=1 und b=2 das Ergebnis 3. An derselben Stelle sehen wir die Liste der Tools und Ressourcen und die rohen JSON-RPC-Nachrichten, was bei der Fehlersuche viel Zeit spart.

Den Inspector gibt es auch als Terminalversion (--tui) und mit einem Modus für Skripte (--cli). Dieser gibt zum Beispiel die Liste der Tools aus und beendet sich, eignet sich also für CI:

npx @modelcontextprotocol/inspector --cli uv run server.py --method tools/list

(prüfe deine Node.js-Version mit node --version, der Inspector verlangt 22.19.0 oder neuer)

Schritt 5: Wie binden wir den Server an Claude Code an?

Einen lokalen Server fügen wir als stdio-Server hinzu. Alles nach -- ist der Befehl, den Claude Code ausführt:

claude mcp add --transport stdio demo -- uv --directory /VOLLER/PFAD/mein-server run server.py

Der Pfad muss absolut sein (wir bekommen ihn mit pwd im Projektverzeichnis). Den Verbindungsstatus zeigt claude mcp get demo, in einer Claude-Code-Sitzung der Befehl /mcp. Jetzt können wir zum Beispiel „addiere 1234 und 5678 mit dem Tool add“ eintippen und den Aufruf bestätigen.

Zwei Dinge aus der Dokumentation von Claude Code helfen gleich am Anfang:

  1. die Startzeit des Servers ändern wir mit der Variable MCP_TIMEOUT, zum Beispiel gibt MCP_TIMEOUT=10000 claude dem Server 10 Sekunden,
  2. Claude Code warnt, wenn das Ergebnis eines Tools 10.000 Token überschreitet, und schneidet es standardmäßig bei 25.000 Token ab (das Limit ändert die Variable MAX_MCP_OUTPUT_TOKENS), Tools sollten also keine ganzen Datenbanken zurückgeben.

Schritt 6: Wie fügen wir den Server in Claude Desktop hinzu?

In Claude Desktop tragen wir lokale Server in die Konfigurationsdatei claude_desktop_config.json ein. Sie liegt unter macOS in ~/Library/Application Support/Claude/, unter Linux in ~/.config/Claude/ und unter Windows in %AppData%\Claude\ (wenn es sie noch nicht gibt, legen wir sie an). Der Eintrag sieht so aus:

{
  "mcpServers": {
    "demo": {
      "command": "uv",
      "args": [
        "--directory",
        "/VOLLER/PFAD/mein-server",
        "run",
        "server.py"
      ]
    }
  }
}

Danach beenden wir die App vollständig (unter macOS mit Cmd+Q, das Fenster zu schließen reicht nicht) und starten sie neu. Der Server sollte im Menü „Connectors“ unter dem Plus-Symbol auftauchen. Fehlt er, rät die Dokumentation, die JSON-Syntax zu prüfen, außerdem ob der Pfad absolut ist, und im Feld command den vollständigen Pfad zu uv einzutragen (den zeigt which uv). Die Logs liegen in ~/Library/Logs/Claude (macOS) oder ~/.config/Claude/logs/ (Linux), in den Dateien mcp.log und mcp-server-NAME.log.

Schritt 7: Wie starten wir den MCP-Server über HTTP?

Ein stdio-Server läuft nur auf unserem eigenen Rechner. Um ihn als Remote-Server bereitzustellen, starten wir ihn über Streamable HTTP, also den Transport, den man laut README des SDK in Produktion einsetzt:

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

Der Server lauscht dann unter http://localhost:8000/mcp, und in Claude Code fügen wir ihn wie jeden Remote-Server hinzu:

claude mcp add --transport http demo-http http://localhost:8000/mcp

Damit so ein Server in der Claude-App im Browser als sogenannter „custom connector“ funktioniert, muss er aus dem Internet erreichbar sein, denn Claude verbindet sich aus der Cloud von Anthropic mit ihm. Dann braucht er auch eine Anmeldung: Die MCP-Dokumentation beschreibt die Autorisierung von Servern über OAuth 2.1.

Worauf solltest du achten?

Erstens darauf, was ein Tool erlaubt. Ein MCP-Server gibt dem Modell echte Handlungsmöglichkeiten auf unserem Rechner, also schneiden wir Tools so eng wie möglich zu: lieber „lies eine Datei aus diesem Verzeichnis“ als „führe einen beliebigen Befehl aus“.

Zweitens auf Daten von außen. Holt ein Tool Inhalte aus dem Internet oder aus E-Mails, kann es Prompt Injection mitbringen, also versteckte Anweisungen an das Modell. Mehr dazu steht in meiner Anleitung KI-Agenten-Sicherheit.

Drittens auf Geheimnisse. API-Schlüssel übergeben wir über Umgebungsvariablen (--env in Claude Code) und schreiben sie nicht in den Code. Laut Dokumentation speichert der Inspector Token im Schlüsselbund des Systems, und wenn es keinen gibt (etwa im Container), in der unverschlüsselten Datei ~/.mcp-inspector/secrets.json.

Einen solchen Server können wir später auch an einen eigenen Agenten anbinden. Wie das geht, zeige ich in der Anleitung KI-Agent erstellen mit Python.

FAQ

Wie kann ich am einfachsten einen MCP-Server bauen?

Der einfachste Server aus dem README des SDK ist keine zwanzig Zeilen lang: ein MCPServer-Objekt, eine Funktion mit dem Dekorator @mcp.tool() und mcp.run(). Den Rest, also das Schema der Argumente und die Abwicklung des Protokolls, erledigt das SDK.

Was ist FastMCP?

Der frühere Name der Hauptklasse des Servers im MCP Python SDK. In Version 2.0 wurde sie in MCPServer umbenannt, der Import lautet from mcp.server import MCPServer.

Kann man einen MCP-Server auch in einer anderen Sprache als Python schreiben?

Ja. Das offizielle Tutorial gibt es unter anderem für TypeScript, Java, Kotlin, C#, Ruby, Rust und Go.

Funktioniert ein MCP-Server nur mit Claude?

Nein. MCP ist ein offener Standard, derselbe Server läuft also in jedem Host, der das Protokoll unterstützt, zum Beispiel in ChatGPT, Visual Studio Code oder Cursor.

  • KI
  • KI-Agenten
  • Claude Code
  • Programmierung
  • Anleitung

KI heute, jeden Abend

Jeden Abend die wichtigsten KI-News des Tages und neue Blogbeiträge. Kurz und mit Quellen.

Einmal täglich. Abmelden mit einem Klick. Datenschutz