easypanel-mcp-server
Servidor MCP para control total de Easypanel mediante Claude Code, Cursor y Claude Desktop.
Documentación
easypanel-mcp-server
Servidor MCP para el control completo de Easypanel mediante Claude Code, Cursor y Claude Desktop.
Qué es esto
easypanel-mcp-server conecta Claude Code, Cursor y Claude Desktop directamente a tu instancia de Easypanel — un panel de control de servidores moderno basado en Docker — mediante el Protocolo de Contexto del Modelo.
En lugar de alternar entre tu editor y el panel de Easypanel, controlas todo desde dentro de Claude: desplegar desde GitHub, actualizar variables de entorno, leer registros en vivo, ejecutar comandos en los contenedores, gestionar dominios, bases de datos, volúmenes y puertos, establecer límites de recursos, realizar mantenimiento de Docker y supervisar tu servidor — todo en lenguaje natural.
Asigna la API de Easypanel a 57 herramientas tipadas en 15 categorías, más una única vía de escape easypanel_raw que llega a cualquiera de las ~375 operaciones de la API de Easypanel para todo lo que no cubre una herramienta dedicada. Habla las tres generaciones de la API — la API tRPC de paneles ≤ 2.30, la capa RPC de 2.31–2.32 y la API pública introducida en Easypanel 2.33 — detectando automáticamente cuál usa tu panel. Cada acción destructiva está protegida por una confirmación explícita, cada respuesta comienza con un banner de contexto para que Claude sepa siempre qué está tocando, y un modo de solo lectura opcional te permite conectarte de forma segura a un panel de producción.
📖 Referencia de la API: docs/easypanel-api.md — arquitectura, las generaciones de la API, operaciones confirmadas mapeadas herramienta por herramienta, y cómo descubrir otras nuevas.
Compatibilidad
Easypanel cambió su API dos veces en rápida sucesión:
- 2.31 sustituyó la API interna tRPC por una capa RPC (
/api/rpc/*). En paneles ≥ 2.31, toda llamada v1.x que lleve parámetros falla con400 Input validation failed. - 2.33 incluyó una API pública documentada (
/api/<operation>, GET para lecturas, POST para escrituras) y declaró que la antigua API interna "puede cambiar sin previo aviso y no debe utilizarse como base". v3 se dirige a la API pública en esos paneles.
| Tu versión de Easypanel | Usa |
|---|---|
| cualquiera (recomendado) | easypanel-mcp-server@latest (v3.x) — detecta automáticamente la generación, funciona en las tres |
| ≤ 2.30.x únicamente, fijada | easypanel-mcp-server@legacy (v1.3.x) — línea congelada solo-tRPC, última validada contra v2.30.1 |
v3 detecta la generación con una única sonda en la primera llamada (con caché) y registra la versión del panel en stderr. Para omitir la detección, establece EASYPANEL_API_FLAVOR a trpc (≤ 2.30), rpc (2.31–2.32) o public (≥ 2.33).
¿Actualizando desde v2? Si fijaste
EASYPANEL_API_FLAVOR=rpcpara solucionar los problemas de la 2.32, quítalo — de lo contrario el cliente permanece en la API interna que Easypanel ahora declara inestable.
Este MCP frente al MCP integrado de Easypanel
Easypanel 2.33 también incluye su propio endpoint MCP (/api/mcp, detalles de conexión junto a tu clave de API). Es un envoltorio ligero sobre la API pública. Este servidor es un equilibrio distinto:
| MCP integrado de Easypanel | easypanel-mcp-server | |
|---|---|---|
| Registros de contenedor en tiempo real | — | ✅ mediante /ws/serviceLogs (sin necesidad de Loki/licencia) |
| Ejecutar comandos dentro de un contenedor | — | ✅ exec_in_container con barrera de comandos destructivos |
| Eventos de Docker en vivo | — | ✅ get_docker_events |
| Modo de solo lectura | — | ✅ MCP_ACCESS_MODE=readonly bloquea toda escritura en el origen |
| Barrera de confirmación en operaciones destructivas | — | ✅ confirm: "CONFIRMO" |
Redacción de secretos (list_users) | — | ✅ elimina apiToken / twoFactorSecret |
| Lectura-modificación-escritura de variables de entorno | — | ✅ nunca sobrescribe otras variables |
| Construcción de cadenas de conexión | — | ✅ inspect_database |
| Cobertura de cada operación de la API | ✅ | ✅ mediante easypanel_raw |
| Instalación cero | ✅ | requiere npx/node |
Usar ambos a la vez es correcto — no entran en conflicto.
Requisitos previos
- Instancia de Easypanel en funcionamiento y accesible
- Token de API — genéralo en Easypanel → Settings → API → Generate Token
- Node.js ≥ 18 y Claude Code, Cursor o Claude Desktop
Inicio rápido
Opción A — npx (sin instalación necesaria)
Añade .mcp.json a la raíz de tu proyecto:
{
"mcpServers": {
"easypanel-mcp": {
"command": "npx",
"args": ["-y", "easypanel-mcp-server"],
"env": {
"EASYPANEL_URL": "https://your-panel.example.com",
"EASYPANEL_TOKEN": "your-api-token"
}
}
}
}
Opción B — compilación local
git clone https://github.com/helbertparanhos/easypanel-mcp-server
cd easypanel-mcp-server
npm install && npm run build
{
"mcpServers": {
"easypanel-mcp": {
"command": "node",
"args": ["/ABSOLUTE/PATH/easypanel-mcp-server/dist/index.js"],
"env": {
"EASYPANEL_URL": "https://your-panel.example.com",
"EASYPANEL_TOKEN": "your-api-token"
}
}
}
}
Cursor — reutilizar variables de entorno entre proyectos
En Cursor Settings → Tools & MCPs → Environment Variables, establece:
EASYPANEL_URL=https://your-panel.example.comEASYPANEL_TOKEN=your-api-token
Entonces tu .cursor/mcp.json usa referencias que se aplican automáticamente a cada proyecto:
{
"mcpServers": {
"easypanel-mcp": {
"command": "npx",
"args": ["-y", "easypanel-mcp-server"],
"env": {
"EASYPANEL_URL": "${EASYPANEL_URL}",
"EASYPANEL_TOKEN": "${EASYPANEL_TOKEN}"
}
}
}
}
Variables de entorno
| Variable | Requerida | Valor por defecto | Descripción |
|---|---|---|---|
EASYPANEL_URL | ✅ | — | URL del panel, sin barra final (p. ej. https://panel.example.com) |
EASYPANEL_TOKEN | ✅ | — | Token de API (Easypanel → Settings → API → Generate Token) |
MCP_ACCESS_MODE | — | full | Establécelo a readonly para bloquear todas las escrituras (herramientas seleccionadas y easypanel_raw). Las lecturas siguen disponibles — ideal para conectarse a un panel de producción solo para inspección. |
EASYPANEL_API_FLAVOR | — | (automático) | Fuerza la generación de API del panel en lugar de la autodetección: trpc (≤ 2.30), rpc (2.31–2.32) o public (≥ 2.33). Aliases: legacy / modern. Déjalo sin establecer a menos que tengas un motivo — una fijación obsoleta de rpc mantiene un panel 2.33 en la API interna. |
EASYPANEL_RAW_DISABLED | — | (habilitado) | Establécelo a 1 para deshabilitar por completo la vía de escape easypanel_raw. Recomendado cuando el MCP está expuesto a contenido no confiable (riesgo de inyección de prompts), ya que las lecturas de easypanel_raw pueden devolver secretos y no están cubiertas por el modo de solo lectura. |
Añadir contexto a un proyecto
Coloca esto en el CLAUDE.md de tu proyecto para que Claude sepa qué proyecto y servicio de Easypanel debe operar por defecto:
## Easypanel
Project: `my-project` | Service: `my-api` | Branch: `main`
Repo: `owner/repo`
No es necesario copiar carpetas — una única instalación del MCP sirve para todos tus proyectos.
Casos de uso
"Despliega mi aplicación" — Claude lista los proyectos, inspecciona el servicio actual, dispara
deploy_service, y luego observalist_actionshasta que se complete.
"¿Por qué mi servicio está caído?" — Claude llama a
get_service_error,get_service_logsyget_build_logs, y puedeexec_in_containerpara inspeccionar archivos/variables de entorno en vivo.
"Añade DATABASE_URL a staging" — Claude lee las variables de entorno actuales con
get_env_vars, añade solo la nueva clave conset_env_var(nunca borra otras), y te recuerda redesplegar.
"Dale a este servicio 512MB y medio núcleo" — Claude llama a
set_service_resources(lee los límites actuales y fusiona tu cambio) y te recuerda reiniciar.
"Persiste /app/data y expón el puerto 5432" — Claude llama a
create_mount(volumen con nombre) ycreate_port, ambos aplicados en el siguiente despliegue.
"Mi disco está lleno" — Claude ejecuta
get_storage_stats, luegocleanup_docker_imagesoprune_docker(con confirmación) para recuperar espacio.
"Muéstrame la configuración del panel de Traefik" — para cualquier cosa sin herramienta dedicada, Claude usa
easypanel_rawpara llamar directamente al procedimiento.
Herramientas disponibles (57)
| Categoría | Herramientas |
|---|---|
| Proyectos | list_projects, get_project, create_project, delete_project ⚠️ |
| Servicios | inspect_service, create_service, rename_service ⚠️, destroy_service ⚠️, deploy_service, start_service, stop_service ⚠️, restart_service, get_service_error, get_exposed_ports, get_service_notes, set_service_notes, set_service_resources |
| Despliegue / GitHub | set_source_github, set_source_image, enable_github_deploy, disable_github_deploy, list_actions, get_action |
| Variables de entorno | get_env_vars, set_env_var, delete_env_var ⚠️ |
| Registros | get_service_logs, get_build_logs, get_system_stats |
| Contenedores | list_containers, exec_in_container ⚠️, get_docker_events |
| Dominios | list_domains, add_domain, remove_domain ⚠️, set_primary_domain |
| Bases de datos | create_database, inspect_database, destroy_database ⚠️ |
| Volúmenes / Montajes | list_mounts, create_mount ⚠️ |
| Puertos | list_ports, create_port ⚠️ |
| Compose | create_compose, inspect_compose, deploy_compose |
| Monitorización | get_docker_stats, get_storage_stats, get_service_stats |
| Mantenimiento | prune_docker ⚠️, cleanup_docker_images |
| Servidor / Infraestructura | list_users, list_certificates, list_nodes, restart_panel ⚠️, reboot_server ⚠️ |
| Acceso directo | easypanel_raw ⚠️ |
⚠️ = requiere confirm: "CONFIRMO". Para exec_in_container, create_mount, create_port y easypanel_raw la confirmación es condicional (solo para comandos destructivos, montajes de bind de rutas sensibles del host, puertos privilegiados < 1024 y escrituras, respectivamente).
Las descripciones completas de las herramientas con parámetros están en llms.txt. Para la API subyacente (todas las generaciones), consulta docs/easypanel-api.md.
easypanel_raw — alcanza cualquiera de las ~375 operaciones
Cubrir cada operación de Easypanel con una herramienta tipada no es práctico, así que cualquier cosa sin herramienta dedicada es accesible directamente:
// read (default) — flat name, as documented in your panel's /api/openapi.json
{ "procedure": "listCertificates" }
{ "procedure": "getPanelDomain" }
{ "procedure": "listVolumeBackups", "input": { "projectName": "app", "serviceName": "api" } }
// the old dot notation still works and is translated
{ "procedure": "certificates.listCertificates" }
// write — requires isMutation:true AND confirm:"CONFIRMO"
{ "procedure": "setLogoSettings", "input": { /* ... */ },
"isMutation": true, "confirm": "CONFIRMO" }
Áreas solo accesibles mediante easypanel_raw: Traefik, branding, Cloudflare Tunnel, Box, middlewares, notificaciones, copias de seguridad de volúmenes/bases de datos, WordPress, proveedores de almacenamiento, constructores de Docker, claves Git, gestión de clústeres y actualizaciones. Para descubrir nombres, lee GET <your-panel>/api/openapi.json.
El cliente clasifica cada operación contra la especificación OpenAPI del propio panel, con cierre ante fallo: una lectura solo se ejecuta si la especificación indica que es una lectura, de modo que las escrituras no pueden colarse más allá del modo readonly ni de la barrera de confirmación — y lo inverso también se detecta (llamar a una lectura con isMutation:true se rechaza con un mensaje claro). En 2.33+ esa clasificación es exacta, ya que la API pública declara GET para lecturas y POST para escrituras. En 2.31 es el método HTTP documentado; en 2.32, donde la especificación es solo-POST y no lleva tal marcador, el cliente recurre a la convención de nombres del panel (get/list/inspect/check/query/search = lectura, cualquier otra cosa = escritura), restringido a las operaciones presentes en la especificación.
Una excepción deliberada: en 2.33+ el panel valida los parámetros de consulta sin coerción de tipos, por lo que
?limit=5llega como la cadena"5"y es rechazado. Siempre que una entrada lleve un valor no-cadena, el cliente enruta esa lectura a través del transporte interno/api/rpc(que envía JSON en el cuerpo) y registra el motivo en stderr. La clasificación lectura/escritura proviene primero de la especificación, por lo que la protección no se ve afectada.
Funciones de seguridad
Banner de contexto
Cada respuesta que toca un proyecto/servicio específico comienza con:
[Contexto ativo: projeto="my-project" | serviço="my-api"]
Claude siempre sabe qué está modificando antes de realizar cualquier acción.
Barrera de confirmación
Las acciones destructivas o que impactan la producción devuelven BLOQUEADO hasta que reciben confirm: "CONFIRMO":
{
"status": "BLOQUEADO",
"acao": "stop_service",
"alvo": "serviço \"api\" (usuários perderão acesso)",
"instrucao": "Para confirmar, passe o parâmetro: confirm: \"CONFIRMO\"",
"aviso": "⚠️ Esta ação pode ser IRREVERSÍVEL. Confirme apenas se tiver certeza."
}
Esto protege la eliminación de proyectos/servicios, detener/renombrar, eliminación de variables de entorno/dominios, destrucción de bases de datos, las operaciones globales de servidor (prune_docker, restart_panel, reboot_server) y — condicionalmente — comandos peligrosos de contenedor, montajes de bind sensibles, puertos privilegiados y mutaciones directas.
Modo de solo lectura
Establece MCP_ACCESS_MODE=readonly para bloquear toda escritura en el origen (client.mutate), cubriendo tanto las herramientas curadas como easypanel_raw. Las lecturas siguen disponibles — perfecto para un panel de producción que solo quieres inspeccionar.
Controles de escape directo
easypanel_raw valida el nombre de la operación (plano o namespace.procedure, sin inyección de rutas/consultas), requiere que input sea un objeto (≤ 50KB), y exige CONFIRMO para cualquier mutación. Establece EASYPANEL_RAW_DISABLED=1 para desactivarlo por completo.
Redacción de secretos
list_users elimina apiToken, twoFactorSecret y los campos de contraseña antes de devolverlos — solo id, email, admin, twoFactorEnabled y createdAt llegan al modelo.
Variables de entorno seguras (leer-modificar-escribir)
set_env_var y delete_env_var leen el estado actual, aplican solo el cambio solicitado y lo escriben de vuelta. La API de Easypanel reemplaza toda la cadena de entorno en cada actualización — sin esta protección es fácil borrar accidentalmente todas las variables de una vez.
Enmascaramiento de valores sensibles
get_env_vars enmascara valores cuya clave coincide con *SECRET*, *PASSWORD*, *TOKEN*, *KEY* por defecto. Pasa include_values: true para revelarlos.
El token nunca se filtra
Los errores HTTP y las fallas de WebSocket se registran en stderr y se muestran al modelo como un mensaje genérico — el token de portador (enviado en la cadena de consulta de WebSocket, como exige Easypanel) nunca llega al contexto del modelo.
Validación de entrada
projectName / serviceName se validan contra ^[a-z0-9][a-z0-9_-]*$ antes de usarse para construir un nombre de servicio Docker o una consulta WebSocket (defensa en profundidad contra confusión de objetivos / inyección de parámetros). Los puertos se validan como enteros 1–65535; los valores de recursos deben ser números positivos.
Skill complementario /ep
Instala el skill de flujo de trabajo para operaciones de despliegue guiadas en Claude Code:
mkdir -p ~/.claude/skills/ep
cp skill/SKILL.md ~/.claude/skills/ep/SKILL.md
Luego usa /ep para un flujo de despliegue interactivo sin necesidad de recordar nombres de herramientas.
Cómo funciona
El panel de Easypanel se comunica con su backend a través de tRPC (/api/trpc/<router>.<procedure>), no de una API REST pública. Este servidor usa los mismos endpoints:
- Las lecturas son consultas tRPC; las escrituras son mutaciones tRPC — consulta
docs/easypanel-api.md. - Registros en vivo, ejecución de contenedores y eventos de Docker usan los canales WebSocket del panel (
/ws/serviceLogs,/ws/containerShell,/ws/dockerEvents) — los mismos que usa la interfaz — por lo que funcionan sin los Advanced Logs (Loki) con licencia. - Algunos esquemas de entrada (montajes, puertos, recursos) se validaron contra una instancia real de Easypanel y están documentados en la referencia de la API.
Limitaciones conocidas
- Tipos de servicio WordPress / Box — no se exponen como herramientas dedicadas; accede a ellos mediante
easypanel_raw(p. ej.inspectWordPressService,createBoxService). - Las lecturas de
easypanel_rawomiten el modo de solo lectura — el modo de solo lectura bloquea solo las escrituras. Una lectura directa puede devolver datos sensibles; usaEASYPANEL_RAW_DISABLED=1en entornos no confiables. - Herramientas de clúster —
list_nodesdevuelve solo el nodo local en configuraciones de un solo servidor (sin clúster Swarm). - Los eventos de Docker son solo en tiempo real (sin historial) — un servidor inactivo puede devolver una ventana vacía.
Pruebas sin Claude
npx @modelcontextprotocol/inspector dist/index.js
Abre una interfaz de navegador donde puedes llamar a cualquier herramienta manualmente e inspeccionar la respuesta.
Comparación con paquetes similares
| Característica | easypanel-mcp-server | easypanel-mcp (sitp2k) |
|---|---|---|
| Herramientas curadas | 57 | ~15 |
| Acceso directo a las ~375 operaciones de la API | ✅ (easypanel_raw) | ❌ |
| Método de autenticación | Token de portador | Email + contraseña |
| Protección de confirmación | ✅ | ❌ |
| Modo de solo lectura | ✅ | ❌ |
| Ejecución de contenedores + registros en vivo (WebSocket) | ✅ | ❌ |
| Volúmenes / puertos / compose / recursos | ✅ | ❌ |
| Mantenimiento del servidor (prune / reinicio) | ✅ | ❌ |
| Actualización segura de entorno (leer-modificar-escribir) | ✅ | ❌ |
| Redacción de secretos y enmascaramiento de valores | ✅ | ❌ |
| Skill complementario de Claude | ✅ | ❌ |
| Limitaciones conocidas documentadas | ✅ | ❌ |
🤝 Contribuciones
¡Las contribuciones son bienvenidas! Consulta CONTRIBUTING.md para saber cómo añadir herramientas, reportar errores y abrir PRs.
👤 Autor
Creado por Helbert Paranhos de Strat Academy.
Si este proyecto te fue útil, considera darle una ⭐ y seguir a Strat Academy para más contenido sobre automatización con IA.
📄 Licencia
MIT © Helbert Paranhos / Strat Academy
Consulta LICENSE para más detalles.