Cuando construyes un servidor MCP que permite a agentes IA gestionar infraestructura de producción, la pregunta no es si el agente puede reiniciar tu aplicación -- es si debería, y quién lo autorizó.
El servidor MCP de sh0 comenzó con 12 herramientas de solo lectura. Un agente IA podía listar aplicaciones, verificar el estado del servidor, leer logs. Útil, pero limitado. La Fase 3 agrega operaciones de escritura: reiniciar, desplegar, escalar, respaldar, ejecutar tareas cron, y sí -- eliminar aplicaciones y bases de datos.
El desafío: ¿cómo le das a los agentes IA poder real sin crear un arma de doble filo?
El modelo de seguridad de tres capas
Capa 1: Claves API con alcance
Cada conexión MCP se autentica con una clave API. Cada clave ahora lleva un alcance: read, standard o admin.
El alcance determina a qué nivel de riesgo de herramientas puede acceder la clave:
| Alcance | Herramientas lectura | Herramientas escritura | Herramientas destructivas |
|---|---|---|---|
read | Sí | No | No |
standard | Sí | Sí | No |
admin | Sí | Sí | Sí (con confirmación) |
La implementación es deliberadamente simple. Sin matrices RBAC complejas, sin listas de permisos por herramienta. Tres niveles, tres categorías de riesgo, una matriz directa. Esto es importante porque las personas que configuran estas claves necesitan entender el modelo de seguridad en 30 segundos.
Por compatibilidad retroactiva, las claves API existentes tienen alcance admin por defecto. Los usuarios autenticados por JWT (el dashboard) omiten la verificación de alcance por completo -- ya tienen acceso total.
Capa 2: Clasificación de riesgos
Cada herramienta MCP tiene un nivel de riesgo:
- Read:
list_apps,get_server_status,server_metrics-- no pueden modificar estado - Write:
restart_app,deploy_app,scale_app-- modifica estado pero es recuperable - Destructive:
delete_app,delete_database-- permanente, irreversible
El nivel de riesgo se declara en la especificación OpenAPI vía extensiones x-mcp-risk, el mismo mecanismo que la Fase 2 introdujo para auto-generar definiciones de herramientas. Pero para la aplicación, usamos una función tool_risk() con match simple en la capa de transporte. La especificación es la fuente de verdad para la documentación; la sentencia match es la fuente de verdad para la aplicación. Deliberadamente desacoplados -- no puedes cambiar accidentalmente la aplicación editando un comentario de documentación.
Capa 3: Tokens de confirmación
Incluso con alcance admin, las operaciones destructivas no se ejecutan inmediatamente. En cambio:
- El agente IA llama
delete_appconapp_id: "myapp" - El servidor MCP devuelve un mensaje:
- > Esta acción ELIMINARÁ la aplicación 'myapp' y su contenedor. Esto no se puede deshacer. Para confirmar, llama confirm_action con el token:
abc-123-def - El agente debe llamar
confirm_actioncon ese token - Solo entonces procede la eliminación
El token es:
- De un solo uso: eliminado después de la confirmación
- Con tiempo limitado: TTL de 5 minutos con evicción perezosa
- Vinculado al usuario: el usuario que confirma debe coincidir con el que solicita
- En memoria: sin persistencia, sin cron de limpieza -- solo un HashMap con verificaciones de TTL
Esto le da a la IA (o al humano que la supervisa) una pausa deliberada. El agente ve una descripción clara de las consecuencias y debe hacer una segunda llamada explícita. Para flujos de trabajo agénticos donde un humano revisa las acciones del agente, esto crea un punto de control visible.
¿Por qué no simplemente usar middleware?
La alternativa era un middleware de Axum que intercepte todas las solicitudes MCP y verifique permisos. Lo rechazamos por tres razones:
- Las herramientas MCP no mapean 1:1 a endpoints REST. La herramienta
confirm_actionno tiene equivalente REST. La herramientaget_app_logsllama a Docker directamente, no a un manejador REST.
- El flujo de confirmación es específico de MCP. Los clientes REST usan la UI del dashboard para confirmación. Los clientes MCP necesitan un mecanismo a nivel de protocolo.
- La semántica de alcance difiere entre REST y MCP. Una clave API REST podría tener permisos granulares por endpoint. Los alcances MCP son más gruesos por diseño -- los agentes IA necesitan modelos de acceso simples y predecibles.
La pista de auditoría
Cada operación MCP de escritura y destructiva se registra en el sistema de auditoría con un prefijo mcp::
mcp:restart_app app app-123 myapp
mcp:deploy_app deploy dep-456 myapp
mcp:delete_app app app-123 myappEsto hace trivial responder "¿qué hizo el agente IA?" después del hecho. Filtra los logs de auditoría por mcp:* y tienes un historial completo de mutaciones iniciadas por IA.
Lo que aprendimos
Simple supera a configurable. Tres alcances, tres niveles de riesgo, una matriz. Cualquiera puede entenderlo. La tentación era construir permisos por herramienta, jerarquías de roles, ventanas de acceso basadas en tiempo. Toda esa complejidad serviría a casos extremos mientras haría el caso común más difícil de razonar.
Los tokens de confirmación son sorprendentemente efectivos. Resuelven dos problemas: prevenir destrucción accidental y crear un punto de decisión visible en la auditoría. También funcionan naturalmente con cómo operan los agentes IA -- el agente ve el mensaje de advertencia en su contexto y puede decidir si proceder.
La columna scopes existente ahorró una migración. La tabla de claves API ya tenía un campo scopes de formato libre. Lo reutilizamos con semántica definida (read, standard, admin) y un valor predeterminado retrocompatible. Sin cambio de esquema, sin migración, sin riesgo de tiempo de inactividad.
Próximos pasos
La Fase 3 está completa y encaminándose a dos rondas de auditorías independientes. Los auditores revisarán: - Corrección de la aplicación de alcance (sin rutas de bypass) - Seguridad de los tokens de confirmación (sin replay, sin cruce de usuarios, sin ataques de temporización) - Seguridad del ejecutor de escritura (sin unwrap, manejo de errores adecuado, llamadas Docker correctas) - Compatibilidad retroactiva (herramientas de lectura existentes sin cambios, claves existentes siguen funcionando)
Después de las auditorías, probaremos con Claude Desktop como cliente MCP para validar la experiencia de extremo a extremo.