Por Qué las CLI Superan a MCP para Agentes de IA — Y Cómo Construir Tu Propio Ejército de CLI

13 min read

Seis palabras. Eso es lo que publicó Peter Steinberger —el tipo detrás de OpenClaw, 190,000 estrellas en GitHub, recién fichado por Sam Altman— en X el mes pasado. Y mi reacción inmediata fue capturar pantalla y enviárselo a tres colegas desarrolladores con "OS LO DIJE" en mayúsculas.

Llevo años desarrollando en Ubuntu.

Cada herramienta que uso a diario es un CLI.

Supabase CLI, Vercel CLI, Docker, git, n8n — todo mi stack funciona desde terminal. Cuando los servidores MCP empezaron a ser tendencia el año pasado, probé algunos. Funcionaban. También se comían el 40% de mi ventana de contexto, se colgaban aleatoriamente y añadían una dependencia para algo que ya podía hacer con una línea y un pipe.

Así que cuando el desarrollador open-source más prolífico de 2026 dice que los CLIs son la verdadera interfaz entre los agentes de IA y el mundo —y OpenAI está tan de acuerdo que lo contrata— quizás sea hora de prestar atención.

TL;DR: Los servidores MCP inflan tu ventana de contexto, añaden dependencias frágiles y resuelven un problema que no existe si tus herramientas son CLIs 😂 Peter Steinberger construyó ~10 CLIs personalizados para OpenClaw, y OpenAI lo fichó por ello.

Puedes usar el mismo patrón con Claude Code hoy (documenta CLIs en CLAUDE.md), conectarlos a OpenClaw como skills, o construir tu propio agente autónomo con la API tool_use de Anthropic. Los CLIs son la interfaz nativa entre agentes de IA y el mundo real. Las GUIs son para humanos. Las APIs son para servicios. Los CLIs son para agentes.

Agente de IA ejecutando comandos CLI en terminal versus servidor MCP sobrecargado
MCP: hinchando contextos desde 2024. CLI: siendo eficiente desde 1971.

El Caso Contra MCP (Y Por Qué el Tipo de OpenClaw Coincide Con Mi Terminal)

Clasifiquemos las formas en que un agente de IA puede interactuar con herramientas externas. De peor a mejor.

Las GUIs obviamente están descartadas. No le pedirías a tu pipeline de CI/CD que haga clic en botones de un navegador. La misma lógica aplica a los agentes. Sigamos.

Las APIs REST y SDKs funcionan. Pero cada servicio tiene su propio flujo de autenticación, su propio formato de respuesta, su propio manejo de errores. Terminas escribiendo código wrapper para cada integración. Está bien para un backend SaaS. Es excesivo para un agente que solo necesita verificar si tienes emails nuevos.

MCP —el Model Context Protocol— se suponía que arreglaría esto. Un protocolo estándar para conectar agentes con herramientas. Suena genial en teoría. ¿En la práctica? Cada servidor MCP que añades vuelca todo su esquema en la ventana de contexto de tu agente. Descripciones de herramientas, listas de parámetros, declaraciones de capacidades —todo. Antes de que tu agente haya empezado siquiera a pensar en tu petición real, el 30-40% de su contexto ya está consumido por boilerplate de MCP.

Peter Steinberger lo probó. Construyó soporte para ello. Luego construyó MCPorter —una herramienta que literalmente convierte servidores MCP de vuelta a CLIs. Así de equivocado piensa que está el formato.

Sus palabras exactas sobre lo que MCP realmente aportó al ecosistema: "Lo único bueno de MCP fue que las empresas abrieron algunas APIs."

Brutal. Y preciso.

El protocolo en sí fue un desvío —las APIs que forzó a existir son el verdadero regalo.

Los CLIs ganan porque son lo opuesto a toda esa hinchazón. Un CLI es:

  • Cero sobrecarga de contexto. Tu agente no necesita cargar un esquema. Lee un documento de una página (o ejecuta --help) y conoce cada comando disponible.
  • Componible. Pasa la salida de un CLI a otro. goplaces search "coffee" --json | jq '.[0].address' - intenta hacer eso con un servidor MCP.
  • Testeable en 2 segundos. Abre una terminal, ejecuta el comando, ve qué pasa. No hay servidor que levantar, no hay handshake de protocolo, no hay conexión WebSocket.
  • Salida estructurada gratis. Añade una flag --json y tu agente obtiene datos parseables sin ninguna capa de serialización.

Una llamada exec. Eso es todo lo que un agente necesita para usar un CLI. Sin middleware, sin protocolo, sin proceso servidor corriendo en segundo plano comiendo RAM por el privilegio de estar disponible.

Comparación arquitectura CLI simple versus servidor MCP complejo para agentes IA
Un protocolo para gobernarlos a todos. Un CLI para liberarlos.

Y esto no es alguna preferencia teórica.

Steinberger construyó todo su ecosistema OpenClaw alrededor de CLIs. Cerca de una docena: goplaces para Google Maps, imsg para iMessage, bird para X/Twitter, wacli para WhatsApp, gog para Gmail y Calendar, camsnap para cámaras de seguridad, peekaboo para capturas de pantalla de macOS con visión IA, summarize para digerir videos y podcasts. Cada uno sigue el mismo patrón: hace una cosa bien, soporta --json, tiene un --help claro.

Luego OpenAI lo contrató.

Se pasó la mayor parte de un año construyendo este ejército de CLIs. Luego OpenAI lo contrató. Sam Altman no reclutó a un tipo que construyó dashboards bonitos —reclutó al tipo que demostró que bash es la mejor interfaz para agentes. Saca tus propias conclusiones.

Usando CLIs Ahora Mismo para Construir Más Rápido (Sin Necesidad de OpenClaw)

No necesitas OpenClaw para beneficiarte de esto. Si estás usando Claude Code, Codex, o cualquier agente con acceso a shell, ya tienes la infraestructura.

El truco que la mayoría se pierde: tu agente ya puede llamar CLIs. Pero no conoce TUS CLIs específicos a menos que se lo digas.

# CLAUDE.md (raíz de tu proyecto)

## CLIs Disponibles

### Supabase
- `supabase db push` - aplicar migraciones a remoto
- `supabase functions deploy ` - desplegar edge function
- `supabase db dump --data-only` - exportar datos de producción
- `supabase migration new ` - crear nuevo archivo de migración

### Vercel
- `vercel deploy --prod` - desplegar a producción
- `vercel env pull .env.local` - sincronizar variables de entorno
- `vercel logs --follow` - seguir logs de producción

### Específicos del proyecto
- `./scripts/check-mrr.sh` - devuelve JSON con MRR actual, registros, abandono
- `./scripts/seed-demo.sh` - resetea entorno demo con datos de muestra

Eso es todo.

Claude Code lee CLAUDE.md al inicio de cada sesión. La próxima vez que digas "despliega a prod y verifica si cambió el MRR," sabe exactamente qué comandos ejecutar. Sin plugin, sin servidor MCP, sin archivo de configuración con 47 claves anidadas.

Para Codex, mismo concepto —el archivo se llama AGENTS.md.

Para Cursor, .cursorrules.

Nombre de archivo diferente, patrón idéntico.

Pero la jugada maestra es construir tus propios CLIs. Y antes de que cierres esta pestaña pensando "no tengo tiempo para construir herramientas CLI" —estamos hablando de 20-30 líneas de código. En serio.

Tres reglas para un CLI amigable con agentes:

1. Salida estructurada con **--json**

Tu agente no puede parsear una tabla bonita con caracteres de dibujo de cajas. Necesita 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(`Activos: ${active.length}`)
console.log(`Registros hoy: ${today.length}`)
}

2. Un **--help** que realmente explique las cosas

Los agentes leen --help como los humanos leen READMEs. Si tu texto de ayuda es basura, tu agente alucinará las flags.

$ ./check-mrr.js --help
Uso: check-mrr [opciones]

Verifica métricas SaaS actuales desde Supabase.
Opciones:
--json Salida como JSON (por defecto: legible para humanos)
--period Filtro: today | week | month (por defecto: today)
--help Mostrar este mensaje

3. Códigos de salida limpios

0 = éxito. 1 = error.

Tu agente usa esto para decidir qué hacer después. Si tu CLI sale con 0 en caso de fallo, tu agente piensa que todo está bien y continúa.

Aprendí esto por las malas a las 2 AM cuando mi script de deploy estaba fallando silenciosamente y Claude seguía diciéndome "despliegue exitoso" —me tomó 20 minutos darme cuenta de que el script estaba tragándose los errores y saliendo con 0 de todas formas, pero divago.

Una vez que tienes algunos de estos CLIs, algo cambia.

Dejas de pedirle a Claude Code que escriba queries de Supabase. Empiezas a decir "verifica mis métricas, y si los registros cayeron más del 20% desde ayer, redacta un mensaje de Slack para el equipo." Claude encadena los CLIs, decide la lógica, actúa sobre el resultado. Eso no es autocompletado. Eso es un agente.

El Patrón Que Hace Esto Escalable: CLI + Documentación de Skill

Entonces aquí está lo que Steinberger descubrió temprano, y que la mayoría de la gente aún no ha interiorizado: un CLI sin documentación es inútil para un agente.

Tu agente no puede explorar un CLI por prueba y error como lo haría un humano. Necesita saber de antemano qué comandos existen, qué flags están disponibles, cómo se ve la salida. Por eso cada CLI en el ecosistema OpenClaw viene con un SKILL.md —un documento estructurado que actúa como manual de instrucciones para el agente.

El patrón es: binario CLI + documentación de skill = capacidad autónoma.

El CLI hace el trabajo. La documentación de skill enseña al agente cómo usarlo. Juntos, son una unidad autocontenida que cualquier agente puede tomar y ejecutar. Steinberger los llama "skills". El concepto es el mismo ya sea que lo llames skill, herramienta, o "ese script bash que escribió Dave el martes pasado."

Y no necesitas OpenClaw para usar este patrón. Ya lo estás haciendo, de hecho —cuando escribes un CLAUDE.md que documenta tus CLIs, eso es una documentación de skill. La diferencia es que Steinberger estandarizó el formato y construyó una capa de distribución encima: ClawHub, con más de 3,000 skills que puedes navegar e instalar.

¿La parte interesante? Puedes robar cualquiera de esos skills para tu propia configuración. Cada skill en ClawHub es solo un CLI que puedes instalar independientemente (brew install steipete/tap/goplaces, npm install -g @steipete/oracle, etc.) y un SKILL.md que puedes leer. No necesitas el runtime de OpenClaw. Instala el binario, pega los comandos relevantes en tu CLAUDE.md, y Claude Code puede usarlo inmediatamente.

# En tu CLAUDE.md — robado directamente de ClawHub

## goplaces (CLI de Google Maps)
- `goplaces search "café cerca de mí" --open-now --json` - encontrar lugares
- `goplaces search "pizza" --lat 40.8 --lng -73.9 --radius-m 3000 --json` - búsqueda sesgada por ubicación
- `goplaces details <place_id> --json` - detalles completos del lugar con reseñas
- `goplaces resolve "Soho, London" --json` - geocodificar un nombre de lugar
Requiere: variable de entorno GOOGLE_PLACES_API_KEY

## summarize (CLI resumidor de Video/Podcast/Web)
- `summarize --url "https://youtube.com/watch?v=xxx" --json` - resumir un video
- `summarize --url "https://some-blog.com/post" --json` - resumir una página web
- `summarize --url "https://podcast.fm/ep42" --cli claude --json` - elegir qué modelo usar

Eso es goplaces y summarize —dos de las propias herramientas de Steinberger— ejecutándose dentro de Claude Code con cero dependencia de OpenClaw. Solo un binario y un documento.

Por esto es que el enfoque CLI escala de una manera que MCP nunca podrá. Un servidor MCP es un proceso en ejecución que necesita configuración, un handshake de protocolo y espacio en la ventana de contexto. Un skill CLI es un binario estático y un archivo de texto. Uno requiere infraestructura. El otro requiere un brew install y 10 líneas de markdown.

Conectando CLIs a OpenClaw

Si ya estás ejecutando OpenClaw, convertir un CLI en un skill de agente toma unos 5 minutos.

El sistema funciona así: cada skill tiene un archivo SKILL.md que describe qué hace el CLI, cómo instalarlo y qué comandos están disponibles. El agente lee ese archivo y sabe cómo usar la herramienta.

---
name: check-mrr
description: Verificar métricas SaaS (MRR, registros, abandono) desde Supabase.
metadata:
openclaw:
requires:
env:
- SUPABASE_URL
- SUPABASE_KEY
bins:
- node
primaryEnv: SUPABASE_URL
---

# check-mrr
Obtener métricas SaaS actuales desde Supabase de producción.
## Instalar
npm install -g @yourhandle/check-mrr
## Comandos
- `check-mrr --json` - métricas completas como JSON
- `check-mrr --period week` - métricas para la semana actual
- `check-mrr --period month` - resumen mensual
## Formato de salida (--json)
{
"mrr": 1247,
"active_subscriptions": 89,
"signups_today": 3,
"timestamp": "2026-02-17T10:30:00Z"
}

Publícalo en ClawHub (clawhub publish) y cualquiera ejecutando OpenClaw puede instalar tu skill. Pero el valor real es local: combínalo con un cron job, y tu agente verifica tus métricas cada mañana y te avisa por WhatsApp si algo se ve mal.

// En openclaw.json
{
"cron": [
{
"schedule": "0 8 * * *",
"message": "Ejecuta check-mrr --json. Si signups_today es 0 o el mrr cayó más del 5% desde ayer, alertarme en WhatsApp con un resumen. Si no, solo registrarlo.",
"channel": "whatsapp"
}
]
}

Ese es el ciclo completo. Cron activa el agente, el agente lee el skill, llama al CLI, interpreta el resultado, decide qué hacer. Sin dashboard que revisar. Sin fatiga de notificaciones por alertas que no necesitas. El agente usa criterio —el mismo patrón que Steinberger ejecuta en toda su configuración.

El directorio ClawHub ya tiene más de 3,000 skills de terceros, la mayoría siguiendo exactamente esta estructura. goplaces para búsqueda de ubicación, himalaya para email vía IMAP, bird (😭) para X/Twitter, sonoscli para control de altavoces - todo el ejército. Los instalas, el agente los aprende, listo.

Construyendo Tu Propio Agente (El Patrón OpenClaw, Sin OpenClaw)

OK entonces ¿qué pasa si no quieres ejecutar OpenClaw?

Tal vez quieres algo más ligero, más personalizado, o simplemente disfrutas construir cosas desde cero. (Lo entiendo. Yo auto-hosteo todo. Es una enfermedad.)

El patrón central es súper simple: un script que llama a la API de Anthropic con tool_use, mapea llamadas de herramientas a ejecuciones CLI, y hace loop hasta que el agente termina.

import Anthropic from '@anthropic-ai/sdk'
import { execSync } from 'child_process'

const client = new Anthropic()
// Tus CLIs, declarados como herramientas
const tools = [
{
name: "check_mrr",
description: "Obtener métricas SaaS actuales (MRR, suscripciones activas, registros hoy)",
input_schema: {
type: "object",
properties: {
period: { type: "string", enum: ["today", "week", "month"], default: "today" }
}
}
},
{
name: "deploy_production",
description: "Desplegar último commit a producción de Vercel. Devuelve URL de deploy.",
input_schema: {
type: "object",
properties: {}
}
},
{
name: "send_slack",
description: "Enviar un mensaje a un canal de Slack",
input_schema: {
type: "object",
properties: {
channel: { type: "string" },
message: { type: "string" }
},
required: ["channel", "message"]
}
}
]
// Mapear nombres de herramientas a comandos CLI
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 })
}
}
// El loop del agente
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: "Eres un agente autónomo. Usa las herramientas disponibles para completar tareas. Sé conciso en tu razonamiento.",
tools,
messages
})
// Si Claude terminó de hablar, terminamos
if (response.stop_reason === "end_turn") {
const text = response.content.find(b => b.type === 'text')
return text?.text || 'Listo.'
}
// Si Claude quiere usar herramientas, ejecutarlas
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 })
}
}
// Ejecutarlo
const result = await runAgent(
"Verifica nuestro MRR. Si está por encima de $1000, despliega a producción y notifica a #team en Slack con las métricas. Si está por debajo, solo envía una advertencia a Slack."
)
console.log(result)

~80 líneas. Ese es tu propio mini-OpenClaw. El agente decide qué herramientas llamar y en qué orden basándose en la tarea que le das. Añadir un nuevo CLI toma 30 segundos —añade una definición de herramienta, añade una línea en el mapa commands, listo.

Para la parte autónoma, envuélvelo en un cron:

# crontab -e
0 8 * * * cd /home/deploy/my-agent && node agent.js "Verificación matutina: métricas, desplegar si está estable, notificar equipo"
0 20 * * * cd /home/deploy/my-agent && node agent.js "Fin del día: resumir registros, marcar cualquier anomalía a Slack"

También puedes ejecutar esto como un servicio systemd con un timer, o meterlo en un contenedor Docker en tu servidor. Mismo resultado, diferentes sabores de devops.

Desarrollador construyendo CLI personalizado para integración con agentes de IA
Construir CLI: 30 minutos. Explicar por qué no usaste MCP: eternidad.

GitHub Actions es otra opción si quieres cero infraestructura. Un workflow programado que instala tus CLIs en el runner y llama a la API de Anthropic:

name: Ejecución Diaria del Agente
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 "Rutina matutina"
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
SUPABASE_KEY: ${{ secrets.SUPABASE_KEY }}

Gratis para repos públicos, 2,000 minutos/mes en privados. No está mal para un agente diario que se ejecuta en 30 segundos.

¿Y n8n?

Técnicamente puedes orquestar CLIs a través de n8n usando el nodo Execute Command o envolviéndolos en contenedores FastAPI.

Pero honestamente, es más fricción que el enfoque de script para este caso de uso. n8n brilla cuando necesitas workflows visuales con 15 pasos y ramificación compleja —no para "llamar un CLI y dejar que el LLM decida."

Si quieres profundizar en ejecutar código personalizado en n8n, escribí una guía completa sobre llamar scripts de Python desde n8n que cubre la configuración Docker + FastAPI.

Qué Significa Esto Para Ti

La tendencia es clara.

Los constructores más productivos en el espacio de agentes de IA no están apilando servidores MCP y configurando adaptadores de protocolo. Están escribiendo CLIs pequeños y afilados y dejando que sus agentes los llamen.

Peter Steinberger lo demostró a escala con OpenClaw. OpenAI lo validó con una oferta de trabajo. Y puedes empezar hoy con un archivo CLAUDE.md y un script Node de 20 líneas.

El stack no importa. OpenClaw, Claude Code, Codex, un loop de agente personalizado —el patrón es el mismo. Envuelve tus herramientas en CLIs. Documéntalas para tu agente. Deja que el LLM maneje la orquestación.

Tu terminal era una interfaz de IA todo este tiempo. La mayoría de la gente simplemente no se había dado cuenta aún.


Si esto te resonó, sígueme para más contenido de automatización IA probado en batalla. Lo siguiente: estoy construyendo un agente completamente autónomo que gestiona mi SaaS —despliega, monitorea y maneja tickets de soporte— enteramente a través de CLIs. Sin dashboard. Sin GUI. Solo una langosta y un cron job. 🦞


Descubre por qué los CLIs son el arma secreta de los agentes de IA, directamente desde la trinchera de un desarrollador que construye herramientas reales.

Únete a la newsletter de desarrollo de agentes