Darle un cluster de Kubernetes a un agente LLM sin miedo

Darle kubectl a un agente de código es fácil. El problema es todo lo que
viene con eso: tu kubeconfig, que seguramente también tiene un cluster de
staging, quizá producción, quizá un login de la nube que ejecuta un exec
plugin la primera vez que se usa. Un --context equivocado, o ninguno, y
“limpia los pods que fallan” termina pasando donde no querías.
litek8s mcp es nuestra respuesta para clusters locales y de home lab: un
servidor MCP dentro del mismo binario de litek8s, con herramientas que
responden en JSON estructurado y barreras que viven en el código y no en un
prompt. Este post cuenta qué le da a un agente, qué lo frena y los huecos que
conocemos.
Configuración
Para Claude Code:
claude mcp add litek8s -- litek8s mcp # all toolsclaude mcp add litek8s -- litek8s mcp --context litek8s-dev # pin a default clusterclaude mcp add litek8s-ro -- litek8s mcp --read-only # no apply/delete/cluster changeslitek8s skill --install ~/.claude/skills # the skill, for every projectCualquier otro cliente MCP también sirve: el servidor habla MCP por stdio
(JSON-RPC, un mensaje por línea), versiones de protocolo 2025-06-18,
2025-03-26 y 2024-11-05, y se arranca con
{"command": "litek8s", "args": ["mcp"]}.
Lo que recibe el agente
| necesita | herramientas |
|---|---|
| clusters donde trabajar | clusters_list, cluster_status, cluster_up, cluster_down, cluster_delete, contexts_list |
| objetos | get (una tabla, o un objeto con sus eventos y su cadena de dueños), describe, events |
| por qué este pod está roto | diagnose_pod |
| cambiar cosas | apply (server-side apply, dry_run), delete |
| logs | pod_logs (previous), logs_search (entre pods y nodos, incluidos contenedores borrados) |
| métricas y alertas | query, query_range (PromQL sobre las métricas incluidas), alerts_list, alert_silence, alert_unsilence |
| GitOps | applications_list, application_status, application_diff, application_sync, application_refresh |
| Docker en un cluster de desarrollo | docker_ps, docker_images, docker_logs |
La skill (skills/litek8s/, que imprime litek8s skill) le dice al agente
cuándo usar estas herramientas y cuándo basta con kubectl, con flujos de
trabajo, recetas de PromQL, en qué se diferencia litek8s del Kubernetes
upstream y cómo diagnosticar problemas. El servidor también la expone, junto
con la documentación, como recursos MCP compilados dentro del binario.
Una llamada en vez de seis
La forma típica en que un agente depura un pod es un ciclo: get pods,
describe, logs, logs --previous, get events, get deployment, y cada
paso le vuelca texto en el contexto. diagnose_pod hace todo eso en una
llamada y pone la conclusión primero. Este es el ejemplo de la documentación,
recortado:
> diagnose_pod {"context": "litek8s-demo", "namespace": "default", "selector": "app=web"}{"pod": "default/web-7c9f-abcde", "ready": false, "phase": "Running", "findings": [{"severity": "error", "reason": "CrashLoopBackOff", "message": "container web keeps exiting (4 restarts); last exit code 1 (Error: application error (see its logs))", "next_step": "Read previous_logs below: the reason it exited is usually in its last lines."}], "containers": [...], "owners": [{"kind": "ReplicaSet", ...}, {"kind": "Deployment", "status": "ready 0/1"}], "events": [...], "logs": {"web": {"previous_logs": ["Error: DATABASE_URL is not set"]}}}findings[0] trae la causa y el siguiente paso; el resto es la evidencia:
condiciones, estado de los contenedores, última salida, probes, si el nodo
está listo, eventos, dueños, logs actuales y anteriores. Un detalle que vale
la pena saber: el agente de nodo de litek8s no registra los eventos
Unhealthy, BackOff ni Failed del kubelet, así que el diagnóstico lee el
estado de los contenedores, las últimas terminaciones y la definición de las
probes en lugar de los eventos.
El repositorio prueba esto con un agente real. compat/agents-e2e.sh crea un
cluster de desarrollo desechable con un Deployment que se reinicia en bucle y
otro que nunca queda listo, corre Claude Code sin interfaz (claude -p) con
solo las herramientas MCP de litek8s permitidas y la skill instalada, y
verifica que su respuesta nombre las dos causas: DATABASE_URL, sacado de
los logs anteriores, y el puerto 8080 de la probe.
Las barreras
Solo litek8s. Antes de la primera llamada a un API server, y de nuevo
cada minuto, el servidor lee /version sin credenciales y se niega a
seguir si gitVersion no lleva +litek8s. De ahí salen dos cosas. El exec
plugin de un kubeconfig (un login de la nube) nunca se ejecuta para un
servidor que no es litek8s. Y un contexto que apunta a otro cluster recibe
un error, no una acción. El mensaje, tal como está en el código:
refusing: context prod (…) is not a litek8s API server (gitVersion …). These tools only operate litek8s clusters; use kubectl for other clusters.Las herramientas de Docker hacen lo mismo: rechazan un motor cuya plataforma
en /version no sea litek8s.
Lo destructivo son dos llamadas. delete, application_sync,
cluster_down y cluster_delete no cambian nada sin confirm: true. Sin
eso responden qué pasaría. Un delete ilustrativo de un Deployment sin
confirm, con los campos que devuelve el código:
> delete {"context": "litek8s-demo", "kind": "deployments", "name": "web"}{"would_delete": "Deployment/web", "context": "litek8s-demo", "namespace": "default", "note": "its 1 replicas (and their pods) go with it", "confirmed": false, "hint": "Nothing was changed. This is destructive: call again with confirm: true once the user agrees."}application_sync sin confirm lista lo que está desincronizado y lo que se
borraría (prune). Además, las herramientas llevan anotaciones MCP
(readOnlyHint, destructiveHint), para que el cliente le pregunte al
usuario antes de ejecutarlas.
--read-only deja fuera todas las herramientas que cambian algo. El
agente no puede llamar lo que no ve.
Límite de tamaño. Un resultado de más de --max-output caracteres
(20000) se corta: las listas conservan el principio, los logs y eventos lo
más reciente, y _truncated explica cómo acotar la consulta. Un pod con un
mega de logs no se come la ventana de contexto del agente.
Sin canales laterales. Los comandos de clusters de desarrollo corren como procesos hijos con su salida capturada en el resultado, y el servidor nunca cambia el contexto de kubectl ni el de Docker a tus espaldas.
Clusters desechables, tan baratos que son lo normal
La regla de la skill para experimentar es: hazlo en un cluster aparte.
cluster_up name=try nodes=1, luego apply, get o diagnose_pod, y al
final cluster_delete name=try confirm=true. Eso solo tiene sentido porque un
cluster de desarrollo es pequeño y rápido:
| litek8s | referencia | |
|---|---|---|
dev up → nodo Ready, Linux / macOS |
0.17 s / 1.28 s | kind 31.6 s / 34.3 s, k3d 11.1 s / 10.4 s |
Medido con los scripts de benchmark del repositorio; el detalle está en
Números. El contexto es litek8s-<nombre>, y
cluster_up lo agrega sin cambiar el actual.
GitOps y métricas sin montar nada nuevo
El cluster ya trae métricas, logs y alertas, así que el agente responde “¿está lento, grande, reiniciándose?” con PromQL en lugar de adivinar. Una receta de la skill:
topk(10, sum by (namespace, pod) (container_memory_working_set_bytes{container!=""}))Para las Applications de Argo CD (reconciliadas por Argo CD o por litecd),
application_status lista los recursos que necesitan atención con sus
mensajes de salud, y application_diff muestra un diff unificado por recurso
entre lo vivo y git, a partir del Secret <app>.diff que publica su
controlador. Con Argo CD, que no publica ninguno, lo dice.
De qué no te protege
Las barreras en código son mejores que las barreras en un prompt, pero tienen bordes. Estos son los nuestros:
- Solo litek8s no es solo desarrollo. Un servidor litek8s que instalaste
en serio con
litek8s install servertambién dice+litek8s. Si un cluster así está en tu kubeconfig, las herramientas lo van a operar. Registra un servidor--read-onlyaparte para él, o fija--contextal cluster de desarrollo. - La verificación no es autorización. Una vez que un servidor pasa, las
herramientas usan las credenciales del kubeconfig. En un servidor, lo que
las limita es RBAC; los clusters de desarrollo siguen en AlwaysAllow sobre
127.0.0.1. - Un agente con shell igual puede correr kubectl. La skill le dice que no apunte kubectl a otros contextos y que siempre nombre el contexto que quiere usar. Eso es una regla en un prompt, no un muro. Si te importa, permite solo las herramientas MCP, como hace la prueba de punta a punta.
confirm: trueestá a un argumento de distancia. La vista previa hace que el agente vea la consecuencia primero, y las anotaciones le permiten al cliente preguntarte, pero un cliente que lo aprueba todo automáticamente también va a aprobar esto.
Pruébalo
brew install jairoFernandez/tap/litek8sclaude mcp add litek8s -- litek8s mcplitek8s skill --install ~/.claude/skillsDespués pídele a tu agente que cree un cluster, que rompa algo en él y que te
diga por qué. La lista completa de herramientas, las barreras y los comandos
con -o json están en MCP y agentes LLM; las métricas que
puede consultar, en Métricas, logs y alertas.