Construyendo un agente SRE de IA con MCP: lo que realmente construí
Tabla de contenidos
Un agente SRE de IA no es un chatbot con acceso a kubectl. Es una capa de razonamiento sobre herramientas delimitadas.
He estado experimentando con servidores MCP desde que empezaron a ganar tracción en comunidades como r/LocalLLaMA. La idea es simple: en lugar de darle a un agente acceso directo a Kubernetes o AWS, expones un conjunto pequeño de herramientas a través de un protocolo estándar. El agente descubre e invoca esas herramientas, pero no puede hacer nada que no esté expuesto.
Este post describe cómo construí un agente SRE sobre un servidor MCP. No es teórico. Es lo que realmente ejecuto en mi homelab.
Por qué MCP para agentes de infraestructura
El problema con la mayoría de las demos de agentes es el alcance. Conectan el agente a una shell y confían en que el prompt sea suficiente. Eso funciona hasta que no funciona.
MCP hace explícita la capa de herramientas. Cada herramienta tiene nombre, descripción, esquema e implementación acotada. El agente solo puede invocar lo expuesto. El operador controla lo expuesto.
Para infraestructura, eso es exactamente lo que quiero. No quiero que el agente ejecute kubectl arbitrario. Quiero que llame a get_pod_logs, list_deployments o restart_deployment si he decidido que es seguro.
La arquitectura que realmente uso
Cuatro capas:
- Observabilidad: API de Kubernetes, métricas, logs.
- Servidor MCP: FastMCP u oficial SDK, exponiendo herramientas acotadas.
- Runtime del agente: Kimi Code, Continue.dev o agente custom.
- Gobernanza: logs de auditoría, gates de aprobación, políticas.
La capa 4 es la que la gente omite. También es la que evita incidentes.
Lo que realmente se ve el servidor MCP
Mi servidor MCP actual tiene exactamente dos herramientas:
from kubernetes import client, configfrom mcp.server.fastmcp import FastMCP
mcp = FastMCP("k8s-diagnostics")config.load_kube_config()v1 = client.CoreV1Api()
@mcp.tool()async def get_pod_logs( pod_name: str, namespace: str = "default", tail_lines: int = 100,) -> str: """Obtiene logs recientes de un pod de Kubernetes.""" try: logs = v1.read_namespaced_pod_log( name=pod_name, namespace=namespace, tail_lines=tail_lines, ) return logs except client.exceptions.ApiException as e: return f"Error de la API de Kubernetes: {e.status}: {e.reason}"
@mcp.tool()async def list_pods(namespace: str = "default") -> str: """Lista pods y su estado en un namespace.""" try: pods = v1.list_namespaced_pod(namespace=namespace) lines = [f"{'POD':<40} {'ESTADO':<12} {'REINICIOS':<10}"] for pod in pods.items: restarts = sum( c.restart_count for c in (pod.status.container_statuses or []) ) lines.append( f"{pod.metadata.name:<40} {pod.status.phase:<12} {restarts:<10}" ) return "\n".join(lines) except client.exceptions.ApiException as e: return f"Error de la API de Kubernetes: {e.status}: {e.reason}"
if __name__ == "__main__": mcp.run(transport="stdio")Solo lectura. Solo dos herramientas. No hay restart_deployment, no hay delete_pod, no hay exec_into_container. Todavía no. Estoy en el escalón 1 de una escalera de confianza que tiene muchos escalones.
La escalera de confianza
Mi plan, no mi realidad actual:
| Escalón | Herramientas | Ejemplos | Estado |
|---|---|---|---|
| 1 | Solo lectura | get_pod_logs, list_pods | Aquí estoy ahora |
| 2 | Lectura con contexto | get_deployment_events, describe_node | Planeado |
| 3 | Acciones reversibles | scale_deployment, restart_deployment | No antes de 6 meses de evidencia |
| 4 | Acciones con aprobación | apply_manifest, rollback | Solo con gate humano |
| 5 | Autonomía limitada | Auto-escalar, auto-reiniciar | No este año |
La mayoría de las demos que veo online saltan al escalón 4 o 5 sin pasar por los primeros. Eso es marketing, no ingeniería.
Defaults de seguridad
Mis reglas para el servidor MCP:
- Solo lectura por defecto.
- Allowlists de namespaces.
- Modo dry-run para herramientas de escritura durante desarrollo.
- Gates de aprobación para acciones destructivas.
- Cada invocación de herramienta logueada con contexto completo.
Prefiero agregar una herramienta lento a quitar un incidente después.
Conectando a un agente
Kimi Code tiene soporte nativo de MCP. Agregas el servidor a un archivo de configuración, reinicias, y el agente descubre las herramientas. La conexión se ve así:
{ "mcpServers": { "k8s-diagnostics": { "command": "python", "args": ["/path/to/mcp_server.py"], "env": { "KUBECONFIG": "/home/eduardo/.kube/config" } } }}Kimi Code no necesita saber de Kubernetes. Necesita saber de herramientas. Ese desacoplamiento es lo que hace MCP poderoso. Puedo cambiar la versión del cliente de Kubernetes sin tocar Kimi Code. Puedo cambiar Kimi Code sin tocar el servidor.
Para qué realmente lo uso
No lo uso para remediación autónoma. Todavía no. Lo uso para:
- Diagnosticar pods en
CrashLoopBackOffsin tener que ejecutarkubectl logsmanualmente. - Obtener una lista de pods con estado de reinicio para verificar si un despliegue está causando problemas.
- Rápidamente revisar logs de múltiples pods cuando algo se siente “mal” pero no hay alertas específicas.
Eso es todo. No es emocionante. No es futurista. Pero funciona, y no me ha hecho borrar nada.
Lo que no hace (y por qué)
- No reinicia pods. No hasta que tenga 6 meses de evidencia de que leer logs es confiable.
- No escala deployments. No hasta que entienda por qué algo necesita escalar.
- No aplica manifests. No hasta que tenga un pipeline de CI que valide los manifests antes de que el agente los vea.
- No ejecuta comandos arbitrarios. Nunca. Esa es la línea que no cruzo.
Conclusión
Construir un agente SRE de IA no se trata de darle más poder a la IA. Se trata de darle el poder correcto, con los límites correctos. Los servidores MCP hacen eso posible.
Empecé con diagnósticos de solo lectura. Agregaré acciones reversibles con aprobación cuando tenga evidencia. Mediré qué hace bien y dónde falla. Expandiré solo cuando los datos lo justifiquen.
La mayoría de las demos que ves online son escalón 4 o 5. Yo estoy en el escalón 1. No me avergüenza. Es donde debería estar.