Warum CLIs besser als MCP für KI-Agenten sind — So baust du deine eigene CLI-Armee auf
Sechs Wörter. Das war alles. Peter Steinberger — der Typ hinter OpenClaw, 190.000 GitHub-Stars, frisch von Sam Altman abgeworben — postete das letzten Monat auf X. Meine sofortige Reaktion? Screenshot gemacht und an drei Dev-Kumpels geschickt mit "HATTE ICH DOCH GESAGT" in Großbuchstaben.
Ich entwickle seit Jahren auf Ubuntu.
Jedes Tool, das ich täglich nutze, ist ein CLI.
Supabase CLI, Vercel CLI, Docker, git, n8n — mein kompletter Stack läuft über das Terminal. Als MCP-Server letztes Jahr im Trend lagen, probierte ich ein paar aus. Sie funktionierten. Sie fraßen auch 40% meines Context-Windows, crashten zufällig und fügten eine Abhängigkeit für etwas hinzu, was ich bereits mit einer Zeile und einer Pipe erledigen konnte.
Wenn also der produktivste Open-Source-Entwickler von 2026 sagt, CLIs seien die echte Schnittstelle zwischen KI-Agenten und der Welt — und OpenAI dem genug zustimmt, um ihn einzustellen — dann wird es Zeit, aufzumerken.
TL;DR: MCP-Server blähen dein Context-Window auf, fügen fragile Abhängigkeiten hinzu und lösen ein Problem, das nicht existiert, wenn deine Tools CLIs sind 😂 Peter Steinberger baute ~10 eigene CLIs für OpenClaw und wurde dafür von OpenAI rekrutiert.
Du kannst das gleiche Muster heute mit Claude Code verwenden (dokumentiere CLIs in CLAUDE.md), sie als Skills in OpenClaw einbinden oder deinen eigenen autonomen Agenten mit der Anthropic tool_use API bauen. CLIs sind die native Schnittstelle zwischen KI-Agenten und der realen Welt. GUIs sind für Menschen. APIs sind für Services. CLIs sind für Agenten.

Warum MCP versagt (Und warum der OpenClaw-Typ meinem Terminal zustimmt)
Lass uns die Arten bewerten, wie ein KI-Agent mit externen Tools interagieren kann. Von schlecht zu gut.
GUIs fallen offensichtlich raus. Du würdest deine CI/CD-Pipeline auch nicht bitten, Buttons in einem Browser zu klicken. Gleiche Logik für Agenten. Weiter.
REST APIs und SDKs funktionieren. Aber jeder Service hat seinen eigenen Auth-Flow, sein eigenes Response-Format, sein eigenes Error-Handling. Du schreibst am Ende Wrapper-Code für jede Integration. Für ein SaaS-Backend ist das okay. Für einen Agenten, der nur checken soll, ob du neue E-Mails hast, ist es übertrieben.
MCP — das Model Context Protocol — sollte das beheben. Ein Standard-Protokoll, um Agenten mit Tools zu verbinden. Klingt theoretisch super. In der Praxis? Jeder MCP-Server, den du hinzufügst, kippt sein komplettes Schema in das Context-Window deines Agenten. Tool-Beschreibungen, Parameter-Listen, Capability-Deklarationen — alles. Bevor dein Agent überhaupt anfängt, über deine eigentliche Anfrage nachzudenken, sind bereits 30–40% seines Kontexts von MCP-Boilerplate verbraucht.
Peter Steinberger probierte es aus. Baute Support dafür. Dann baute er MCPorter — ein Tool, das MCP-Server buchstäblich zurück in CLIs konvertiert. So sehr hält er das Format für falsch.
Seine exakten Worte zu MCPs tatsächlichem Beitrag zum Ökosystem: "Das einzig Gute an MCP war, dass Unternehmen dadurch ein paar APIs öffneten."
Brutal. Und zutreffend.
Das Protokoll selbst war ein Umweg — die APIs, zu deren Entstehung es zwang, sind das echte Geschenk.
CLIs gewinnen, weil sie das Gegenteil von all diesem Ballast sind. Ein CLI ist:
- Null Context-Overhead. Dein Agent muss kein Schema laden. Er liest eine einseitige Doku (oder führt
--helpaus) und kennt jeden verfügbaren Befehl. - Komponierbar. Pipe die Ausgabe eines CLIs in ein anderes.
goplaces search "coffee" --json | jq '.[0].address'- versuch das mal mit einem MCP-Server. - In 2 Sekunden testbar. Terminal öffnen, Befehl ausführen, sehen was passiert. Kein Server zum Hochfahren, kein Protokoll-Handshake, keine WebSocket-Verbindung.
- Strukturierte Ausgabe umsonst. Füge ein
--json-Flag hinzu und dein Agent bekommt parsbare Daten ohne Serialisierungs-Layer.
Ein exec-Aufruf. Das ist alles, was ein Agent braucht, um ein CLI zu nutzen. Keine Middleware, kein Protokoll, kein Server-Prozess, der im Hintergrund läuft und RAM frisst für das Privileg, verfügbar zu sein.

Und das ist keine theoretische Präferenz.
Steinberger baute sein komplettes OpenClaw-Ökosystem um CLIs herum. Etwa ein Dutzend davon: goplaces für Google Maps, imsg für iMessage, bird für X/Twitter, wacli für WhatsApp, gog für Gmail und Calendar, camsnap für Überwachungskameras, peekaboo für macOS-Screenshots mit KI-Vision, summarize für das Zusammenfassen von Videos und Podcasts. Jedes folgt dem gleichen Muster: macht eine Sache gut, unterstützt --json, hat eine klare --help.
Dann stellte OpenAI ihn ein.
Er verbrachte den Großteil eines Jahres damit, diese CLI-Armee aufzubauen. Dann stellte OpenAI ihn ein. Sam Altman rekrutierte keinen Typen, der hübsche Dashboards baute — er rekrutierte den Typen, der bewies, dass bash die beste Agent-Schnittstelle ist. Interpretiere das, wie du willst.
CLIs jetzt sofort nutzen, um schneller zu entwickeln (OpenClaw nicht erforderlich)
Du brauchst OpenClaw nicht, um davon zu profitieren. Wenn du Claude Code, Codex oder irgendeinen Agenten mit Shell-Zugriff nutzt, hast du bereits die Infrastruktur.
Der Trick, den die meisten übersehen: Dein Agent kann bereits CLIs aufrufen. Aber er weiß nichts über DEINE spezifischen CLIs, außer du sagst es ihm.
# CLAUDE.md (Projektroot)
## Verfügbare CLIs
### Supabase
- `supabase db push` - Migrationen auf Remote anwenden
- `supabase functions deploy
- `supabase db dump --data-only` - Produktionsdaten exportieren
- `supabase migration new
### Vercel
- `vercel deploy --prod` - In Produktion deployen
- `vercel env pull .env.local` - Env-Variablen synchronisieren
- `vercel logs
### Projektspezifisch
- `./scripts/check-mrr.sh` - Gibt JSON mit aktuellem MRR, Anmeldungen, Churn aus
- `./scripts/seed-demo.sh` - Setzt Demo-Umgebung mit Beispieldaten zurück
Das war's.
Claude Code liest CLAUDE.md zu Beginn jeder Session. Wenn du das nächste Mal sagst "deploy in Produktion und check, ob sich der MRR geändert hat", weiß er genau, welche Befehle er ausführen muss. Kein Plugin, kein MCP-Server, keine Config-Datei mit 47 verschachtelten Schlüsseln.
Für Codex, gleiches Konzept — die Datei heißt AGENTS.md.
Für Cursor, .cursorrules.
Anderer Dateiname, identisches Muster.
Aber der echte Power-Move ist, eigene CLIs zu bauen. Und bevor du diesen Tab schließt mit dem Gedanken "Ich habe keine Zeit, CLI-Tools zu bauen" — wir reden von 20–30 Zeilen Code. Ernsthaft.
Drei Regeln für ein agenten-freundliches CLI:
1. Strukturierte Ausgabe mit **--json**
Dein Agent kann keine hübsche Tabelle mit Box-Drawing-Zeichen parsen. Er braucht JSON.
#!/usr/bin/env node
// scripts/check-mrr.js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_KEY)
const args = process.argv.slice(2)
const jsonMode = args.includes('--json')
const { data } = await supabase
.from('subscriptions')
.select('plan, status, created_at')
const active = data.filter(s => s.status === 'active')
const mrr = active.reduce((sum, s) => sum + (s.plan === 'pro' ? 29 : 9), 0)
const today = data.filter(s =>
new Date(s.created_at).toDateString() === new Date().toDateString()
)
const stats = {
mrr,
active_subscriptions: active.length,
signups_today: today.length,
timestamp: new Date().toISOString()
}
if (jsonMode) {
console.log(JSON.stringify(stats))
} else {
console.log(`MRR: $${mrr}`)
console.log(`Aktiv: ${active.length}`)
console.log(`Anmeldungen heute: ${today.length}`)
}
2. Eine **--help**, die tatsächlich erklärt
Agenten lesen --help wie Menschen READMEs lesen. Wenn dein Hilfetext Müll ist, halluziniert dein Agent die Flags.
$ ./check-mrr.js --help
Verwendung: check-mrr [optionen]
Aktuelle SaaS-Metriken aus Supabase prüfen.
Optionen:
--json Ausgabe als JSON (Standard: menschenlesbar)
--period Filter: today | week | month (Standard: today)
--help Diese Nachricht anzeigen
3. Saubere Exit-Codes
0 = Erfolg. 1 = Fehler.
Dein Agent nutzt das, um zu entscheiden, was als nächstes zu tun ist. Wenn dein CLI bei Fehlern mit 0 beendet, denkt dein Agent, alles sei in Ordnung und macht weiter.
Das lernte ich auf die harte Tour um 2 Uhr nachts, als mein Deploy-Script stumm fehlschlug und Claude mir immer wieder "Deployment erfolgreich" sagte — dauerte 20 Minuten, bis ich merkte, dass das Script Fehler verschluckte und trotzdem mit 0 beendete, aber ich schweife ab.
Sobald du ein paar dieser CLIs hast, ändert sich etwas.
Du hörst auf, Claude Code zu bitten, Supabase-Queries zu schreiben. Du fängst an zu sagen "check meine Metriken, und wenn die Anmeldungen mehr als 20% gegenüber gestern gefallen sind, entwirf eine Slack-Nachricht an das Team." Claude verkettet die CLIs, entscheidet die Logik, handelt basierend auf dem Ergebnis. Das ist keine Autovervollständigung. Das ist ein Agent.
Das Muster, das skaliert: CLI + Skill-Doku
Hier ist die Sache, die Steinberger früh kapierte und die die meisten immer noch nicht verinnerlicht haben: Ein CLI ohne Dokumentation ist für einen Agenten nutzlos.
Dein Agent kann ein CLI nicht durch Trial-and-Error erkunden wie ein Mensch. Er muss im Voraus wissen, welche Befehle existieren, welche Flags verfügbar sind, wie die Ausgabe aussieht. Deshalb kommt jedes einzelne CLI im OpenClaw-Ökosystem mit einer SKILL.md — einer strukturierten Doku, die als Bedienungsanleitung für den Agenten fungiert.
Das Muster ist: CLI-Binary + Skill-Doku = autonome Fähigkeit.
Das CLI macht die Arbeit. Die Skill-Doku lehrt den Agenten, wie er es nutzt. Zusammen sind sie eine in sich geschlossene Einheit, die jeder Agent aufgreifen und ausführen kann. Steinberger nennt sie "Skills". Das Konzept ist dasselbe, egal ob du es Skill, Tool oder "das Bash-Script, das Dave letzten Dienstag schrieb" nennst.
Und du brauchst OpenClaw nicht, um dieses Muster zu nutzen. Du machst es bereits — wenn du eine CLAUDE.md schreibst, die deine CLIs dokumentiert, ist das eine Skill-Doku. Der Unterschied ist, dass Steinberger das Format standardisierte und eine Verteilungsschicht darüber baute: ClawHub, mit 3.000+ Skills, die du durchsuchen und installieren kannst.
Das Interessante? Du kannst jeden dieser Skills für dein eigenes Setup klauen. Jeder Skill auf ClawHub ist nur ein CLI, das du unabhängig installieren kannst (brew install steipete/tap/goplaces, npm install -g @steipete/oracle, etc.) und eine SKILL.md, die du lesen kannst. Du brauchst die OpenClaw-Runtime nicht. Installiere die Binary, füge die relevanten Befehle in deine CLAUDE.md ein, und Claude Code kann es sofort nutzen.
# In deiner CLAUDE.md — direkt von ClawHub geklaut
## goplaces (Google Maps CLI)
- `goplaces search "coffee near me" --open-now --json` - Orte finden
- `goplaces search "pizza" --lat 40.8 --lng -73.9 --radius-m 3000 --json` - standortbasierte Suche
- `goplaces details <place_id> --json` - vollständige Ortsdetails mit Bewertungen
- `goplaces resolve "Soho, London" --json` - Ortsnamen geocodieren
Benötigt: GOOGLE_PLACES_API_KEY env var
## summarize (Video/Podcast/Web-Zusammenfasser CLI)
- `summarize --url "https://youtube.com/watch?v=xxx" --json` - Video zusammenfassen
- `summarize --url "https://some-blog.com/post" --json` - Webseite zusammenfassen
- `summarize --url "https://podcast.fm/ep42" --cli claude --json` - Modell auswählen
Das sind goplaces und summarize — zwei von Steinbergers eigenen Tools — die in Claude Code ohne jede OpenClaw-Abhängigkeit laufen. Nur eine Binary und eine Doku.
Deshalb skaliert der CLI-Ansatz auf eine Weise, wie MCP es nie wird. Ein MCP-Server ist ein laufender Prozess, der Konfiguration, einen Protokoll-Handshake und Context-Window-Platz braucht. Ein CLI-Skill ist eine statische Binary und eine Textdatei. Eines braucht Infrastruktur. Das andere braucht ein brew install und 10 Zeilen Markdown.
CLIs in OpenClaw einbinden
Wenn du bereits OpenClaw laufen hast, dauert es etwa 5 Minuten, ein CLI in einen Agent-Skill zu verwandeln.
Das System funktioniert so: Jeder Skill hat eine SKILL.md-Datei, die beschreibt, was das CLI macht, wie man es installiert und welche Befehle verfügbar sind. Der Agent liest diese Datei und weiß, wie er das Tool nutzt.
---
name: check-mrr
description: SaaS-Metriken (MRR, Anmeldungen, Churn) aus Supabase prüfen.
metadata:
openclaw:
requires:
env:
- SUPABASE_URL
- SUPABASE_KEY
bins:
- node
primaryEnv: SUPABASE_URL
---
# check-mrr
Aktuelle SaaS-Metriken aus Produktions-Supabase abrufen.
## Installation
npm install -g @yourhandle/check-mrr
## Befehle
- `check-mrr --json` - vollständige Metriken als JSON
- `check-mrr --period week` - Metriken für die aktuelle Woche
- `check-mrr --period month` - Monatsübersicht
## Ausgabeformat (--json)
{
"mrr": 1247,
"active_subscriptions": 89,
"signups_today": 3,
"timestamp": "2026-02-17T10:30:00Z"
}
Veröffentliche es auf ClawHub (clawhub publish) und jeder, der OpenClaw laufen hat, kann deinen Skill installieren. Aber der echte Wert ist lokal: kombiniere es mit einem Cron-Job, und dein Agent checkt jeden Morgen deine Metriken und pingt dich auf WhatsApp an, wenn etwas komisch aussieht.
// In openclaw.json
{
"cron": [
{
"schedule": "0 8 * * *",
"message": "Führe check-mrr --json aus. Wenn signups_today 0 ist oder mrr mehr als 5% gegenüber gestern gefallen ist, alarmiere mich auf WhatsApp mit einer Zusammenfassung. Sonst nur loggen.",
"channel": "whatsapp"
}
]
}
Das ist der komplette Kreislauf. Cron triggert den Agenten, Agent liest den Skill, ruft das CLI auf, interpretiert das Ergebnis, entscheidet was zu tun ist. Kein Dashboard zum Checken. Keine Notification-Fatigue von Alerts, die du nicht brauchst. Der Agent nutzt Urteilsvermögen — gleiches Muster, das Steinberger über sein komplettes Setup laufen lässt.
Das ClawHub-Verzeichnis hat bereits 3.000+ Third-Party-Skills, die meisten folgen genau dieser Struktur. goplaces für Ortssuche, himalaya für E-Mail via IMAP, bird (😭) für X/Twitter, sonoscli für Lautsprecher-Kontrolle - die ganze Armee. Du installierst sie, der Agent lernt sie, fertig.
Deinen eigenen Agenten bauen (Das OpenClaw-Muster, ohne OpenClaw)
OK, was ist, wenn du OpenClaw nicht laufen lassen willst?
Vielleicht willst du etwas Leichteres, Angepassteres, oder du baust einfach gerne Dinge von Grund auf. (Verstehe ich. Ich hoste alles selbst. Es ist eine Krankheit.)
Das Kern-Muster ist todseinfach: ein Script, das die Anthropic API mit tool_use aufruft, Tool-Aufrufe auf CLI-Ausführungen mappt und loopt, bis der Agent fertig ist.
import Anthropic from '@anthropic-ai/sdk'
import { execSync } from 'child_process'
const client = new Anthropic()
// Deine CLIs, als Tools deklariert
const tools = [
{
name: "check_mrr",
description: "Aktuelle SaaS-Metriken abrufen (MRR, aktive Abos, Anmeldungen heute)",
input_schema: {
type: "object",
properties: {
period: { type: "string", enum: ["today", "week", "month"], default: "today" }
}
}
},
{
name: "deploy_production",
description: "Neuesten Commit auf Vercel-Produktion deployen. Gibt Deploy-URL zurück.",
input_schema: {
type: "object",
properties: {}
}
},
{
name: "send_slack",
description: "Nachricht an einen Slack-Channel senden",
input_schema: {
type: "object",
properties: {
channel: { type: "string" },
message: { type: "string" }
},
required: ["channel", "message"]
}
}
]
// Tool-Namen auf CLI-Befehle mappen
function executeTool(name, input) {
const commands = {
check_mrr: `node ./scripts/check-mrr.js --json --period ${input.period || 'today'}`,
deploy_production: `vercel deploy --prod --yes 2>&1`,
send_slack: `curl -X POST -H 'Authorization: Bearer ${process.env.SLACK_TOKEN}' \
-H 'Content-Type: application/json' \
-d '{"channel":"${input.channel}","text":"${input.message}"}' \
https://slack.com/api/chat.postMessage\`
}
try {
const result = execSync(commands[name], { encoding: 'utf-8', timeout: 30000 })
return result
} catch (err) {
return JSON.stringify({ error: err.message, exitCode: err.status })
}
}
// Die Agent-Schleife
async function runAgent(task) {
let messages = [{ role: "user", content: task }]
while (true) {
const response = await client.messages.create({
model: "claude-sonnet-4-5-20250514",
max_tokens: 4096,
system: "Du bist ein autonomer Agent. Nutze die verfügbaren Tools, um Aufgaben zu erledigen. Sei prägnant in deiner Begründung.",
tools,
messages
})
// Wenn Claude fertig ist mit Reden, sind wir fertig
if (response.stop_reason === "end_turn") {
const text = response.content.find(b => b.type === 'text')
return text?.text || 'Fertig.'
}
// Wenn Claude Tools nutzen will, führe sie aus
const toolBlocks = response.content.filter(b => b.type === 'tool_use')
if (toolBlocks.length === 0) break
messages.push({ role: "assistant", content: response.content })
const toolResults = toolBlocks.map(block => ({
type: "tool_result",
tool_use_id: block.id,
content: executeTool(block.name, block.input)
}))
messages.push({ role: "user", content: toolResults })
}
}
// Ausführen
const result = await runAgent(
"Check unseren MRR. Wenn er über $1000 ist, deploy in Produktion und benachrichtige #team auf Slack mit den Metriken. Wenn darunter, sende nur eine Warnung an Slack."
)
console.log(result)
~80 Zeilen. Das ist dein eigenes Mini-OpenClaw. Der Agent entscheidet, welche Tools er in welcher Reihenfolge aufruft, basierend auf der Aufgabe, die du ihm gibst. Ein neues CLI hinzuzufügen dauert 30 Sekunden — Tool-Definition hinzufügen, eine Zeile in der commands-Map hinzufügen, fertig.
Für den autonomen Teil, wickle es in einen Cron ein:
# crontab -e
0 8 * * * cd /home/deploy/my-agent && node agent.js "Morgen-Check: Metriken, deploy wenn stabil, Team benachrichtigen"
0 20 * * * cd /home/deploy/my-agent && node agent.js "Tagesende: Anmeldungen zusammenfassen, Anomalien an Slack melden"
Du kannst das auch als systemd-Service mit einem Timer laufen lassen oder in einen Docker-Container auf deinem Server werfen. Gleiches Ergebnis, verschiedene DevOps-Geschmäcker.

GitHub Actions ist eine weitere Option, wenn du null Infrastruktur willst. Ein geplanter Workflow, der deine CLIs im Runner installiert und die Anthropic API aufruft:
name: Daily Agent Run
on:
schedule:
- cron: '0 8 * * *'
jobs:
agent:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- run: npm install @anthropic-ai/sdk
- run: node agent.js "Morgenroutine"
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
SUPABASE_KEY: ${{ secrets.SUPABASE_KEY }}
Kostenlos für öffentliche Repos, 2.000 Minuten/Monat bei privaten. Nicht schlecht für einen täglichen Agenten, der in 30 Sekunden läuft.
Und n8n?
Du kannst technisch CLIs über n8n orchestrieren, indem du den Execute Command Node nutzt oder sie in FastAPI-Container verpackst.
Aber ehrlich gesagt ist es mehr Reibung als der Script-Ansatz für diesen Use Case. n8n glänzt, wenn du visuelle Workflows mit 15 Schritten und komplexem Branching brauchst — nicht für "CLI aufrufen und das LLM entscheiden lassen."
Wenn du tiefer in das Ausführen von Custom Code in n8n einsteigen willst, schrieb ich einen vollständigen Guide zum Aufrufen von Python-Scripts aus n8n, der das Docker + FastAPI Setup abdeckt.
Was das für dich bedeutet
Der Trend ist klar.
Die produktivsten Builder im KI-Agent-Bereich stapeln keine MCP-Server und konfigurieren keine Protokoll-Adapter. Sie schreiben kleine, scharfe CLIs und lassen ihre Agenten sie aufrufen.
Peter Steinberger bewies es im großen Maßstab mit OpenClaw. OpenAI validierte es mit einem Jobangebot. Und du kannst heute anfangen mit einer CLAUDE.md-Datei und einem 20-Zeilen-Node-Script.
Der Stack ist egal. OpenClaw, Claude Code, Codex, eine eigene Agent-Schleife — das Muster ist dasselbe. Verpacke deine Tools in CLIs. Dokumentiere sie für deinen Agenten. Lass das LLM die Orchestrierung übernehmen.
Dein Terminal war die ganze Zeit eine KI-Schnittstelle. Die meisten haben es nur noch nicht gemerkt.
Wenn das bei dir klick gemacht hat, folge mir für mehr kampferprobten KI-Automatisierungs-Content. Als nächstes: Ich baue einen vollständig autonomen Agenten, der mein SaaS verwaltet — deployed, überwacht und Support-Tickets bearbeitet — komplett über CLIs. Kein Dashboard. Keine GUI. Nur ein Hummer und ein Cron-Job. 🦞
CLIs sind der Schlüssel zur effizienten KI-Agent-Entwicklung — direkt aus der Praxis von Entwicklern, die täglich mit KI-Tooling arbeiten.