MCP-Server mit Python bauen: Praxis-Tutorial für KI-Tool-Integration

Eigenen MCP-Server mit Python und FastMCP bauen – vom ersten Tool über SQLite-Datenbankanbindung bis zum produktionsreifen Deployment mit Streamable HTTP. Mit komplettem, lauffähigem Code.

Warum das Model Context Protocol 2026 den Standard für KI-Integrationen setzt

Stellen Sie sich mal vor, Ihr KI-Agent könnte direkt auf Ihre Firmendatenbank zugreifen, Ihre internen APIs aufrufen und das Ganze über ein einziges, standardisiertes Protokoll abwickeln. Kein mühsames Basteln an Custom-Konnektoren für jede einzelne Datenquelle. Keine proprietären Plugin-Systeme, die beim nächsten API-Update auseinanderfallen.

Klingt gut? Genau das ermöglicht das Model Context Protocol (MCP).

2026 hat sich MCP zum De-facto-Standard für die Anbindung von Large Language Models an externe Systeme entwickelt. Ursprünglich von Anthropic im November 2024 als Open-Source-Projekt veröffentlicht, wird es inzwischen von der Agentic AI Foundation unter dem Dach der Linux Foundation verwaltet — unterstützt von Anthropic, OpenAI und Block. Dass gleich mehrere Branchengrößen dahinterstehen, ist kein Zufall: MCP löst ein echtes, fundamentales Problem.

Nämlich das sogenannte M×N-Problem: Wenn Sie M verschiedene KI-Modelle mit N verschiedenen Datenquellen verbinden wollen, brauchen Sie ohne Standard M×N individuelle Integrationen. Mit MCP als universeller Schnittstelle reduziert sich das auf M+N. Denken Sie an USB-C — ein Anschluss für alles. Genau dieses Prinzip überträgt MCP auf die KI-Welt.

In diesem Tutorial bauen wir gemeinsam einen vollständigen MCP-Server mit Python — von der Installation über Tools und Ressourcen bis hin zum Deployment mit Streamable HTTP. Schritt für Schritt, mit funktionierendem Code, den Sie direkt in Ihren eigenen Projekten einsetzen können.

MCP-Architektur verstehen: Host, Client und Server

Bevor wir Code schreiben, sollten wir kurz die Architektur verstehen. MCP basiert auf einem klassischen Client-Server-Modell mit drei klar definierten Rollen:

  • MCP-Host: Die Anwendung, mit der Sie direkt interagieren — etwa Claude Desktop, Cursor, ChatGPT oder eine eigene Chat-Oberfläche. Der Host enthält das LLM und orchestriert die Kommunikation.
  • MCP-Client: Lebt innerhalb des Hosts und verwaltet die 1:1-Verbindung zu einem bestimmten MCP-Server. Er übersetzt LLM-Anfragen in MCP-konforme Nachrichten und umgekehrt.
  • MCP-Server: Ein externer Dienst, der dem LLM Tools (aufrufbare Funktionen), Resources (lesbare Daten) und Prompts (wiederverwendbare Vorlagen) bereitstellt. Genau diesen Server werden wir gleich bauen.

Die Kommunikation läuft über JSON-RPC 2.0 und beginnt immer mit einem Handshake (Capability Discovery): Client und Server tauschen Informationen über unterstützte Protokollversionen und verfügbare Fähigkeiten aus. Erst danach kann der Client die Tools, Resources und Prompts des Servers abfragen und nutzen.

Die drei Kernprimitive

Jeder MCP-Server bietet bis zu drei Arten von Fähigkeiten an:

  1. Tools: Funktionen, die das LLM aktiv aufrufen kann — eine Datenbankabfrage, eine API-Anfrage oder eine Berechnung. Tools verändern potenziell den Zustand und erfordern daher in der Regel eine Nutzerfreigabe.
  2. Resources: Schreibgeschützte Datenquellen, die das LLM in seinen Kontext laden kann — etwa ein Datenbankschema, eine Konfigurationsdatei oder aktuelle Sensordaten. Hier besteht kein Risiko von Seiteneffekten.
  3. Prompts: Vorgefertigte Prompt-Vorlagen für wiederkehrende Aufgaben — zum Beispiel ein Template für Code-Reviews oder Datenanalysen. Ehrlich gesagt werden Prompts in der Praxis seltener genutzt als Tools und Resources, aber sie sind trotzdem ein nützliches Feature.

Entwicklungsumgebung einrichten: Python und MCP SDK installieren

Für dieses Tutorial brauchen Sie Python 3.10 oder höher. Als Paketmanager empfiehlt das MCP-Team uv — einen modernen, extrem schnellen Python-Projektmanager, der pip und virtualenv in einem Werkzeug vereint.

Option A: Mit uv (empfohlen)

# uv installieren (falls noch nicht vorhanden)
curl -LsSf https://astral.sh/uv/install.sh | sh

# Projektverzeichnis erstellen und initialisieren
uv init mein-mcp-server
cd mein-mcp-server

# MCP SDK mit CLI-Tools hinzufügen
uv add "mcp[cli]"

Option B: Mit pip und venv

# Projektverzeichnis erstellen
mkdir mein-mcp-server && cd mein-mcp-server

# Virtuelle Umgebung anlegen und aktivieren
python -m venv .venv
source .venv/bin/activate    # macOS/Linux
# .venv\Scripts\activate     # Windows

# MCP SDK installieren
pip install "mcp[cli]"

Das mcp-Paket enthält die Klasse FastMCP, die den Aufbau von MCP-Servern wirklich radikal vereinfacht. Sie nutzt Python-Typannotationen und Docstrings, um Tool-Definitionen, Validierung und Protokollkonformität automatisch zu generieren. Wer schon mal versucht hat, einen ähnlichen Server von Hand mit JSON-Schema aufzusetzen, wird den Unterschied sofort merken.

Der erste MCP-Server: Schritt für Schritt

Also, legen wir los. Wir beginnen mit einem einfachen Server, der ein Rechenwerkzeug und eine Begrüßungsressource bereitstellt — klein genug zum Verstehen, groß genug für echte Lerneffekte.

Erstellen Sie eine Datei server.py:

from mcp.server.fastmcp import FastMCP

# MCP-Server initialisieren
mcp = FastMCP("MeinErsterServer")


# === TOOLS ===

@mcp.tool()
def addiere(a: float, b: float) -> float:
    """Addiert zwei Zahlen und gibt das Ergebnis zurueck."""
    return a + b


@mcp.tool()
def multipliziere(a: float, b: float) -> float:
    """Multipliziert zwei Zahlen miteinander."""
    return a * b


# === RESOURCES ===

@mcp.resource("info://serverversion")
def get_server_version() -> str:
    """Gibt die aktuelle Serverversion zurueck."""
    return "MeinErsterServer v1.0.0 – MCP-Tutorial 2026"


@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
    """Erzeugt eine personalisierte Begruessung."""
    return f"Hallo {name}! Willkommen beim MCP-Server."


# === PROMPTS ===

@mcp.prompt()
def analyse_prompt(thema: str) -> str:
    """Erstellt einen strukturierten Analyse-Prompt."""
    return f"""Bitte analysiere das folgende Thema strukturiert:

Thema: {thema}

Gehe dabei auf folgende Punkte ein:
1. Aktuelle Situation und Kontext
2. Zentrale Herausforderungen
3. Moegliche Loesungsansaetze
4. Empfohlene naechste Schritte"""


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

Schauen wir uns den Code mal genauer an:

  • FastMCP-Initialisierung: FastMCP("MeinErsterServer") erstellt eine Server-Instanz mit einem Namen, der bei der Capability Discovery an den Client übermittelt wird.
  • @mcp.tool(): Jede damit dekorierte Funktion wird zu einem aufrufbaren Tool. FastMCP leitet aus den Typannotationen (a: float, b: float) automatisch das JSON-Schema ab, das der Client für die Parametervalidierung braucht. Der Docstring wird zur Toolbeschreibung — das ist wichtig, denn nur so versteht das LLM, wann es das Tool einsetzen soll.
  • @mcp.resource(): Stellt schreibgeschützte Daten bereit. Die URI greeting://{name} enthält einen Platzhalter — der Client kann also greeting://Anna anfragen und bekommt eine personalisierte Antwort.
  • @mcp.prompt(): Registriert eine wiederverwendbare Prompt-Vorlage. Der Client kann sie mit Argumenten aufrufen, und das LLM erhält den fertigen Prompt.
  • mcp.run(transport="stdio"): Startet den Server mit STDIO-Transport — ideal für die lokale Entwicklung mit Claude Desktop oder Cursor.

Server testen mit dem MCP Inspector

Das MCP SDK bringt ein richtig praktisches Debugging-Tool mit — den MCP Inspector. Starten Sie ihn so:

# Mit uv
uv run mcp dev server.py

# Oder mit npx
npx @modelcontextprotocol/inspector uv run server.py

Der Inspector öffnet eine Weboberfläche, in der Sie alle registrierten Tools, Resources und Prompts sehen und interaktiv testen können. Gerade am Anfang ist das Gold wert für die Fehlersuche.

Praxis-Projekt: Datenbank-MCP-Server mit SQLite

Jetzt wird es spannend. Wir bauen einen MCP-Server, der einem KI-Agenten kontrollierten Zugriff auf eine SQLite-Datenbank ermöglicht — mit Leserechten für Schemata und einem sicheren, schreibgeschützten Query-Tool.

Erstellen Sie eine Datei db_server.py:

import sqlite3
import json
from pathlib import Path
from mcp.server.fastmcp import FastMCP

# Konfiguration
DB_PATH = Path("produkte.db")
mcp = FastMCP("DatenbankServer")


def get_connection() -> sqlite3.Connection:
    """Erstellt eine schreibgeschuetzte Datenbankverbindung."""
    conn = sqlite3.connect(str(DB_PATH))
    conn.row_factory = sqlite3.Row
    conn.execute("PRAGMA query_only = ON")
    return conn


def init_demo_db():
    """Erstellt eine Demo-Datenbank mit Beispieldaten."""
    conn = sqlite3.connect(str(DB_PATH))
    conn.executescript("""
        CREATE TABLE IF NOT EXISTS produkte (
            id INTEGER PRIMARY KEY,
            name TEXT NOT NULL,
            kategorie TEXT NOT NULL,
            preis REAL NOT NULL,
            bestand INTEGER DEFAULT 0
        );
        INSERT OR IGNORE INTO produkte (id, name, kategorie, preis, bestand)
        VALUES
            (1, 'Widget Pro', 'Elektronik', 29.99, 150),
            (2, 'Gadget Mini', 'Elektronik', 14.99, 300),
            (3, 'Buerostuhl Komfort', 'Bueromoebel', 249.00, 45),
            (4, 'Schreibtischlampe LED', 'Bueromoebel', 39.99, 200),
            (5, 'USB-C Hub 7-Port', 'Zubehoer', 34.99, 500);
    """)
    conn.commit()
    conn.close()


# === RESOURCES ===

@mcp.resource("schema://tables")
def get_table_schema() -> str:
    """Gibt das Schema aller Tabellen in der Datenbank zurueck."""
    conn = get_connection()
    cursor = conn.execute(
        "SELECT sql FROM sqlite_master WHERE type='table' AND sql IS NOT NULL"
    )
    schemas = [row[0] for row in cursor.fetchall()]
    conn.close()
    return "\n\n".join(schemas)


@mcp.resource("stats://overview")
def get_db_stats() -> str:
    """Liefert eine Uebersicht ueber die Datenbank-Statistiken."""
    conn = get_connection()
    tables = conn.execute(
        "SELECT name FROM sqlite_master WHERE type='table'"
    ).fetchall()

    stats = {}
    for table in tables:
        name = table[0]
        count = conn.execute(f"SELECT COUNT(*) FROM [{name}]").fetchone()[0]
        stats[name] = {"zeilen": count}

    conn.close()
    return json.dumps(stats, indent=2, ensure_ascii=False)


# === TOOLS ===

@mcp.tool()
def sql_abfrage(query: str) -> str:
    """Fuehrt eine schreibgeschuetzte SQL-Abfrage auf der Datenbank aus.
    Nur SELECT-Anweisungen sind erlaubt. Gibt die Ergebnisse als
    JSON-formatierte Liste von Objekten zurueck."""
    # Sicherheitspruefung
    normalized = query.strip().upper()
    if not normalized.startswith("SELECT"):
        return "Fehler: Nur SELECT-Abfragen sind erlaubt."

    forbidden = ["INSERT", "UPDATE", "DELETE", "DROP", "ALTER", "CREATE"]
    for keyword in forbidden:
        if keyword in normalized:
            return f"Fehler: {keyword}-Anweisungen sind nicht erlaubt."

    try:
        conn = get_connection()
        cursor = conn.execute(query)
        columns = [desc[0] for desc in cursor.description] if cursor.description else []
        rows = cursor.fetchall()
        conn.close()

        results = [dict(zip(columns, row)) for row in rows]
        return json.dumps(results, indent=2, ensure_ascii=False)
    except Exception as e:
        return f"SQL-Fehler: {str(e)}"


@mcp.tool()
def tabellen_auflisten() -> str:
    """Listet alle Tabellen in der Datenbank mit Spalteninformationen auf."""
    conn = get_connection()
    tables = conn.execute(
        "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name"
    ).fetchall()

    result = []
    for table in tables:
        name = table[0]
        cols = conn.execute(f"PRAGMA table_info([{name}])").fetchall()
        col_info = [
            {"name": c[1], "type": c[2], "nullable": not c[3], "pk": bool(c[5])}
            for c in cols
        ]
        result.append({"tabelle": name, "spalten": col_info})

    conn.close()
    return json.dumps(result, indent=2, ensure_ascii=False)


# === PROMPTS ===

@mcp.prompt()
def datenanalyse_prompt(fragestellung: str) -> str:
    """Erstellt einen Prompt fuer strukturierte Datenbankanalyse."""
    return f"""Du bist ein Datenanalyst mit Zugriff auf eine SQLite-Datenbank.

Fragestellung: {fragestellung}

Vorgehensweise:
1. Pruefe zuerst das Schema mit der Ressource schema://tables
2. Nutze tabellen_auflisten fuer Spaltendetails
3. Formuliere gezielte SQL-Abfragen mit sql_abfrage
4. Interpretiere die Ergebnisse im Kontext der Fragestellung
5. Fasse die Erkenntnisse zusammen"""


# Demo-Datenbank initialisieren und Server starten
if __name__ == "__main__":
    if not DB_PATH.exists():
        init_demo_db()
        print(f"Demo-Datenbank erstellt: {DB_PATH}")
    mcp.run(transport="stdio")

Was hier besonders auffällt — und das finde ich bei MCP-Servern generell gut gelöst:

  • Schreibschutz auf Datenbankebene: PRAGMA query_only = ON verhindert schreibende Operationen direkt in SQLite. Das ist eine zusätzliche Sicherheitsschicht neben der Validierung im Python-Code — quasi ein doppelter Boden.
  • Eingabevalidierung: Das Tool sql_abfrage prüft sowohl den Anfang der Query als auch bekannte gefährliche Schlüsselwörter. Für eine Produktionsumgebung sollten Sie allerdings einen vollständigen SQL-Parser einsetzen.
  • Strukturierte Ausgaben: JSON-Rückgaben ermöglichen dem LLM eine zuverlässige Weiterverarbeitung der Ergebnisse.
  • Kontextuelle Prompts: Der datenanalyse_prompt führt das LLM durch einen strukturierten Analyseprozess und referenziert dabei die verfügbaren Tools und Resources.

Integration mit Claude Desktop

Um Ihren MCP-Server mit Claude Desktop zu verbinden, müssen Sie die Konfigurationsdatei bearbeiten. Die finden Sie hier:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Fügen Sie Ihren Server in den Block mcpServers ein:

{
  "mcpServers": {
    "datenbank": {
      "command": "uv",
      "args": [
        "--directory", "/absoluter/pfad/zu/mein-mcp-server",
        "run", "db_server.py"
      ]
    }
  }
}

Wichtig: Verwenden Sie unbedingt den absoluten Pfad zu Ihrem Projektverzeichnis — relative Pfade funktionieren hier nicht zuverlässig. Nach dem Speichern der Konfiguration starten Sie Claude Desktop neu. Im Chat-Fenster sollten Sie jetzt ein Hammer-Symbol sehen, das die verfügbaren Tools Ihres Servers anzeigt.

Probieren Sie es gleich aus: Fragen Sie Claude einfach „Welche Produkte haben wir mit einem Preis über 30 Euro?" — und Claude nutzt automatisch Ihren MCP-Server, um die Datenbank abzufragen und die Ergebnisse aufzubereiten. Beim ersten Mal hat man da schon einen kleinen Aha-Moment.

Vom Prototyp zur Produktion: Streamable HTTP Transport

STDIO-Transport ist perfekt für die lokale Entwicklung. Aber für den Produktionseinsatz — insbesondere wenn mehrere Clients gleichzeitig auf den Server zugreifen sollen — brauchen Sie Streamable HTTP. Dieser Transport wurde mit der MCP-Spezifikation vom März 2025 eingeführt und ersetzt den älteren SSE-Transport.

Vorteile von Streamable HTTP

  • Netzwerkfähig: Der Server wird ein regulärer HTTP-Endpunkt, erreichbar über URLs.
  • Mehrere Clients: Im Gegensatz zu STDIO kann ein einzelner Server viele gleichzeitige Verbindungen bedienen.
  • Skalierbar: Load Balancing und horizontale Skalierung funktionieren wie bei jeder REST-API.
  • Bidirektional: Streamed Responses über SSE ermöglichen Echtzeit-Updates.

Die Umstellung ist erfreulich unkompliziert — im Grunde ändern Sie nur den Transport-Parameter:

if __name__ == "__main__":
    if not DB_PATH.exists():
        init_demo_db()

    # Produktionsmodus: Streamable HTTP auf Port 8080
    mcp.run(
        transport="streamable-http",
        host="0.0.0.0",
        port=8080
    )

Der Server ist nun unter http://localhost:8080/mcp erreichbar. Für den echten Produktionseinsatz sollten Sie allerdings unbedingt HTTPS via Reverse Proxy (nginx, Caddy) aktivieren und eine Authentifizierung implementieren. Ohne das wäre Ihr Server offen wie ein Scheunentor.

Sicherheit und Best Practices

MCP-Server stellen eine direkte Brücke zwischen KI-Modellen und Ihren Systemen dar — und genau das macht sie zu einem attraktiven Angriffsziel. Im April 2025 identifizierten Sicherheitsforscher mehrere kritische Schwachstellen im Protokoll. Das Thema Sicherheit sollten Sie daher von Anfang an ernst nehmen.

Eingabevalidierung

Trauen Sie keiner Eingabe, die vom LLM kommt. Wirklich keiner. Das LLM generiert Tool-Parameter auf Basis von Nutzereingaben, die durch Prompt Injection manipuliert sein können. Validieren Sie jeden einzelnen Parameter:

import re

@mcp.tool()
def sichere_abfrage(tabelle: str, limit: int = 10) -> str:
    """Fuehrt eine sichere Abfrage auf einer bestimmten Tabelle aus."""
    # Tabellenname validieren: nur Buchstaben, Zahlen, Unterstriche
    if not re.match(r"^[a-zA-Z_][a-zA-Z0-9_]*$", tabelle):
        return "Fehler: Ungueltiger Tabellenname."

    # Limit einschraenken
    limit = max(1, min(limit, 100))

    conn = get_connection()
    try:
        rows = conn.execute(
            f"SELECT * FROM [{tabelle}] LIMIT ?", (limit,)
        ).fetchall()
        columns = [desc[0] for desc in conn.execute(
            f"SELECT * FROM [{tabelle}] LIMIT 0"
        ).description]
        return json.dumps(
            [dict(zip(columns, row)) for row in rows],
            indent=2, ensure_ascii=False
        )
    except sqlite3.OperationalError as e:
        return f"Fehler: {str(e)}"
    finally:
        conn.close()

Weitere Sicherheitsempfehlungen

  • Prinzip der minimalen Rechte: Geben Sie dem MCP-Server nur die Berechtigungen, die er wirklich braucht. Datenbankbenutzer mit reinen Leserechten, API-Tokens mit eingeschränktem Scope. Weniger ist hier definitiv mehr.
  • Logging: Protokollieren Sie alle Tool-Aufrufe mit Zeitstempel, Parametern und Ergebnissen. Verwenden Sie stderr für Logs bei STDIO-Transport — stdout ist für JSON-RPC reserviert.
  • Rate Limiting: Begrenzen Sie die Anzahl der Anfragen pro Zeitfenster, um Missbrauch und überhöhte Kosten zu verhindern.
  • Human-in-the-Loop: Für kritische Operationen (Löschungen, Zahlungen, Systemänderungen) sollte immer eine menschliche Freigabe erforderlich sein. KI-Agenten sind mächtig, aber nicht unfehlbar.

Asynchrone Tools und fortgeschrittene Muster

Für I/O-lastige Operationen — API-Aufrufe, Dateioperationen, Datenbankabfragen — unterstützt FastMCP nativ asynchrone Funktionen. Das verhindert, dass eine langsame Operation den gesamten Server blockiert:

import httpx

@mcp.tool()
async def webseite_abrufen(url: str) -> str:
    """Ruft den Inhalt einer Webseite ab und gibt ihn als Text zurueck."""
    if not url.startswith(("http://", "https://")):
        return "Fehler: URL muss mit http:// oder https:// beginnen."

    async with httpx.AsyncClient(timeout=15.0) as client:
        try:
            response = await client.get(url, follow_redirects=True)
            response.raise_for_status()
            # Auf 5000 Zeichen begrenzen
            return response.text[:5000]
        except httpx.HTTPStatusError as e:
            return f"HTTP-Fehler: {e.response.status_code}"
        except httpx.RequestError as e:
            return f"Verbindungsfehler: {str(e)}"

FastMCP dispatcht synchrone Funktionen automatisch in einen Thread-Pool, sodass auch blockierende Operationen den Event-Loop nicht lahmlegen. Trotzdem: Verwenden Sie async überall dort, wo eine asynchrone Alternative existiert. Ihr zukünftiges Ich wird es Ihnen danken, wenn der Server unter Last steht.

Server-Komposition

Für größere Projekte können Sie mehrere MCP-Server zu einem Gesamtsystem zusammensetzen. Jeder Server kümmert sich um einen abgegrenzten Bereich — Datenbank, E-Mail, Dateisystem — und wird unabhängig entwickelt und getestet.

Die Client-Konfiguration bindet sie dann als separate Einträge ein:

{
  "mcpServers": {
    "datenbank": {
      "command": "uv",
      "args": ["--directory", "/pfad/db-server", "run", "db_server.py"]
    },
    "dateisystem": {
      "command": "uv",
      "args": ["--directory", "/pfad/fs-server", "run", "fs_server.py"]
    },
    "web-recherche": {
      "command": "uv",
      "args": ["--directory", "/pfad/web-server", "run", "web_server.py"]
    }
  }
}

So entsteht ein modulares KI-Ökosystem, bei dem jeder Server unabhängig aktualisiert, skaliert und abgesichert werden kann. In meiner Erfahrung ist diese Aufteilung ab dem dritten oder vierten Tool fast immer sinnvoller als alles in einen monolithischen Server zu packen.

Debugging und Testen

Effizientes Debugging ist bei MCP-Servern besonders wichtig, weil die Kommunikation über JSON-RPC für den Entwickler nicht direkt sichtbar ist. Hier sind die wichtigsten Werkzeuge:

MCP Inspector

Das mit dem SDK mitgelieferte grafische Debugging-Tool. Es zeigt alle registrierten Fähigkeiten, lässt Sie Tools interaktiv aufrufen und zeigt die JSON-RPC-Nachrichten im Detail an:

# Server im Entwicklungsmodus starten
uv run mcp dev db_server.py

# Oder mit Hot Reload (FastMCP 3.0)
fastmcp dev db_server.py

Claude Code als Testumgebung

Claude Code unterstützt MCP-Server nativ und eignet sich hervorragend zum Testen. Sie können Ihren Server direkt in der Terminal-Umgebung einbinden und in natürlicher Sprache mit ihm interagieren — perfekt, um die Benutzererfahrung aus der Perspektive eines echten Nutzers zu validieren.

Unit Tests für Tools

Ab FastMCP 3.0 geben Dekoratoren die Original-Funktion zurück. Das heißt: Sie können Ihre Tools ganz normal als Python-Funktionen importieren und testen — ohne MCP-spezifisches Test-Setup:

# test_tools.py
from db_server import sql_abfrage, tabellen_auflisten

def test_sql_abfrage_select():
    result = sql_abfrage("SELECT 1 AS test")
    assert "test" in result

def test_sql_abfrage_blockiert_delete():
    result = sql_abfrage("DELETE FROM produkte")
    assert "Fehler" in result
    assert "nicht erlaubt" in result

def test_tabellen_auflisten():
    result = tabellen_auflisten()
    assert "produkte" in result

Häufig gestellte Fragen (FAQ)

Was ist der Unterschied zwischen MCP und einer normalen REST-API?

Eine REST-API ist für die Maschine-zu-Maschine-Kommunikation entworfen und erfordert vom Entwickler die manuelle Integration jedes Endpunkts. MCP hingegen ist speziell für die LLM-zu-Tool-Kommunikation konzipiert: Es bietet automatische Tool-Erkennung (Capability Discovery), standardisierte Parameterbeschreibungen via JSON-Schema und ein einheitliches Protokoll, das jeder MCP-kompatible Client sofort versteht. Sie bauen einmal einen MCP-Server, und er funktioniert mit Claude, ChatGPT, Cursor und jedem anderen MCP-Host.

Welche Programmiersprachen werden für MCP-Server unterstützt?

Offizielle SDKs gibt es für Python, TypeScript, Kotlin, C# und Java. Darüber hinaus existieren Community-SDKs für Ruby, Go, PHP, Rust, Swift und Elixir. Python und TypeScript sind die mit Abstand am häufigsten verwendeten Sprachen, wobei FastMCP rund 70 % aller MCP-Server weltweit antreibt.

Ist MCP sicher genug für den Produktionseinsatz?

Kurze Antwort: Ja, aber Sie müssen aktiv mitarbeiten. MCP bringt Zugriffskontrollen, Datenisolation und Protokollierung mit. Allerdings müssen Sie als Entwickler selbst Sicherheitsmaßnahmen implementieren: Eingabevalidierung, das Prinzip der minimalen Rechte, HTTPS für Netzwerk-Transport und Human-in-the-Loop für kritische Operationen. Die im April 2025 identifizierten Schwachstellen (Prompt Injection, Tool-Spoofing) zeigen, dass ein Bewusstsein für diese Risiken unverzichtbar ist.

Kann ich einen MCP-Server auch ohne Claude nutzen?

Absolut. MCP ist ein offenes Protokoll und seit der Übernahme durch die Linux Foundation herstellerunabhängig. Neben Claude Desktop unterstützen auch ChatGPT, Cursor, Zed, Sourcegraph, Windsurf und zahlreiche weitere Anwendungen MCP. Sie können auch eigene Clients mit dem MCP SDK bauen.

Was kostet der Betrieb eines MCP-Servers?

Der MCP-Server selbst ist Open Source und kostenlos. Die Betriebskosten hängen von Ihrer Infrastruktur ab: Lokal auf dem eigenen Rechner fallen keine Kosten an. Für Cloud-Deployments gelten die üblichen Hosting-Kosten. Da MCP-Server typischerweise leichtgewichtig sind, genügt meistens eine kleine VM oder ein Container. Die eigentlichen Kosten entstehen durch die LLM-API-Aufrufe des Hosts — nicht durch den MCP-Server selbst.

Über den Autor Editorial Team

Our team of expert writers and editors.