easypanel-mcp-server
MCP Server for Easypanel — control deployments, services, logs and databases from Claude Code, Cursor and Claude Desktop
Documentation
easypanel-mcp-server
> MCP Server for full Easypanel control via Claude Code, Cursor and Claude Desktop.
What is this
easypanel-mcp-server connects Claude Code, Cursor and Claude Desktop directly to your Easypanel instance — a modern Docker-based server control panel — through the Model Context Protocol.
Instead of switching between your editor and the Easypanel dashboard, you control everything from inside Claude: deploy from GitHub, update env vars, read live logs, exec into containers, manage domains, databases, volumes and ports, set resource limits, run Docker maintenance and monitor your server — all in natural language.
It maps the Easypanel API to 57 typed tools across 15 categories, plus a single `easypanel_raw` escape hatch that reaches any of Easypanel's ~375 API operations for everything not covered by a dedicated tool. It speaks all three API generations — the tRPC API of panels ≤ 2.30, the RPC layer of 2.31–2.32, and the public API introduced in Easypanel 2.33 — auto-detecting which one your panel uses. Every destructive action is gated behind an explicit confirmation, every response opens with a context banner so Claude always knows what it is touching, and an optional read-only mode lets you connect safely to a production panel.
📖 API reference: `docs/easypanel-api.md` — architecture, the API generations, confirmed operations mapped tool-by-tool, and how to discover new ones.
Compatibility
Easypanel changed its API twice in quick succession:
- 2.31 replaced the internal tRPC API with an RPC layer (`/api/rpc/*`). On panels ≥ 2.31, every v1.x call that carries parameters fails with `400 Input validation failed`.
- 2.33 shipped a documented public API (`/api/`, GET for reads, POST for writes) and stated that the old internal API *"may change without notice and should not be relied upon"*. v3 targets the public API on those panels.
| Your Easypanel version | Use |
|---|---|
| any (recommended) | `easypanel-mcp-server@latest` (v3.x) — auto-detects the generation, works on all three |
| ≤ 2.30.x only, pinned | `easypanel-mcp-server@legacy` (v1.3.x) — frozen tRPC-only line, last validated against v2.30.1 |
v3 detects the generation with a single probe request on first call (cached) and logs the panel version to stderr. To skip detection, set `EASYPANEL_API_FLAVOR` to `trpc` (≤ 2.30), `rpc` (2.31–2.32) or `public` (≥ 2.33).
> Upgrading from v2? If you pinned `EASYPANEL_API_FLAVOR=rpc` to work around the 2.32 issues, remove it — otherwise the client stays on the internal API that Easypanel now declares unstable.
This MCP vs. Easypanel's built-in MCP
Easypanel 2.33 also ships its own MCP endpoint (`/api/mcp`, connection details next to your API key). It's a thin wrapper over the public API. This server is a different trade-off:
| Easypanel built-in MCP | easypanel-mcp-server | |
|---|---|---|
| Runtime container logs | — | ✅ via `/ws/serviceLogs` (no Loki/licence needed) |
| Exec inside a container | — | ✅ `exec_in_container` with destructive-command gate |
| Live Docker events | — | ✅ `get_docker_events` |
| Read-only mode | — | ✅ `MCP_ACCESS_MODE=readonly` blocks every write at the source |
| Confirmation gate on destructive ops | — | ✅ `confirm: "CONFIRMO"` |
| Secret redaction (`list_users`) | — | ✅ strips `apiToken` / `twoFactorSecret` |
| Env var read-modify-write | — | ✅ never clobbers other variables |
| Connection-string building | — | ✅ `inspect_database` |
| Coverage of every API operation | ✅ | ✅ via `easypanel_raw` |
| Zero install | ✅ | needs npx/node |
Using both at once is fine — they don't conflict.
Prerequisites
- Easypanel instance running and accessible
- API token — generate at Easypanel → Settings → API → Generate Token
- Node.js ≥ 18 and Claude Code, Cursor or Claude Desktop
Quick start
Option A — npx (no install needed)
Add `.mcp.json` to your project root:
{
"mcpServers": {
"easypanel-mcp": {
"command": "npx",
"args": ["-y", "easypanel-mcp-server"],
"env": {
"EASYPANEL_URL": "https://your-panel.example.com",
"EASYPANEL_TOKEN": "your-api-token"
}
}
}
}Option B — local build
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 — reuse env vars across projects
In Cursor Settings → Tools & MCPs → Environment Variables, set:
- `EASYPANEL_URL` = `https://your-panel.example.com`
- `EASYPANEL_TOKEN` = `your-api-token`
Then your `.cursor/mcp.json` uses references that apply automatically to every project:
{
"mcpServers": {
"easypanel-mcp": {
"command": "npx",
"args": ["-y", "easypanel-mcp-server"],
"env": {
"EASYPANEL_URL": "${EASYPANEL_URL}",
"EASYPANEL_TOKEN": "${EASYPANEL_TOKEN}"
}
}
}
}Environment variables
| Variable | Required | Default | Description |
|---|---|---|---|
| `EASYPANEL_URL` | ✅ | — | Panel URL, no trailing slash (e.g. `https://panel.example.com`) |
| `EASYPANEL_TOKEN` | ✅ | — | API token (Easypanel → Settings → API → Generate Token) |
| `MCP_ACCESS_MODE` | — | `full` | Set to `readonly` to block all writes (curated tools and `easypanel_raw`). Reads stay available — ideal for connecting to a production panel for inspection only. |
| `EASYPANEL_API_FLAVOR` | — | _(auto)_ | Force the panel's API generation instead of auto-detecting: `trpc` (≤ 2.30), `rpc` (2.31–2.32) or `public` (≥ 2.33). Aliases: `legacy` / `modern`. Leave unset unless you have a reason — a stale `rpc` pin keeps a 2.33 panel on the internal API. |
| `EASYPANEL_RAW_DISABLED` | — | _(enabled)_ | Set to `1` to fully disable the `easypanel_raw` escape hatch. Recommended when the MCP is exposed to untrusted content (prompt-injection risk), since `easypanel_raw` reads can return secrets and are not covered by read-only mode. |
Adding context to a project
Place this in your project's `CLAUDE.md` so Claude knows which Easypanel project and service it should operate on by default:
## Easypanel
Project: `my-project` | Service: `my-api` | Branch: `main`
Repo: `owner/repo`No folder copying needed — one MCP install serves all your projects.
Use cases
> "Deploy my app" — Claude lists projects, inspects the current service, triggers `deploy_service`, then watches `list_actions` until it completes.
> "Why is my service down?" — Claude calls `get_service_error`, `get_service_logs` and `get_build_logs`, and can `exec_in_container` to inspect files/env live.
> "Add DATABASE_URL to staging" — Claude reads current env vars with `get_env_vars`, adds only the new key with `set_env_var` (never wipes others), and reminds you to redeploy.
> "Give this service 512MB and half a core" — Claude calls `set_service_resources` (reads current limits and merges your change) and reminds you to restart.
> "Persist /app/data and expose port 5432" — Claude calls `create_mount` (named volume) and `create_port`, both applied on the next deploy.
> "My disk is full" — Claude runs `get_storage_stats`, then `cleanup_docker_images` or `prune_docker` (with confirmation) to reclaim space.
> "Show me the Traefik dashboard config" — for anything without a dedicated tool, Claude uses `easypanel_raw` to call the procedure directly.
Available tools (57)
| Category | Tools |
|---|---|
| Projects | `list_projects`, `get_project`, `create_project`, `delete_project` ⚠️ |
| Services | `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` |
| Deploy / GitHub | `set_source_github`, `set_source_image`, `enable_github_deploy`, `disable_github_deploy`, `list_actions`, `get_action` |
| Env Vars | `get_env_vars`, `set_env_var`, `delete_env_var` ⚠️ |
| Logs | `get_service_logs`, `get_build_logs`, `get_system_stats` |
| Containers | `list_containers`, `exec_in_container` ⚠️, `get_docker_events` |
| Domains | `list_domains`, `add_domain`, `remove_domain` ⚠️, `set_primary_domain` |
| Databases | `create_database`, `inspect_database`, `destroy_database` ⚠️ |
| Volumes / Mounts | `list_mounts`, `create_mount` ⚠️ |
| Ports | `list_ports`, `create_port` ⚠️ |
| Compose | `create_compose`, `inspect_compose`, `deploy_compose` |
| Monitoring | `get_docker_stats`, `get_storage_stats`, `get_service_stats` |
| Maintenance | `prune_docker` ⚠️, `cleanup_docker_images` |
| Server / Infra | `list_users`, `list_certificates`, `list_nodes`, `restart_panel` ⚠️, `reboot_server` ⚠️ |
| Raw access | `easypanel_raw` ⚠️ |
⚠️ = requires `confirm: "CONFIRMO"`. For `exec_in_container`, `create_mount`, `create_port` and `easypanel_raw` the confirmation is conditional (only for destructive commands, sensitive host-path bind mounts, privileged ports `/api/openapi.json`.
The client classifies each operation against the panel's own OpenAPI spec, fail-closed: a read only executes if the spec says it's a read, so writes can't sneak past `readonly` mode or the confirmation gate — and the reverse is caught too (calling a read with `isMutation:true` is refused with a clear message). On 2.33+ that classification is exact, since the public API declares GET for reads and POST for writes. On 2.31 it's the documented HTTP method; on 2.32, where the spec is POST-only and carries no such marker, the client falls back to the panel's naming convention (`get`/`list`/`inspect`/`check`/`query`/`search` = read, anything else = write), restricted to operations present in the spec.
> One deliberate exception: on 2.33+ the panel validates query params without type coercion, so `?limit=5` arrives as the string `"5"` and is rejected. Whenever an input carries a non-string value, the client routes that read through the internal `/api/rpc` transport (which sends JSON in the body) and logs the reason to stderr. The read/write classification still comes from the spec first, so the guard is unaffected.
Safety features
Context banner
Every response that touches a specific project/service starts with:
[Contexto ativo: projeto="my-project" | serviço="my-api"]Claude always knows what it is modifying before taking any action.
Confirmation guard
Destructive or production-impacting actions return `BLOQUEADO` until they receive `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."
}This gates project/service deletion, stop/rename, env/domain removal, database destruction, the global server ops (`prune_docker`, `restart_panel`, `reboot_server`), and — conditionally — dangerous container commands, sensitive bind mounts, privileged ports and raw mutations.
Read-only mode
Set `MCP_ACCESS_MODE=readonly` to block every write at the source (`client.mutate`), covering both curated tools and `easypanel_raw`. Reads remain available — perfect for a production panel you only want to inspect.
Raw escape-hatch controls
`easypanel_raw` validates the operation name (flat or `namespace.procedure`, no path/query injection), requires the `input` to be an object (≤ 50KB), and demands `CONFIRMO` for any mutation. Set `EASYPANEL_RAW_DISABLED=1` to turn it off entirely.
Secret redaction
`list_users` strips `apiToken`, `twoFactorSecret` and password fields before returning — only `id`, `email`, `admin`, `twoFactorEnabled` and `createdAt` reach the model.
Safe env vars (read-modify-write)
`set_env_var` and `delete_env_var` read the current state, apply only the requested change, and write back. The Easypanel API replaces the entire env string on every update — without this protection it is easy to accidentally wipe all variables at once.
Sensitive value masking
`get_env_vars` masks values whose key matches `*SECRET*`, `*PASSWORD*`, `*TOKEN*`, `*KEY*` by default. Pass `include_values: true` to reveal.
Token never leaks
HTTP errors and WebSocket failures are logged to stderr and surfaced to the model as a generic message — the bearer token (sent in the WebSocket query string, as Easypanel requires) never reaches the model context.
Input validation
`projectName` / `serviceName` are validated against `^[a-z0-9][a-z0-9_-]*$` before being used to build a Docker service name or WebSocket query (defense-in-depth against target confusion / parameter injection). Ports are validated as integers `1–65535`; resource values must be positive numbers.
Companion skill `/ep`
Install the workflow skill for guided deploy operations in Claude Code:
mkdir -p ~/.claude/skills/ep
cp skill/SKILL.md ~/.claude/skills/ep/SKILL.mdThen use `/ep` for an interactive deploy workflow without needing to remember tool names.
How it works
The Easypanel panel talks to its backend over tRPC (`/api/trpc/.`), not a public REST API. This server uses the same endpoints:
- Reads are tRPC queries; writes are tRPC mutations — see `docs/easypanel-api.md`.
- Live logs, container exec and Docker events use the panel's WebSocket channels (`/ws/serviceLogs`, `/ws/containerShell`, `/ws/dockerEvents`) — the same ones the UI uses — so they work without the licensed Advanced Logs (Loki).
- A few input schemas (mounts, ports, resources) were validated against a live Easypanel and are documented in the API reference.
Known limitations
- WordPress / Box service types — not exposed as dedicated tools; reach them via `easypanel_raw` (e.g. `inspectWordPressService`, `createBoxService`).
- `easypanel_raw` reads bypass read-only mode — read-only blocks writes only. A raw read can return sensitive data; use `EASYPANEL_RAW_DISABLED=1` in untrusted environments.
- Cluster tools — `list_nodes` returns the local node only on single-server setups (no Swarm cluster).
- Docker events are real-time only (no history) — an idle server may return an empty window.
Testing without Claude
npx @modelcontextprotocol/inspector dist/index.jsOpens a browser UI where you can call any tool manually and inspect the response.
Comparison with similar packages
| Feature | easypanel-mcp-server | easypanel-mcp (sitp2k) |
|---|---|---|
| Curated tools | 57 | ~15 |
| Raw access to all ~375 API operations | ✅ (`easypanel_raw`) | ❌ |
| Auth method | Bearer token | Email + password |
| Confirmation guard | ✅ | ❌ |
| Read-only mode | ✅ | ❌ |
| Container exec + live logs (WebSocket) | ✅ | ❌ |
| Volumes / ports / compose / resources | ✅ | ❌ |
| Server maintenance (prune / reboot) | ✅ | ❌ |
| Safe env update (read-modify-write) | ✅ | ❌ |
| Secret redaction & value masking | ✅ | ❌ |
| Companion Claude skill | ✅ | ❌ |
| Known limitations documented | ✅ | ❌ |
🤝 Contributing
Contributions are welcome! See CONTRIBUTING.md for how to add tools, report bugs and open PRs.
👤 Author
Created by **Helbert Paranhos from Strat Academy**.
If this project was useful, consider giving it a ⭐ and following Strat Academy for more AI automation content.
📄 License
MIT © Helbert Paranhos / Strat Academy
See LICENSE for details.
Frequently asked questions
What is easypanel-mcp-server?
easypanel-mcp-server is MCP Server for Easypanel — control deployments, services, logs and databases from Claude Code, Cursor and Claude Desktop
How do I install easypanel-mcp-server?
Open the GitHub repository and follow its README. Most MCP servers are added to your client's MCP config, then called by your agent.
Is easypanel-mcp-server open source?
Yes — it is hosted on GitHub at https://github.com/helbertparanhos/easypanel-mcp-server and has 2 stars.
Related MCP tools
Open-source cross-agent memory layer for coding agents via MCP. Compatible with Claude Code, Codex, Cursor, Windsurf, Gemini CLI, Antigravity, OpenClaw, Hermes Agent, Oh-my-Pi, Pi, Copilot, Kiro, OpenCode, and Trae.
AI Skills, MCP Tools, and CLI for Unity Engine. Full AI develop and test loop. Use cli for quick setup. Efficient token usage, advanced tools. Any C# method may be turned into a tool by a single line. Works with Claude Code, Gemini, Copilot, Cursor and any other absolutely for free.
Cut AI token costs 95%+ on code exploration. The leading MCP server for precise, symbol-level GitHub code retrieval via tree-sitter AST. Works with Claude Code, Cursor & any MCP client. 313B+ tokens saved.
Open-source coding agent memory. Records issues, attempts, fixes and decisions, then warns your agent before it repeats an approach that already failed. Native MCP server for Claude Code, Cursor, Antigravity and Codex. 100% local, no cloud, no telemetry. MIT.
Browser MCP is a Model Context Provider (MCP) server that allows AI applications to control your browser
The go-to web for your AI coding agent — local-first search, fetch, crawl & research over MCP. No API keys, no cloud, $0/query. Public beta.
Run your own MCP server? See who uses it and what to fix.
Measure it with TrackMCP