proxmox-mcps
v0.2.1
Published
MCP server for Proxmox VE — AI-driven QEMU VM and LXC container management
Readme
A Model Context Protocol server that exposes your Proxmox VE cluster to AI assistants (Claude Code, Cursor, Windsurf, …). VMs, containers, storage, network, HA, replication, SDN, node admin — 195 tools over stdio, HTTP+SSE, or streamable HTTP.
User-confirmation gates every destructive call. No silent deletes.
Why
Proxmox has no first-class AI surface. Existing bridges are usually a thin wrapper around one or two endpoints. This server exposes the entire Proxmox API surface — VMs and containers, lifecycle, diagnostics, console access, replication, SDN, HA, cluster jobs, node admin — and wraps every destructive call behind an explicit yes/no prompt the model has to relay to you.
- 195 tools across 9 functional areas (see Tool catalog)
- 3 transports — stdio for Claude Code, streamable HTTP for remote clients, SSE legacy
- Approval-gated destructive ops —
delete_vm,wipe_node_disk,apply_sdn, … wait for you to typeyes - SSRF guard for server-side downloads (URL allowlist, RFC1918 / loopback rejection)
- Pluggable job store — in-memory (default) or SQLite for tracking long-running operations across restarts
- QEMU guest agent — exec inside the guest, fstrim, fsinfo, hostname, OS info, users, network
- SSH-backed
execute_container_command— runspct execon the host to drop into a container
Install
From npm
# One-off run (always picks the latest published version)
npx proxmox-mcps
# Or install globally
npm install -g proxmox-mcps
proxmox-mcpsThe package ships three binaries:
| Binary | Purpose |
| --------------------------------- | -------------------------------------------------------------------- |
| proxmox-mcps | MCP server (the thing you wire into Claude Code / your client) |
| proxmox-mcps-check-config | Validate .env / env vars without starting the server |
| proxmox-mcps-print-tools | Print every registered tool (or just the destructive ones) |
From source
git clone https://github.com/ngocdd/proxmox-mcps.git
cd proxmox-mcps
npm install
cp .env.example .env # then fill in host + API token
npm run check-config # validates your env without starting the server
npm run build # tsc → dist/
npm start # node dist/index.jsConfigure
1. Get a Proxmox API token
Proxmox UI → Datacenter → Permissions → API Tokens → Add
- User:
root@pam - Token ID:
mcp - Uncheck "Privilege Separation" (so the token inherits the user's full privileges)
- Copy the generated UUID — that goes into
PROXMOX_TOKEN_VALUE
2. Wire it into Claude Code
Install at user scope so the same proxmox server follows you across every project:
claude mcp add proxmox --scope user \
-e PROXMOX_HOST=proxmox.example.com \
-e PROXMOX_PORT=8006 \
-e PROXMOX_USER=root@pam \
-e PROXMOX_TOKEN_NAME=mcp \
-e PROXMOX_TOKEN_VALUE=<uuid> \
-e PROXMOX_VERIFY_SSL=false \
-e PROXMOX_DEV_MODE=true \
-- npx -y proxmox-mcps
--scope userwrites to~/.claude.json(or~/.config/claude/on Linux). Use--scope projectto commit a.mcp.jsonentry, or--scope localfor a one-off project-only entry.
Restart Claude Code. Verify with /mcp — you should see proxmox with 195 tools.
Inspect or remove later:
claude mcp list # show all configured servers
claude mcp get proxmox # show env vars + command
claude mcp remove proxmox # delete the entryA drop-in .mcp.json snippet is in .mcp.json.example.
3. Or use any other MCP client
The server speaks the standard MCP protocol over three transports. Pick one via MCP_TRANSPORT:
| Transport | When to use |
| ------------- | -------------------------------------------------------- |
| STDIO | Default. Local clients (Claude Code, Cursor, Windsurf) |
| STREAMABLE | Remote clients, modern MCP-over-HTTP |
| SSE | Legacy SSE-only clients |
For STREAMABLE / SSE the server listens on MCP_HOST:MCP_PORT and exposes /mcp (JSON-RPC) plus /health.
Tool catalog
195 tools, grouped by surface. Run proxmox-mcps-print-tools for the canonical list with risk classifications.
| Group | Count | Highlights |
| ------------------- | :---: | --------------------------------------------------------------------------------------------------------------------------- |
| Cluster status | 1 | get_cluster_status |
| Pools | 5 | CRUD + get_pool |
| HA | 11 | Resources + groups + migrate-on-fail |
| VM (QEMU) | 43 | Lifecycle, config, diagnostics, console (VNC/SPICE/termproxy/monitor), migration, 12 QEMU guest-agent tools |
| Container (LXC) | 27 | Lifecycle, config, diagnostics, SSH-backed execute_container_command, console, migration |
| Snapshots | 4 | list/create/delete/rollback_snapshot |
| Backups | 13 | On-demand + scheduled (vzdump) jobs + restore + prune |
| ISO / templates | 4 | List / download / delete (URL-guarded) |
| Tasks & jobs | 8 | Proxmox task log + long-running MCP job tracking |
| Storage | 5 | list / get / create / update / delete (lvm, zfs, nfs, cifs, pbs, dir, …) |
| Replication | 7 | ZFS replication jobs CRUD + status |
| SDN | 21 | Controllers / zones / vnets / subnets + apply_sdn |
| Node admin | 46 | apt · DNS · hosts · time · config · journal · syslog · pvereport · systemd services · network (bonds/bridges/VLANs/OVS) · disks + ZFS · bulk start/stop/migrate · subscription · certificates |
Risk profile (auto-discovered by print-tools):
| Risk | Count | Behaviour |
| ------------- | :---: | -------------------------------------------------------------------------- |
| low | 79 | Runs immediately. Read-only / inspection tools. |
| medium | 72 | Runs immediately. State-changing but recoverable. |
| high | 19 | Confirmation prompt (returns a yes/no request to the model). |
| destructive | 25 | Confirmation prompt + irreversible — extra warning. |
Audit-only logging for medium-risk tools is independent of the destructive gate. See Safety model.
Safety model
Destructive & high-risk tools
Any tool classified high or destructive does not run immediately. The server returns a confirmation prompt that the model must show you:
⚠️ Confirmation required: 'delete_vm' is DESTRUCTIVE and cannot be undone.
Target: node=pve, vmid=100
Ask the user to reply 'yes' to proceed, or anything else to cancel.
If they confirm, re-invoke this tool with `confirm: true` added to the arguments.You reply "yes", the model calls the same tool again with confirm: true, and the operation proceeds. Every destructive action is gated behind an explicit, visible human yes/no.
To skip the prompt for fully trusted automation:
PROXMOX_DANGEROUSLY_ALLOW_DESTRUCTIVE=trueAudit-only logging for medium-risk tools is independent:
PROXMOX_MCP_AUDIT_ONLY=trueInspect the risk registry at any time:
proxmox-mcps-print-tools # all 195 tools with risk levels
proxmox-mcps-print-tools destructive # only the 25 destructive onesSSRF guard for server-side downloads
download_iso (and any future *_from_url tool) hands the URL to Proxmox, which fetches it server-side. Before that happens, the URL is checked:
- Schemes must be in
PROXMOX_DOWNLOAD_ALLOWED_SCHEMES(default:http,https). - Hosts are resolved and rejected if they fall in RFC1918, RFC4193, loopback, link-local, CGNAT, multicast, or any other reserved range. The Proxmox host cannot be turned into an SSRF proxy against your internal network.
- An optional operator allowlist (
PROXMOX_DOWNLOAD_ALLOWED_HOSTS) supports suffix (.corp.example), bare-IP, or CIDR matches.
See .env.example for the full reference.
VM config allowlist
update_vm_config rejects keys that can attach host PCI/USB devices, override SMBIOS, or change the QEMU machine type — see src/safety/vm-config-allowlist.ts.
Environment reference
All variables can be passed inline, in .env, or as MCP server env vars. See .env.example for the canonical list with defaults.
| Var | Required | Default | Purpose |
| --------------------------------------- | :------: | ------------------------ | ------------------------------------------------------------------ |
| PROXMOX_HOST | ✅ | — | Proxmox API hostname / IP |
| PROXMOX_PORT | | 8006 | Proxmox API port |
| PROXMOX_USER | ✅ | — | API user (user@realm) |
| PROXMOX_TOKEN_NAME | ✅ | — | Token ID |
| PROXMOX_TOKEN_VALUE | ✅ | — | Token secret UUID |
| PROXMOX_VERIFY_SSL | | true | Set false only with self-signed certs |
| PROXMOX_TIMEOUT_MS | | 30000 | Per-request timeout |
| PROXMOX_SERVICE | | PVE | PVE / PMG / PBS |
| PROXMOX_DEV_MODE | | false | Required when PROXMOX_VERIFY_SSL=false |
| PROXMOX_DANGEROUSLY_ALLOW_DESTRUCTIVE | | false | Skip confirmation prompts for high/destructive tools |
| PROXMOX_MCP_AUDIT_ONLY | | false | Audit-log every medium-risk call |
| LOG_LEVEL | | info | debug / info / warn / error |
| LOG_PRETTY | | false | Use pino-pretty (dev only) |
| PROXMOX_MCP_RETRY_MAX | | 3 | Retries on transient API errors |
| PROXMOX_MCP_RETRY_BASE_MS | | 200 | Retry backoff base |
| PROXMOX_MCP_JOB_TTL_HOURS | | 24 | Long-running job retention |
| PROXMOX_MCP_JOB_STORE | | memory | memory or sqlite |
| PROXMOX_MCP_JOB_SQLITE_PATH | | ./proxmox-jobs.sqlite3 | SQLite job store path |
| MCP_TRANSPORT | | STDIO | STDIO / SSE / STREAMABLE |
| MCP_HOST | | 127.0.0.1 | HTTP bind address |
| MCP_PORT | | 8000 | HTTP listen port |
| PROXMOX_SSH_USER | | root | SSH user for pct exec |
| PROXMOX_SSH_PORT | | 22 | SSH port |
| PROXMOX_SSH_KEY_FILE | | — | Path to SSH private key |
| PROXMOX_SSH_PASSWORD | | — | SSH password (prefer key) |
| PROXMOX_SSH_HOST_OVERRIDES | | — | JSON map of node → ssh host |
| PROXMOX_SSH_KNOWN_HOSTS_FILE | | — | Path to known_hosts |
| PROXMOX_SSH_STRICT_HOST_KEY_CHECKING | | true | Reject unknown host keys |
| PROXMOX_DOWNLOAD_ALLOWED_SCHEMES | | http,https | URL schemes for download_iso |
| PROXMOX_DOWNLOAD_ALLOWED_HOSTS | | — | Optional allowlist (suffix / IP / CIDR) |
PROXMOX_VERIFY_SSL=falserequiresPROXMOX_DEV_MODE=true— the server refuses to start otherwise.
Development
git clone https://github.com/ngocdd/proxmox-mcps.git
cd proxmox-mcps
npm install
npm run dev # tsx watch mode
npm run build # tsc → dist/
npm test # 179 unit tests
npm run lint # eslint
npm run format:check # prettierUpdating dependencies
npm outdated # see available updates
npm update # safe patch + minor bumps
npm audit # known CVEs
npm audit fix # safe security fixesNative deps (better-sqlite3, ssh2, …) need install scripts. The repo's .npmrc carries the npm 11+ allowlist. If you add a new native dep, append its name to allow-scripts[] there.
Releasing
- Bump
versioninpackage.json. npm test && npm run build.git tag v<version> && git push --tags.npm publish.
Project layout
src/
index.ts entry point (stdio / streamable / sse)
server.ts MCP server factory
config/ env schema (zod) + typed config
format/ response formatters
jobs/ long-running job tracking (memory + sqlite)
log.ts pino logger
proxmox/ API client + path helpers
safety/ risk registry + approval policy + URL guard
security/ auth + secret redaction
ssh/ SSH client for pct exec
tools/ one file per tool group
vm/ crud, config, diagnostics, migration, console
container/ crud, config, diagnostics, migration, console
cluster, node, storage, tasks, jobs,
snapshot, backup, backup-schedule, iso,
pools, ha, replication, sdn,
node-admin, node-services, node-network, node-disks, node-certs,
storage-admin
cli/ check-config, print-tools
tests/
unit/ vitest unit suite (179 tests)
integration/ end-to-end (gated by PROXMOX_E2E=1)Security
- Destructive calls require an explicit
confirm: truefrom the model after a user-typed "yes". - URL guard rejects private/loopback hosts for server-side downloads.
- VM config allowlist blocks keys that can attach host devices or change machine type.
- Logs redact token UUIDs and SSH passwords.
Found a vulnerability? Please email [email protected] rather than filing a public issue.
Contributing
Issues and PRs welcome. For anything beyond a typo:
- Open an issue first describing the change.
- New tools must register a risk level in
src/safety/risk.ts(low/medium/high/destructive). - New env vars must be added to both
src/config/env.ts(zod schema) and.env.example. - Run
npm test && npm run lint && npm run buildbefore opening the PR.
Acknowledgments
- Built on
@modelcontextprotocol/sdk. - The Proxmox API client uses
axioswithp-retryfor transient errors. - Long-running job tracking uses
better-sqlite3when persistence is enabled. - Container command execution uses
ssh2to shell out topct execon the host.
License
MIT © Proxmox MCP Contributors
