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.
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.
- 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
- Node.js 20+ and npm
- A Proxmox VE server and an API token (see API Token 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-proxmoxThe 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:
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".
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 <- environment file goes here
└── mcp-proxmox/
└── index.js <- loads ../.env from here
# /home/user/.env
PROXMOX_HOST=your-proxmox-ip-or-hostname
PROXMOX_USER=root@pam
PROXMOX_TOKEN_NAME=mcp-server
PROXMOX_TOKEN_VALUE=your-token-secret
PROXMOX_ALLOW_ELEVATED=false- Proxmox web UI -> Datacenter -> Permissions -> API Tokens -> Add
- Pick a user (e.g.
root@pam) and a Token ID (e.g.mcp-server) - Copy the secret immediately — it is shown only once
- Use the Token ID as
PROXMOX_TOKEN_NAMEand the secret asPROXMOX_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.
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.
| 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 |
| 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.
proxmox_generate_terraform reads the live configuration of existing VMs and containers and emits HCL for the bpg/proxmox 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 nodevmid— export a single VM/containertype—qemu,lxc, orall(default)include_provider— includeterraform {}/provider {}scaffolding (defaulttrue)
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 guestsOptions 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.
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.
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.
# Unit 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 for workflow test details.
npm 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.jsContinuous integration runs npm test on Node 20 and 22 via GitHub Actions (.github/workflows/ci.yml).
- TLS verification defaults to off so the server works with Proxmox's self-signed certificate out of the box. Set
PROXMOX_VERIFY_TLS=truewhen 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, andproxmox_set_cloudinitwork 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 fortype: lxc— use SSH orpct execon the host instead.
- "Could not load .env file" warning — harmless if you pass variables via the MCP client
envblock; otherwise put.envin the parent directory of the repo (ls ../.envfrom insidemcp-proxmox). - Connection refused / timeout — check
PROXMOX_HOST,PROXMOX_PORT(default 8006), and firewall rules. - 401 Unauthorized — check
PROXMOX_USERformat (root@pam),PROXMOX_TOKEN_NAME, and that the secret inPROXMOX_TOKEN_VALUEis complete. - "Requires Elevated Permissions" — set
PROXMOX_ALLOW_ELEVATED=trueand 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.
MIT — see LICENSE.