MCP server for Proxmox virtualization management with configurable permissions
Documentation
Proxmox MCP Server (Node.js Edition)
A Node.js-based Model Context Protocol (MCP) server for managing Proxmox VE hypervisors: nodes, QEMU VMs, and LXC containers, with configurable permission levels and Terraform/OpenTofu export.
Credits
Based on the original Python implementation by canvrno/ProxmoxMCP. This Node.js version keeps the same core functionality while adding configurable permission management and Terraform/OpenTofu generation.
Features
- Two permission levels: read-only by default; destructive operations require an explicit opt-in (
PROXMOX_ALLOW_ELEVATED=true) - Node, VM, and container management: status, lifecycle (start/stop/reboot/shutdown/pause), create, clone, resize, delete, migrate, convert-to-template
- Task tracking: read (and optionally wait on) any task by UPID so mutating operations can confirm they actually finished
- Guest agent integration: run commands and read their stdout/exit code, and discover a running VM's real IP addresses
- Snapshots and backups: create, list, rollback, delete
- Disk and network configuration: add, resize, move, and remove disks, mount points, and network interfaces
- Cloud-init, historical metrics (RRD), and read-only observability of pools, HA resources, and firewall rules
- Terraform/OpenTofu export: generate HCL (with
importblocks) from existing VMs and containers to adopt them into IaC without recreation - Structured output: tools return machine-readable
structuredContentalongside the Markdown text, so agents can chain on the data - MCP Resources (
proxmox://nodes,proxmox://vms,proxmox://storage) and Prompts (provisioning, health check, permission diagnosis) - Safety rails: optional TLS verification, node/VMID allowlists, and a protection-flag check that blocks deleting protected guests
- Built on the official MCP SDK
Installation
Prerequisites
- Node.js 20+ and npm
- A Proxmox VE server and an API token (see API Token Setup)
Setup
Clone and install:
git clone https://github.com/gilby125/mcp-proxmox.git
cd mcp-proxmox
npm installOr run without cloning via npx:
PROXMOX_HOST=your-proxmox-ip PROXMOX_TOKEN_VALUE=your-token-secret npx mcp-proxmoxOr with Docker (MCP speaks over stdio, so run attached with -i):
docker build -t mcp-proxmox .
docker run -i --rm \
-e PROXMOX_HOST=your-proxmox-ip \
-e PROXMOX_TOKEN_VALUE=your-token-secret \
mcp-proxmoxConfiguration
The server is configured entirely through environment variables:
| Variable | Required | Default | Description |
|---|---|---|---|
PROXMOX_HOST | yes | — | Proxmox IP or hostname |
PROXMOX_TOKEN_VALUE | yes | — | API token secret |
PROXMOX_USER | no | root@pam | User the token belongs to |
PROXMOX_TOKEN_NAME | no | mcpserver | API token ID |
PROXMOX_PORT | no | 8006 | Proxmox API port |
PROXMOX_ALLOW_ELEVATED | no | false | Set true to enable write/destructive tools |
PROXMOX_VERIFY_TLS | no | false | Set true to verify the Proxmox TLS certificate (use with a CA-signed cert) |
PROXMOX_NODE_ALLOWLIST | no | — | Comma-separated node names the server may touch; empty means no restriction |
PROXMOX_VMID_ALLOWLIST | no | — | Comma-separated VMIDs the server may touch; empty means no restriction |
There are two ways to provide them:
Option 1: env block in your MCP client config (recommended)
For Claude Desktop, edit the config file (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json, Linux: ~/.config/Claude/claude_desktop_config.json, Windows: %APPDATA%\Claude\claude_desktop_config.json):
{
"mcpServers": {
"proxmox": {
"command": "node",
"args": ["/absolute/path/to/mcp-proxmox/index.js"],
"env": {
"PROXMOX_HOST": "your-proxmox-ip",
"PROXMOX_USER": "root@pam",
"PROXMOX_TOKEN_NAME": "mcp-server",
"PROXMOX_TOKEN_VALUE": "your-token-secret",
"PROXMOX_ALLOW_ELEVATED": "false"
}
}
}
}Restart the client after editing, then test by asking: "List my Proxmox VMs".
Option 2: .env file in the parent directory of the installation
The server loads .env from ../.env relative to index.js — i.e. the directory above the cloned repo (kept outside the repo so the secret cannot be committed):
/home/user/
├── .env Datacenter -> Permissions -> API Tokens -> Add
2. Pick a user (e.g. `root@pam`) and a Token ID (e.g. `mcp-server`)
3. Copy the secret immediately — it is shown only once
4. Use the Token ID as `PROXMOX_TOKEN_NAME` and the secret as `PROXMOX_TOKEN_VALUE`
Permissions: basic (read-only) mode works with minimal token permissions. Elevated mode needs roles covering `Sys.Audit`, `VM.Monitor`, `VM.Console`, `VM.Allocate`, `VM.PowerMgmt`, `VM.Snapshot`, `VM.Backup`, `VM.Config.*`, `Datastore.Audit`, `Datastore.Allocate`, depending on which tools you use.
### Permission Levels
Basic mode (`PROXMOX_ALLOW_ELEVATED=false`, the default) allows only read operations: listing nodes, VMs, containers, storage, cluster status, templates, and generating Terraform.
Elevated mode (`PROXMOX_ALLOW_ELEVATED=true`) additionally enables the write tools that can create, modify, and permanently delete VMs, containers, snapshots, backups, disks, and network interfaces, and execute commands inside guests. Only enable it if you understand and accept those risks.
## Available Tools
### Read-only (always available)
| Tool | Description |
|---|---|
| `proxmox_get_nodes` | List cluster nodes with status and resources |
| `proxmox_get_node_status` | Detailed node status (needs elevated + `Sys.Audit`) |
| `proxmox_get_vms` | List VMs/containers, filterable by node and type |
| `proxmox_get_vm_status` | Detailed status for one VM/container |
| `proxmox_get_storage` | List storage pools and usage |
| `proxmox_get_cluster_status` | Cluster health overview |
| `proxmox_list_templates` | List LXC templates on a storage |
| `proxmox_get_next_vmid` | Next free VM/container ID |
| `proxmox_get_vm_config` | Full configuration of a VM/container (cores, memory, disks, network, cloud-init) |
| `proxmox_get_task_status` | Status of a task by UPID; optionally wait until it finishes |
| `proxmox_whoami` | Identity the token authenticates as and its effective permissions |
| `proxmox_get_rrd_data` | Historical CPU/memory/disk/network time series (node or guest) |
| `proxmox_get_pools` | Resource pools and their members |
| `proxmox_get_ha_resources` | High-availability resources and desired state |
| `proxmox_get_firewall_rules` | Firewall rules at cluster / node / guest level |
| `proxmox_generate_terraform` | Generate Terraform/OpenTofu HCL from existing guests |
### Elevated (require `PROXMOX_ALLOW_ELEVATED=true`)
| Category | Tools |
|---|---|
| Create | `proxmox_create_vm`, `proxmox_create_lxc` |
| Lifecycle | `proxmox_start_*`, `proxmox_stop_*`, `proxmox_reboot_*`, `proxmox_shutdown_*`, `proxmox_pause_vm`, `proxmox_resume_vm` |
| Clone / resize / delete | `proxmox_clone_*`, `proxmox_resize_*`, `proxmox_delete_*` |
| Snapshots | `proxmox_create_snapshot_*`, `proxmox_list_snapshots_*`, `proxmox_rollback_snapshot_*`, `proxmox_delete_snapshot_*` |
| Backups | `proxmox_create_backup_*`, `proxmox_list_backups`, `proxmox_restore_backup_*`, `proxmox_delete_backup` |
| Disks | `proxmox_add_disk_vm`, `proxmox_add_mountpoint_lxc`, `proxmox_resize_disk_*`, `proxmox_remove_disk_vm`, `proxmox_remove_mountpoint_lxc`, `proxmox_move_disk_*` |
| Network | `proxmox_add_network_*`, `proxmox_update_network_*`, `proxmox_remove_network_*` |
| Migrate / template | `proxmox_migrate_vm`, `proxmox_convert_to_template` |
| Cloud-init | `proxmox_set_cloudinit` (QEMU) |
| Guest exec / IPs | `proxmox_execute_vm_command`, `proxmox_get_guest_ips` (QEMU via guest agent) |
Tools with a `_*` suffix exist in `_vm` (QEMU) and `_lxc` (container) variants.
`proxmox_execute_vm_command` polls the guest agent by default (`wait: true`) and returns the command's stdout, stderr, and exit code; pass `wait: false` to return only the PID. `proxmox_migrate_vm` and other long-running operations return a task UPID — feed it to `proxmox_get_task_status` (with `wait: true`) to confirm completion.
### Terraform/OpenTofu export
`proxmox_generate_terraform` reads the live configuration of existing VMs and containers and emits HCL for the [bpg/proxmox](https://registry.terraform.io/providers/bpg/proxmox/latest) provider, including `import` blocks so `terraform plan` / `tofu plan` adopts the running guests instead of recreating them.
Arguments (all optional):
- `node` — export only guests on this node
- `vmid` — export a single VM/container
- `type` — `qemu`, `lxc`, or `all` (default)
- `include_provider` — include `terraform {}` / `provider {}` scaffolding (default `true`)
Example prompt: "Generate terraform for VM 100 on node pve1". Then:save the output as main.tf
terraform init # or: tofu init
export TF_VAR_proxmox_api_token='user@realm!tokenid=uuid'
terraform plan # import blocks adopt the existing guests
Options the generator cannot map are listed in comments inside each resource block. LXC resources include an `ignore_changes = [operating_system]` lifecycle block because Proxmox does not record the source template, so the placeholder `template_file_id` must not force replacement of an adopted container.
## Resources and Prompts
Beyond tools, the server exposes MCP **Resources** for browsable, read-only cluster state as JSON — `proxmox://nodes`, `proxmox://vms`, and `proxmox://storage` — and MCP **Prompts** for common workflows: `provision_lxc`, `health_check`, and `diagnose_permissions`.
## Structured output
Every tool returns a Markdown summary for humans plus a `structuredContent` object for programmatic use. For example, `proxmox_get_vms` returns `{ count, vms: [{ vmid, name, type, node, status, cpu, mem, maxmem, ... }] }`. Clients that don't understand `structuredContent` simply render the text.
## TestingUnit tests (no Proxmox server needed)
npm test
Live read-only integration test (needs a configured Proxmox connection)
node test-basic-tools.js
Live workflow tests — CREATES AND DELETES real resources; needs elevated mode
node test-workflows.js [--dry-run] [--interactive] [--workflow=lxc|disk|snapshot]
See [TEST-WORKFLOWS.md](./TEST-WORKFLOWS.md) for workflow test details.
## Developmentnpm install
npm start # run the server
npm run dev # run with auto-reload
npm test # unit tests
Poke the server directly over stdio
echo '{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}' | node index.js
Continuous integration runs `npm test` on Node 20 and 22 via GitHub Actions (`.github/workflows/ci.yml`).
## Known Limitations
- TLS verification defaults to off so the server works with Proxmox's self-signed certificate out of the box. Set `PROXMOX_VERIFY_TLS=true` when you have a CA-signed certificate. Do not point the server at untrusted networks with verification disabled.
- `proxmox_execute_vm_command`, `proxmox_get_guest_ips`, and `proxmox_set_cloudinit` work for QEMU VMs only. The Proxmox HTTP API has no exec/agent endpoint for LXC containers, so command execution returns a clear "not supported" message for `type: lxc` — use SSH or `pct exec` on the host instead.
## Troubleshooting
- "Could not load .env file" warning — harmless if you pass variables via the MCP client `env` block; otherwise put `.env` in the parent directory of the repo (`ls ../.env` from inside `mcp-proxmox`).
- Connection refused / timeout — check `PROXMOX_HOST`, `PROXMOX_PORT` (default 8006), and firewall rules.
- 401 Unauthorized — check `PROXMOX_USER` format (`root@pam`), `PROXMOX_TOKEN_NAME`, and that the secret in `PROXMOX_TOKEN_VALUE` is complete.
- "Requires Elevated Permissions" — set `PROXMOX_ALLOW_ELEVATED=true` and grant the token the roles listed above.
- QEMU command execution fails — install and enable the QEMU guest agent inside the VM (`apt install qemu-guest-agent`), enable it in VM options, and restart the VM.
## License
MIT — see [LICENSE](./LICENSE).Similar MCP
Based on tags & features
Trending MCP
Most active this week