AI Agents und MCP: Wie autonome Agenten Tools aufrufen und was dabei schiefläuft
Hook: Stellen Sie sich vor, Ihr KI‑Assistent bestellt Ihnen nicht nur einen Kaffee, sondern führt automatisch ein Backup, meldet ein Sicherheitsvorfall und pusht ein Docker‑Image – alles ohne Ihr Zutun. Klingt nach Science‑Fiction? In der Realität steckt dahinter das Model‑Calling‑Protocol (MCP), ein relativ neues Muster, das LLMs erlaubt, externe Programme zu starten. Viele Unternehmen stürzen sich jetzt darauf – aber die Hälfte scheitert bereits im ersten Monat, weil sie das „Aufruf‑Handling“ missverstehen. In diesem Beitrag zeige ich, warum das so ist, wie Sie das Protokoll korrekt einbinden und welche drei typischen Implementierungen funktionieren – inklusive vollständiger Befehle und Konfigurationen.
1. Was ist MCP und warum brauchen Sie es?
MCP ist kein offizieller Standard, sondern ein pragmatischer Ansatz, bei dem ein LLM eine funktionale Beschreibung (Name, Parameter, Rückgabetyp) erhält und bei Bedarf einen Funktionsaufruf an den Host‑Adapter zurückgibt. Dieser Adapter führt das gewünschte Tool aus und schickt das Ergebnis zurück ins Modell. Auf diese Weise bleibt das Sprachmodell schlank (es kennt nur das „Was“, nicht das „Wie") und Sie behalten die volle Kontrolle über die System‑Privilegien.
1.1. Beispiel‑Schema (JSON)
{
"name": "run_command",
"description": "Führt einen Shell‑Befehl aus und liefert stdout zurück",
"parameters": {
"type": "object",
"properties": {
"cmd": {"type": "string", "description": "Komplettes Shell‑Kommando"}
},
"required": ["cmd"]
}
}
Das Modell kann nun, wenn es erkennt, dass ein Befehl nötig ist, eine Anfrage in exakt diesem Format zurückgeben. Der Host‑Adapter parst die JSON, führt cmd aus und liefert das Ergebnis über das gleiche JSON‑Schema zurück.
1.2. Meine persönliche Einschätzung
Die Trennung von „Entscheidung“ (LLM) und „Ausführung“ (Adapter) ist das Kern‑Prinzip von Zero‑Trust‑Designs für KI. Ohne diese Trennung öffnen Sie Ihr System für unkontrollierte Befehle – das ist das eigentliche Sicherheitsrisiko, das viele Auto‑GPT‑Klone heute zeigen.
2. Beispiel 1 – Shell‑Befehl via MCP ausführen
2.1. Ziel
Ein Agent soll bei Bedarf das Log‑File /var/log/auth.log auslesen und nach Fehlermeldungen durchsuchen.
2.2. Implementierung
Python‑Adapter (minimal):
import json, subprocess, sys
# –– MCP‑Nachricht von LLM (stdin) ––
request = json.loads(sys.stdin.read())
if request["name"] == "run_command":
cmd = request["arguments"]["cmd"]
# Sicherheits‑Whitelist: nur erlaubte Pfade
allowed = ["cat", "grep", "awk"]
if not any(cmd.split()[0] == a for a in allowed):
response = {"error": "Command not allowed"}
else:
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
response = {"output": result.stdout, "stderr": result.stderr}
print(json.dumps(response))
LLM‑Prompt (Kurzfassung):
You are a security‑aware assistant. If the user asks for recent auth‑failures, call the function:
run_command({"cmd": "grep 'Failed password' /var/log/auth.log | tail -n 5"})
2.3. Ergebnis & Einschätzung
Der Agent liefert nun die letzten fünf Fehlermeldungen ohne je „root“ zu werden – weil das Python‑Skript nicht mit root läuft, sondern nur das grep‑Kommando ausführt. Der kritische Punkt: Whitelist‑Checking schützt vor arbiträren Befehlen. In meinem produktiven Umfeld habe ich die Whitelist per YAML definiert und per inotify dynamisch aktualisiert. Das reduziert das Risiko von Command‑Injection drastisch.
3. Beispiel 2 – HTTP‑API‑Aufruf (z. B. GitHub‑Issue erstellen)
3.1. Ziel
Ein Agent soll bei einem Sicherheitsalarm automatisch ein GitHub‑Issue öffnen, damit das Incident‑Team sofort benachrichtigt wird.
3.2. Implementierung
MCP‑Funktions‑Definition:
{
"name": "create_github_issue",
"description": "Erzeugt ein Issue in einem GitHub‑Repo",
"parameters": {
"type": "object",
"properties": {
"repo": {"type": "string"},
"title": {"type": "string"},
"body": {"type": "string"}
},
"required": ["repo", "title", "body"]
}
}
Adapter‑Code (Python + requests):
import os, json, requests, sys
TOKEN = os.getenv("GH_TOKEN") # Personal Access Token mit repo‑Scope
request = json.loads(sys.stdin.read())
if request["name"] == "create_github_issue":
args = request["arguments"]
url = f"https://api.github.com/repos/{args['repo']}/issues"
payload = {"title": args["title"], "body": args["body"]}
headers = {"Authorization": f"token {TOKEN}", "Accept": "application/vnd.github.v3+json"}
r = requests.post(url, json=payload, headers=headers)
response = {"status": r.status_code, "json": r.json()}
print(json.dumps(response))
Prompt‑Beispiel für das LLM:
User: "Ein unbekannter Login wurde um 02:13 Uhr auf Server X entdeckt."
Assistant: call create_github_issue({"repo": "myorg/security-incidents", "title": "Unbekannter Login auf Server X", "body": "Zeit: 02:13 Uhr\nIP: 203.0.113.42\nDetails siehe /var/log/auth.log"})
3.3. Ergebnis & Einschätzung
Der Agent legt innerhalb von Sekunden ein Issue an und liefert die GitHub‑Response zurück – das gibt dem LLM Kontext, ob das Erstellen erfolgreich war. Ich habe hier OAuth‑Scope‑Limiting verwendet; das ist wichtig, weil sonst ein kompromittierter Agent das gesamte Repository manipulieren könnte. Der größte Stolperstein: das LLM muss die Parameter exakt im vorgegebenen Format senden, sonst bricht die JSON‑Parsen‑Logik ab.
4. Beispiel 3 – Datenbank‑Query über MCP
4.1. Ziel
Ein Agent soll bei einem Anstieg der CPU‑Auslastung (≥ 90 %) die letzten fünf Minuten aus einer Timeseries‑DB (InfluxDB) holen und dem Operator per Slack‑Message präsentieren.
4.2. Implementierung
Funktions‑Schema (SQL‑Like):
{
"name": "query_influx",
"description": "Führt eine InfluxQL‑Abfrage aus und gibt die Resultate zurück",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string"}
},
"required": ["query"]
}
}
Adapter‑Script (Bash + curl):
#!/usr/bin/env bash
read -r payload
query=$(echo "$payload" | jq -r '.arguments.query')
# InfluxDB credentials aus env
INFLUX_URL=${INFLUX_URL:-http://influx.local:8086/query}
INFLUX_DB=${INFLUX_DB:-metrics}
INFLUX_USER=${INFLUX_USER:-metrics_user}
INFLUX_PASS=${INFLUX_PASS:-s3cr3t}
response=$(curl -s -G "$INFLUX_URL" \
-u "$INFLUX_USER:$INFLUX_PASS" \
--data-urlencode "db=$INFLUX_DB" \
--data-urlencode "q=$query")
# Rückgabe im erwarteten JSON‑Format
jq -n --argjson data "$response" '{output: $data}'
Beispiel‑Prompt für das LLM:
If CPU usage exceeds 90%, call query_influx({"query": "SELECT mean(usage_user) FROM cpu WHERE time > now() - 5m"})
Slack‑Benachrichtigung (nach Rückgabe):
import json, requests, sys
payload = json.loads(sys.stdin.read())
if payload.get('output'):
msg = f"⚠️ CPU‑Spike! Last 5 min avg: {payload['output']['results'][0]['series'][0]['values'][0][1]}%"
webhook = os.getenv('SLACK_WEBHOOK')
requests.post(webhook, json={'text': msg})
4.3. Ergebnis & Einschätzung
Der Agent greift nur lesend auf die Datenbank zu; er hat keine Schreibrechte, weil das Bash‑Script das curl‑Kommando mit einem Readonly‑User ausführt. In Projekten, bei denen mehrere Agenten dieselbe DB benutzen, ist das Trennung‑von‑Rollen (Read‑Only vs. Write) entscheidend – sonst kann ein bösartiger Prompt sofort Daten manipulieren.
5. Häufige Fehler beim Einsatz von MCP
| Fehler | Warum er fatal ist | Kurzlösung |
|---|---|---|
| Keine Typ‑Validierung | Das LLM liefert Strings, aber das Backend erwartet Integer – führt zu Crash‑Loops. | Verwenden Sie jsonschema zur Laufzeit‑Validierung. |
| Ungefilterte Eingaben | Direkter shell=True öffnet Command‑Injection. |
Immer Whitelist prüfen, niemals eval. |
| Zu breite Berechtigungen | Der Adapter läuft als root und führt jede Funktion aus. |
Prinzip „least privilege“: separater System‑User pro Funktionsgruppe. |
| Fehlendes Timeout‑Handling | Ein langer Befehl blockiert den gesamten Agent‑Loop. | Setzen Sie subprocess.run(..., timeout=10). |
| Kein Idempotenz‑Check | Wiederholte Funktionsaufrufe erzeugen duplizierte Issues, doppeltes Backup usw. | Return‑Code „already‑done“ und im LLM‑Prompt prüfen. |
Ein weiteres Stolpersteine‑Beispiel: Viele Entwickler versuchen, das MCP‑Schema im Prompt zu hardcoden – das führt schnell zu Inkonsistenzen, weil das Modell bei Version‑Updates andere Feldnamen vorschlagen kann. Der sichere Weg ist, das Schema extern (z. B. als Datei functions.json) zu verwalten und das LLM nur darauf zu verweisen.
6. Fazit & konkreter nächster Schritt
MCP gibt Ihnen das Werkzeug, um LLMs in kontrollierte, auditierbare Automatisierungs‑Pipelines zu integrieren. Der Gewinn ist sofort: weniger manuelle Skripte, konsistente Fehlermeldungen und ein zentrales Policy‑Framework. Die größten Gefahren liegen jedoch in Sicherheits‑ und Zuverlässigkeits‑Lücken, die sich meist aus zu großzügigen Berechtigungen und fehlender Eingabe‑Validierung ergeben.
Dein To‑Do‑Plan für die nächsten 48 Stunden
-
Schema‑Datei erstellen –
functions.jsonmit allen Funktionsdefinitionen, die Ihr Team nutzt. -
Adapter‑Skeleton – ein Python‑Script, das JSON einliest, Whitelist prüft und mit
subprocess.run(..., timeout=5)arbeitet. -
Unit‑Tests – schreiben Sie mindestens drei Tests (Shell, HTTP, DB) mit
pytestundresponses‑Mock, um das Gesamtsystem offline zu prüfen. -
Roll‑out – Deployen Sie den Adapter als System‑Dienste (
systemd‑Unit) unter einem dedizierten Usermcp-agent. Loggen Sie jede Anfrage in/var/log/mcp-agent.logfür Auditing. -
Monitoring – Fügen Sie ein Prometheus‑Export‑Endpoint (
/metrics) zum Adapter hinzu, um Fehlerraten und Latenz zu beobachten.
Wenn Sie diesen Plan umsetzen, haben Sie in weniger als einer Woche ein sicheres, skalierbares AI‑Agent‑Setup, das externe Tools zuverlässig aufruft – und das ohne das übliche „funktioniert auf meinem Rechner“-Problem.
Viel Erfolg beim Automatisieren!
Top comments (0)