Proxmox MCP Server
Provides tools for managing Proxmox Virtual Environment, including VMs, containers, storage, nodes, clusters, and tasks via the Proxmox API.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
✨ Highlights
🧑🚀 Ask for a machine, get a running one. "Spin up a Kali VM" runs
deploy_kali_vm: official image, checksum checked, installed unattended, address reported. Ubuntu, Windows 11 (TPM, Secure Boot, VirtIO) and Datacenter Manager work the same way. More🛰️ Every cluster through one connection. Point it at Proxmox Datacenter Manager and 89 tools reach every Proxmox VE cluster and Backup Server it manages, including cross-cluster migration. More
🧰 The whole API, not a demo. 346 tools across 14 areas: nodes, QEMU VMs, LXC containers, storage and backup, cluster and HA, access control, firewall, disks, Ceph, ACME, SDN, notifications, pools and appliances.
🧭 Workflows built in. Five MCP prompts, such as a cluster health check and a snapshot-change-verify routine, plus live cluster state as MCP resources.
🖥️ Inside your guests too. Run commands through the QEMU guest agent (
vm_agent_exec→vm_agent_exec_status) and read back the exit code and output.🔒 Look-but-don't-touch with one switch.
PROXMOX_READ_ONLY=truerefuses every write inside the server, and the client sees only the 151 read-only tools.🧯 Safe writes, protected guests.
PROXMOX_NO_DESTRUCTIVE=truehides the 73 tools that delete, stop, wipe or roll back.PROXMOX_PROTECTED_VMIDSnames guests no tool may change.⏳ Waits for the slow stuff. Clone, migrate, backup and restore take
wait: true, andwait_for_taskfollows any task to the end, with the log when it fails.🎯 Load only what you use.
PROXMOX_TOOLSETS=nodes,qemu,lxc,storagecuts the tool list from 346 to 127, and the context it costs by more than half. Results come back as compact JSON.🚦 Labelled for safe approval. Every tool carries MCP
readOnlyHintanddestructiveHintannotations, so clients can auto-approve reads and ask before a delete, stop or rollback.🆕 Current protocol, old clients welcome. Built on MCP SDK 2: clients on the stateless 2026-07-28 protocol and on every handshake version back to 2024-11-05 connect. Failed calls are flagged as errors, so clients show them as failures.
🔑 API tokens or passwords. Tokens are recommended; pair them with a
PVEAuditorrole for monitoring.🌐 Local or on the network. Clients spawn it over stdio, or
proxmox-mcp-server-httpserves it over streamable HTTP. Give each client its own token and a role:read,operatororadmin.📜 Every change on the record.
PROXMOX_AUDIT_LOGwrites one JSON line per write call: who, what, the outcome and the task, with secrets redacted.🐳 Runs anywhere. Use
uvfrom a clone, or the multi-arch image onghcr.io.♻️ Long sessions just work. Password logins renew their Proxmox ticket before it expires.
🤝 A2A-ready.
agent-card.jsonlists every tool, Proxmox VE and Datacenter Manager, by skill category, for agent-to-agent discovery.🛡️ Appliances.
deploy_fortigate_vmbuilds a FortiGate-VM from Fortinet's KVM image, with WAN/LAN NICs on the bridges and VLANs you choose.deploy_cloud_vmsbuilds cluster-ready VMs from a cloud image, with your SSH key and a static IP each, ready for k3s-mcp-server'screate_cluster.
Related MCP server: ProxmoxEmCP
💬 Talk to your cluster
Once it's connected, just ask:
"Can you list all VMs in my Proxmox cluster?" "What's the status of VM 100 on node pve1?" "Create a snapshot called 'backup-2025' for VM 100 on pve1." "Show me the storage usage on all nodes." "List all running tasks in the cluster." "Clone VM 9000 to a new VM called web-02 and start it." "Run
df -hinside VM 120 using the guest agent and show me the output." "Make three Ubuntu VMs on pve1 at 192.168.1.181–183 with my SSH key, ready for a K3s cluster."
There are more worked examples in USAGE.md.
🧭 Built-in prompts and resources
The server ships MCP prompts, ready-made workflows your client lists by name. In Claude Code, type / to see them, for example /mcp__proxmox__cluster_health_check.
Prompt | What it does |
| Read-only check of quorum, nodes, guests, failed tasks, HA and Ceph, reported by severity |
| Read-only storage, CPU and memory report with the biggest consumers; takes |
| Snapshot a guest, make your change after your go-ahead, verify it, and offer a rollback; takes |
| Read-only: failed tasks, their logs, grouped by cause with fixes; takes |
| Back up, stop and delete a guest, asking before every change; takes |
Prompts only guide the model. Every step is still an ordinary tool call, so roles, read-only mode and protected guests apply as usual.
MCP resources let a client attach live cluster state as context without spending tool calls:
Resource | Contents |
| Quorum and node membership |
| Every node, VM, container and storage with live usage |
| Recent tasks, with status |
| Nodes with CPU, memory and uptime |
| Storage definitions |
| One node in detail |
| One guest's configuration |
Each resource is a single read, so resources work in read-only mode and for every role.
⚙️ How it works
Your MCP client (Claude Desktop, Claude Code, or anything that speaks MCP) starts the server and talks to it over stdio. Or you run it as a service and clients connect over streamable HTTP.
PROXMOX_TOOLSETSdecides which API areas the server loads, and so which tools the client sees. Each tool is labelled read-only or destructive.The server (Python,
httpx, the MCP SDK) turns each tool call into a request to the Proxmox VE REST API over HTTPS on port 8006, authenticated with an API token or a password.Read-only mode hides the write tools and is also checked in the server's HTTP client, so a refused write never leaves your machine.
🧰 346 tools, 14 areas
Area | Tools | Highlights |
Nodes | 38 | Status, config, DNS/hosts/time, network interfaces, services, APT updates, syslog, power |
QEMU VMs | 46 | Lifecycle, create/clone/delete, config, snapshots, migration, disk resize/move, RRD metrics, guest agent ( |
LXC containers | 28 | Lifecycle, create/clone/delete, config, snapshots, migration, resize |
Storage & backup | 14 | Storage definitions, content and volumes, URL downloads, |
Cluster | 37 | Status, resources, options, log, tasks, HA resources/groups, replication, backup jobs |
Access control | 33 | Users, API tokens, groups, roles, ACLs, realms |
Firewall | 31 | Cluster and node rules, security groups, aliases, IP sets, macros, logs (per-VM and per-container rules are in the guest modules) |
Disks | 17 | SMART, wipe, GPT init, LVM, LVM-thin, ZFS, directory storage |
Ceph | 33 | Status, OSDs, monitors, managers, MDS, pools, flags, CRUSH |
ACME & certificates | 17 | ACME accounts and plugins, node certificate ordering, custom certs |
SDN | 16 | Zones, VNets, subnets, apply |
Notifications | 23 | Gotify, sendmail, SMTP and webhook endpoints, matchers |
Pools | 5 | Resource pool CRUD |
Appliances | 2 |
|
One more tool, wait_for_task, is loaded with every toolset. It waits for any Proxmox task to finish; see Waiting for long tasks.
Tool names follow the Proxmox API: list_*, get_*, create_*, update_*/set_*, delete_*, plus actions such as start_vm, migrate_container or apply_sdn. Each area is one module in proxmox_mcp/tools/. Your MCP client shows every tool with its full input schema, or you can list them all locally:
uv run python -c "from proxmox_mcp.server import ALL_TOOLS; print('\n'.join(sorted(t.name for t in ALL_TOOLS)))"Handy recipes
Task | Tools |
Inventory |
|
VM lifecycle |
|
Disk images |
|
Snapshots |
|
Monitoring |
|
Tasks |
|
Guest agent |
|
Cluster nodes |
|
🚀 Quick start
You need Python 3.10+ with uv, or Docker, and Proxmox VE 6.0 or later.
1. Make an API token. In the Proxmox UI, go to Datacenter → Permissions → API Tokens → Add. For full access, uncheck Privilege Separation so the token inherits your user's permissions. Copy the secret; you won't see it again. The full token ID looks like root@pam!automation.
2. Run the server with one of these:
curl -LsSf https://astral.sh/uv/install.sh | sh # if you don't have uv
git clone https://github.com/ry-ops/proxmox-mcp-server && cd proxmox-mcp-server
./setup.sh # or: uv sync
export PROXMOX_HOST="192.168.1.100"
export PROXMOX_USER="root@pam"
export PROXMOX_TOKEN_NAME="automation"
export PROXMOX_TOKEN_VALUE="your-token-here"
./test-connection.sh # checks connection, auth and permissionsA .env file in the project directory is loaded automatically; see .env.example.
A multi-arch image is published to GitHub Container Registry on every push to main and for each release tag:
docker pull ghcr.io/ry-ops/proxmox-mcp-server:latest # or a version tag, e.g. :2.14.0
docker run -i --rm --env-file .env ghcr.io/ry-ops/proxmox-mcp-server:latestMCP clients talk over stdio, so run the container interactively (-i). docker-compose.yaml does the same using your .env. To serve it over HTTP instead, see Run it over HTTP.
3. Connect your MCP client. For Claude Desktop, edit ~/Library/Application Support/Claude/claude_desktop_config.json on macOS, or %APPDATA%/Claude/claude_desktop_config.json on Windows:
{
"mcpServers": {
"proxmox": {
"command": "uv",
"args": ["--directory", "/absolute/path/to/proxmox-mcp-server", "run", "proxmox-mcp-server"],
"env": {
"PROXMOX_HOST": "192.168.1.100",
"PROXMOX_USER": "root@pam",
"PROXMOX_TOKEN_NAME": "automation",
"PROXMOX_TOKEN_VALUE": "your-token-value-here"
}
}
}
}Use the absolute path to your clone.
{
"mcpServers": {
"proxmox": {
"command": "uv",
"args": ["--directory", "/absolute/path/to/proxmox-mcp-server", "run", "proxmox-mcp-server"],
"env": {
"PROXMOX_HOST": "192.168.1.100",
"PROXMOX_USER": "root@pam",
"PROXMOX_PASSWORD": "your-password-here"
}
}
}
}{
"mcpServers": {
"proxmox": {
"command": "docker",
"args": ["run", "-i", "--rm",
"-e", "PROXMOX_HOST", "-e", "PROXMOX_USER", "-e", "PROXMOX_TOKEN_NAME", "-e", "PROXMOX_TOKEN_VALUE",
"ghcr.io/ry-ops/proxmox-mcp-server:latest"],
"env": {
"PROXMOX_HOST": "192.168.1.100",
"PROXMOX_USER": "root@pam",
"PROXMOX_TOKEN_NAME": "automation",
"PROXMOX_TOKEN_VALUE": "your-token-value-here"
}
}
}
}claude mcp add proxmox \
-e PROXMOX_HOST=192.168.1.100 -e PROXMOX_USER=root@pam \
-e PROXMOX_TOKEN_NAME=automation -e PROXMOX_TOKEN_VALUE=your-token-value-here \
-- uv --directory /absolute/path/to/proxmox-mcp-server run proxmox-mcp-serverAdd -e PROXMOX_TOOLSETS=nodes,qemu,lxc,storage to keep the tool list small. For a server you run over HTTP, see Run it over HTTP.
4. Restart your client completely (quit it, don't just close the window), and ask it to list your VMs. More detail in QUICKSTART.md and SETUP.md.
🏢 Several clusters
Run one server per cluster, each under its own name. Every cluster then gets its own credentials, toolsets, safety settings and audit log, and the assistant always knows which cluster a tool acts on, because the tool names carry the server name (mcp__proxmox-lab__start_vm and mcp__proxmox-prod__start_vm).
{
"mcpServers": {
"proxmox-lab": {
"command": "uv",
"args": ["--directory", "/absolute/path/to/proxmox-mcp-server", "run", "proxmox-mcp-server"],
"env": { "PROXMOX_HOST": "10.0.10.5", "PROXMOX_USER": "root@pam",
"PROXMOX_TOKEN_NAME": "automation", "PROXMOX_TOKEN_VALUE": "lab-token" }
},
"proxmox-prod": {
"command": "uv",
"args": ["--directory", "/absolute/path/to/proxmox-mcp-server", "run", "proxmox-mcp-server"],
"env": { "PROXMOX_HOST": "10.0.20.5", "PROXMOX_USER": "mcp@pve",
"PROXMOX_TOKEN_NAME": "readonly", "PROXMOX_TOKEN_VALUE": "prod-token",
"PROXMOX_NO_DESTRUCTIVE": "true", "PROXMOX_PROTECTED_VMIDS": "100-110",
"PROXMOX_TOOLSETS": "nodes,qemu,lxc,storage" }
}
}
}Give each extra cluster only the toolsets it needs, because every server's tools count against the client's context. Over HTTP, run one proxmox-mcp-server-http per cluster on its own port.
🧑🚀 Deploy an OS by asking
Ask for a VM by name and the server does the rest: fetches the official image (checksum verified, cached on storage and reused), builds a small seed ISO with the first-boot settings, creates and starts the VM, waits until its guest agent answers, and reports how to reach it.
Tool | What you get |
| Ubuntu 24.04 LTS from the official cloud image |
| Kali Linux from its official cloud image. It ships as |
| Proxmox Datacenter Manager on a Debian 13 VM, installed by cloud-init from the no-subscription repository; reports |
| Windows 11 installed unattended: q35, UEFI, Secure Boot keys, TPM 2.0, VirtIO disk and network, VirtIO guest tools. Uses a Windows 11 ISO already on storage (Microsoft has no stable download link); installs without a product key, so activation is yours |
| What's cached on the node, and with |
Give an SSH public key, or the tool generates a password and returns it once (the audit log redacts passwords). The seed ISO holds those credentials, so it's deleted as soon as the guest is up. Each tool takes the usual sizing and network inputs (cores, memory, disk_gb, bridge, vlan, a static ip or DHCP) and wait_until_ready / ready_timeout. Windows Setup takes 20 to 40 minutes; with a shorter timeout the tool returns installing and says what to clean up after.
🛰️ Proxmox Datacenter Manager
If you run Proxmox Datacenter Manager (PDM), point the server at it and the pdm toolset loads: 89 tools that reach every Proxmox VE cluster and Proxmox Backup Server PDM manages, through one connection. It can run alongside a direct Proxmox VE connection, or on its own.
Across everything: resources, top consumers, tasks, pending updates and subscriptions for all remotes at once.
Per remote: nodes, guests, configs, snapshots, storage, firewall, tasks and metrics on Proxmox VE remotes; datastores, namespaces, snapshots and tasks on Backup Server remotes; SDN and Ceph.
Actions: start, stop, shut down and resume guests; create, delete, roll back and describe snapshots; migrate within a cluster or to another cluster (
pdm_pve_remote_migrate_guest); stop tasks; refresh updates, task caches and metrics. Actions takewait.
Tools that cover both VMs and containers take type (qemu or lxc). Every input is checked against PDM's own schema before a request is sent.
"env": {
"PDM_HOST": "10.0.0.20",
"PDM_TOKEN_ID": "root@pam!proxmox-mcp",
"PDM_TOKEN_SECRET": "…",
"PDM_CA_BUNDLE": "/path/to/pdm-api.pem",
"PDM_TLS_NAME": "pdm",
"PDM_PROTECTED_GUESTS": "pve01:104,pve01:105"
}Create the token in PDM under Configuration → Access Control → API Tokens, then give it roles under Permissions. PDM tokens start with no permissions, and never get more than their user:
Path | Role | Covers |
| Auditor for read-only, Administrator for actions | Every remote: reads need |
| Auditor |
|
Seven tools reach endpoints PDM 1.1 allows only for root@pam logged in with a password, so with an API token they return 403 whatever its roles: pdm_pve_list_remotes and pdm_pbs_list_remotes (use pdm_list_remotes instead), pdm_metric_collection_status, pdm_collect_metrics, pdm_get_remote_rrddata, and the two EVPN lookups. Their descriptions say so, and when PDM refuses one, the error explains the elevated permissions it needs and what to use instead.
PDM can also protect a guest itself: a NoAccess entry for the token on /resource/<remote>/guest/<vmid> (for example /resource/pve01/guest/104) makes PDM refuse every call about that guest, whatever this server does. For PDM_CA_BUNDLE, copy /etc/proxmox-datacenter-manager/auth/api.pem from the PDM host. Its self-signed certificate names pdm and localhost, not the host's IP, so when PDM_HOST is an IP also set PDM_TLS_NAME=pdm: the certificate is checked against that name while the server connects to the IP.
Protected guests. VMIDs are only unique within a cluster, so PDM tools use PDM_PROTECTED_GUESTS, with the remote in each entry: pve01:104, or *:9000-9010 for every remote. A migration is refused when its source or its target is protected. PROXMOX_PROTECTED_VMIDS doesn't apply to PDM tools. PROXMOX_READ_ONLY, PROXMOX_NO_DESTRUCTIVE, HTTP roles and the audit log apply as usual.
The tools are generated from PDM's published API schema; ROADMAP.md maps all 327 PDM endpoints and what's planned next.
🔧 Configuration
Variable | Required | Default | What it does |
| ✅¹ | Hostname or IP, without scheme or port ( | |
| ✅¹ | e.g. | |
| one of | API token auth (recommended) | |
| one of | Password auth | |
|
| API port | |
|
| Verify the server's TLS certificate against the system's trusted CAs | |
| CA file to verify against instead, e.g. a copy of | ||
|
| Refuse every write and advertise only read tools; see below | |
| all | Comma-separated API areas to load; see below | |
|
| Hide the 73 tools that delete, stop, wipe or roll back; see Safety | |
| Guest IDs and ranges no tool may change, e.g. | ||
|
| Seconds a | |
|
| HTTP entrypoint only: bind address | |
|
| HTTP entrypoint only: port | |
| HTTP entrypoint only: one admin bearer token; a token is required off loopback | ||
| HTTP entrypoint only: several tokens with roles, | ||
| HTTP entrypoint only: the same, one | ||
| File, or | ||
|
| Log read calls too | |
|
| HTTP entrypoint only: allow a non-loopback address with no token | |
| ✅¹ | Proxmox Datacenter Manager hostname or IP; loads the | |
|
| PDM API port | |
| with | PDM API token, | |
| PDM's certificate (or its CA) to verify against | ||
| Name to check PDM's certificate against when | ||
|
| Verify PDM's certificate against the system's trusted CAs instead | |
|
|
¹ Set PROXMOX_HOST (with PROXMOX_USER and a token or password) to talk to Proxmox VE directly, PDM_HOST to go through Datacenter Manager, or both.
🎯 Toolsets: load only what you use
Every tool the server advertises sits in the client's context on every turn, and all 346 schemas come to roughly 44k tokens. Set PROXMOX_TOOLSETS to the areas you need:
PROXMOX_TOOLSETS=nodes,qemu,lxc,storageSetting | Tools | Approx. tokens |
all (default) | 346 | 44k |
| 273 | 35k |
| 164 | 23k |
| 127 | 19k |
| 151 | 13k |
| 47 | 8k |
Every count includes wait_for_task, which loads with any selection.
The names are nodes, qemu, lxc, storage, cluster, access, firewall, disks, ceph, acme, sdn, notifications, pools and appliances. vms and containers work as aliases for qemu and lxc. A misspelt name stops the server at startup with the list of valid ones. Toolsets combine with read-only mode.
🚦 Tool annotations
Each tool tells the client what it does, through standard MCP annotations:
readOnlyHint: trueon the 151 tools that only read.destructiveHint: trueon the 73 that delete, stop, wipe, roll back, restore over, or run commands in a guest.destructiveHint: falseon the other writes, such as create, start or update.
A test sends every tool through a recording client and checks its read-only label against the HTTP methods it sends, so the labels can't drift from the code.
🌐 Run it over HTTP
proxmox-mcp-server-http serves the same tools over MCP streamable HTTP at /mcp, so the server can run as a network service instead of a process each client spawns. PROXMOX_TOOLSETS and PROXMOX_READ_ONLY apply as usual, and /healthz answers without auth for container health checks.
# Local only, no token needed:
uv run proxmox-mcp-server-http # http://127.0.0.1:8811/mcp
# On the network, a token is required:
MCP_HTTP_HOST=0.0.0.0 MCP_AUTH_TOKEN="$(openssl rand -hex 32)" uv run proxmox-mcp-server-httpThe same image runs it in Docker:
docker run -p 8811:8811 --env-file .env -e MCP_HTTP_HOST=0.0.0.0 -e MCP_AUTH_TOKEN \
ghcr.io/ry-ops/proxmox-mcp-server:latest proxmox-mcp-server-httpClients send Authorization: Bearer <token>. For Claude Code:
claude mcp add --transport http proxmox http://pve-mcp.lan:8811/mcp \
--header "Authorization: Bearer $MCP_AUTH_TOKEN"Anyone who can reach this endpoint can use every loaded tool with your Proxmox credentials. So the server binds to 127.0.0.1 by default. It refuses any other address unless a token is set, or you opt out with MCP_HTTP_ALLOW_NO_AUTH=true because a proxy in front of it authenticates clients. The token check runs in constant time. On loopback, DNS-rebinding protection rejects requests whose Host header isn't a local address. Put TLS in front of it, for example with a reverse proxy, when the token crosses a network.
🎭 One token per client, each with a role
Give every client its own token, so you can tell them apart in the audit log and revoke one without the others. Each token carries a role:
Role | Can use |
| only tools that read, like a dashboard or a monitoring agent |
| everything except destructive tools: start, create, clone, snapshot, migrate |
| everything the server loads |
MCP_AUTH_TOKENS="ops:admin:$(openssl rand -hex 32),grafana:read:$(openssl rand -hex 32)"
# or a file with one "name role token" per line, comments with #:
MCP_AUTH_TOKENS_FILE=/run/secrets/proxmox-mcp-tokensEach client sees only the tools its role allows, and a call outside its role is refused before anything reaches Proxmox. Roles only narrow what the server already allows: PROXMOX_READ_ONLY, PROXMOX_NO_DESTRUCTIVE, toolsets and protected guests still apply to everyone. Tokens must be at least 16 characters, and names and tokens must be unique. MCP_AUTH_TOKEN still works, as an admin token named default.
⏳ Waiting for long tasks
Clone, migrate, backup, restore, disk moves, snapshots and power actions start a Proxmox task and return its ID, a UPID. Pass wait: true to any of these 30 tools and the result also carries the task's outcome:
{"data":"UPID:pve2:0003A1B2:…:qmclone:9000:root@pam:","task":{"status":"stopped","exitstatus":"OK","ok":true}}wait_for_task does the same for any UPID, including ones from the cluster task list. A failed task includes the last 20 lines of its log. A wait never fails just because a task is slow. After PROXMOX_WAIT_TIMEOUT seconds, 900 by default, it returns status: "running", and calling wait_for_task again keeps waiting.
🔒 Safety: read-only mode, destructive tools and protected guests
PROXMOX_READ_ONLY=true makes the server look-but-don't-touch. Only GET requests are sent, and every create, update, delete or action tool is refused inside the server before it reaches the network. The client sees only the 151 read-only tools, so it never plans around a tool that would be refused. Three read-style tools send POST requests, so they're hidden too:
vm_agent_ping;get_vm_vnc_proxyandget_vm_spice_proxy, which create console access tickets.
PROXMOX_NO_DESTRUCTIVE=true is the middle ground. It hides the 73 tools labelled destructive: deleting, stopping, wiping, rolling back, restoring over a guest, and running commands inside one. Safe writes such as start, create, clone, snapshot and config changes stay available, so 268 tools remain.
PROXMOX_PROTECTED_VMIDS=100,101,9000-9010 names guests no tool may change, such as your router, DNS or backup server. The server checks every write before sending it: power actions, config changes, snapshots, migration, disk moves, deletion, guest-agent commands, HA changes, and deleting the guest's volumes or backups. Reads always work. Cloning from a protected template, backing it up and opening its console stay allowed, because they leave it as it is. Node-wide and bulk start, stop and migrate actions need an explicit vms list while any guest is protected, since they would otherwise include it. Whole-node shutdown and reboot are not covered.
PROXMOX_AUDIT_LOG=/var/log/proxmox-mcp/audit.jsonl records every write call as one JSON line, whether it succeeded, failed or was refused. Set it to stderr to send the lines to your container logs instead. PROXMOX_AUDIT_READS=true logs reads too.
{"ts":"2026-10-30T21:04:12.418+00:00","who":"ci","via":"http","tool":"clone_vm","args":{"node":"pve2","vmid":9000,"newid":123},"outcome":"ok","upid":"UPID:pve2:…","task_ok":true,"ms":41873}
{"ts":"2026-10-30T21:05:02.007+00:00","who":"grafana","via":"http","tool":"stop_vm","args":{"node":"pve1","vmid":120},"outcome":"refused","error":"stop_vm is not allowed for grafana (role: read)","ms":0}Arguments whose names look secret, such as passwords, tokens, private keys and cloud-init passwords, are written as ***. A failure to write the log is reported on stderr and never fails the tool call.
The rest of the security picture:
For monitoring-only use, combine both locks:
PROXMOX_READ_ONLY=trueand a token with thePVEAuditorrole. The flag stops the server sending writes; the role makes Proxmox refuse them anyway.The token's permissions are the real limit. The server exposes destructive operations: deleting VMs, wiping disks, and running commands inside guests. Whatever the token can do, a connected AI client can ask for. Grant the minimum.
Prefer API tokens over passwords. They can be revoked on their own.
Verify the TLS certificate. Without it, anyone on the network path can read the token. With Proxmox's default self-signed certificates, copy
/etc/pve/pve-root-ca.pemfrom any node and setPROXMOX_CA_BUNDLEto it; with a publicly trusted certificate, setPROXMOX_VERIFY_SSL=true. The server prints a warning at startup when neither is set.Keep credentials out of version control, and restrict network access to the API with firewall rules.
🤝 Agent-to-agent (A2A)
agent-card.json is this server's identity and capability manifest for other agents. It lists all 346 Proxmox VE tools in 14 skill categories, plus the 89 Datacenter Manager tools, each with its name, description, inputs, and read_only and destructive flags. A test fails if it drifts from the tool registry. It also covers authentication requirements and MCP protocol details.
Category | Tools | Category | Tools |
| 38 |
| 17 |
| 46 |
| 33 |
| 28 |
| 17 |
| 14 |
| 16 |
| 38 |
| 23 |
| 33 |
| 5 |
| 31 |
| 2 |
import json
with open('agent-card.json') as f:
agent_card = json.load(f)
print(f"Agent: {agent_card['name']} Version: {agent_card['version']}")
for skill in agent_card['skills']:
print(f"\n{skill['category']}:")
for capability in skill['capabilities']:
print(f" - {capability['name']}: {capability['description']}")from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
server_params = StdioServerParameters(
command="uv",
args=["--directory", "/path/to/proxmox-mcp-server", "run", "proxmox-mcp-server"],
env={
"PROXMOX_HOST": "192.168.1.100",
"PROXMOX_USER": "root@pam",
"PROXMOX_TOKEN_NAME": "automation",
"PROXMOX_TOKEN_VALUE": "your-token-value",
},
)
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
tools = await session.list_tools()
result = await session.call_tool("list_vms", arguments={})
print(result.content)# Snapshot every VM, then hand off to other agents
async def backup_workflow():
vms = await proxmox_agent.call_tool("list_vms", {})
for vm in vms['data']:
await proxmox_agent.call_tool("create_vm_snapshot", {
"node": vm['node'],
"vmid": vm['vmid'],
"snapname": f"backup-{datetime.now():%Y%m%d-%H%M%S}",
})
await storage_agent.call_tool("check_capacity", {})
await notification_agent.call_tool("send_alert", {"message": f"Backup completed: {len(vms['data'])} VMs"})🩺 Troubleshooting
Double-check the credentials and that the user has the permissions you need.
For API tokens, make sure the token hasn't expired or been revoked.
If the token was created with Privilege Separation on, give the token its own permissions, or recreate it with that option off.
Check
PROXMOX_HOST(no scheme, no port) andPROXMOX_PORT.Check you can reach the host:
curl -k https://YOUR_HOST:8006/api2/json/versionIf
PROXMOX_VERIFY_SSL=trueorPROXMOX_CA_BUNDLEis set, the certificate must be valid forPROXMOX_HOST. Proxmox's node certificates name the node's hostname and IP addresses, so use one of those.
The user or token needs privileges for each operation. Common ones: VM.Monitor, VM.Audit, Datastore.Audit, Sys.Audit, VM.PowerMgmt, VM.Snapshot.
The path in the config must be absolute.
The config file must be valid JSON.
Quit Claude Desktop completely and start it again.
Check Claude Desktop's logs. The server logs its authentication method and connection status to stderr, which shows up there.
PROXMOX_TOOLSETSloads only the areas it names. Add the area, or remove the variable to load all of them.PROXMOX_READ_ONLY=truehides every write tool. Set it tofalseto create, change or delete.PROXMOX_NO_DESTRUCTIVE=truehides the delete, stop, wipe and rollback tools."guest … is protected" means
PROXMOX_PROTECTED_VMIDScovers that guest.The server logs how many tools it loaded, and from which toolsets, to stderr at startup.
401 Unauthorized: the client must send
Authorization: Bearer <token>with one of the configured tokens."… is not allowed for NAME (role: read)": that client's token has a role that excludes the tool. Use a token with a wider role.
421 Misdirected Request: on
127.0.0.1the server only accepts local Host headers. Connect to127.0.0.1orlocalhost, or bind to another address with a token."Refusing to serve on 0.0.0.0 without authentication": set
MCP_AUTH_TOKENorMCP_AUTH_TOKENS, orMCP_HTTP_ALLOW_NO_AUTH=trueif a proxy in front authenticates clients.
./test-connection.shIt checks the connection, the API, authentication, permission to list nodes, and access to cluster resources.
🛠️ Development
uv sync # dependencies, including dev tools
uv run proxmox-mcp-server # run the server directly (stdio)
uv run proxmox-mcp-server-http # or over streamable HTTP
uv run pytest # tests
uv run ruff check . && uv run black .proxmox_mcp/
├── server.py stdio entrypoint: tool calls, roles, guards, waits, audit
├── server_http.py streamable-HTTP entrypoint: bearer tokens, loopback default
├── registry.py toolsets, read-only and no-destructive filtering, annotations
├── auth.py HTTP tokens and roles
├── audit.py JSON-lines audit log
├── guards.py protected guests
├── tasks.py waiting for Proxmox tasks
├── prompts.py MCP prompts: built-in workflows
├── resources.py MCP resources: read-only cluster views
├── client.py Proxmox API client: token/password auth, ticket renewal, read-only guard
└── tools/ one module per API area:
nodes, qemu, lxc, storage, cluster, access, firewall,
disks, ceph, acme, sdn, notifications, pools, appliances
tests/ pytest suite, run in CI on Python 3.10–3.13
docs/ the animations on this page; docs/gen/build.py regenerates four of them
agent-card.json A2A agent card
Dockerfile, docker-compose.yaml, setup.sh, test-connection.sh
QUICKSTART.md · SETUP.md · USAGE.md · CHANGELOG.mdDependencies:
mcp(>=2.3, <3): the MCP SDK. It serves both the handshake protocol (2024-11-05 to 2025-11-25) and the stateless 2026-07-28 protocol, so older and newer clients both connect.httpx: the async HTTP client.python-dotenv: loads.env.starletteanduvicorn: serve the HTTP entrypoint.mcpalready depends on both.
🗺️ Roadmap
One server for several clusters without Datacenter Manager, chosen per call (today: one server per cluster, or through PDM)
Progress notifications while waiting for long tasks
What has shipped is in CHANGELOG.md.
🙌 Contributing
Issues and pull requests are welcome: new tools, better error handling, performance, docs, tests and bug fixes.
📚 Learn more
License
MIT. See LICENSE.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
This server cannot be deployed
Maintenance
Related MCP Connectors
A comprehensive Model Context Protocol (MCP) server that enables AI assistants to interact with yo…
Provides capabilities that let LLM agents perform a range of infrastructure management tasks.
A Model Context Protocol server for Wix AI tools
Manage Vozora VPS servers, SSH keys, firewalls, DNS and usage from an AI agent.
Related MCP Servers
- AlicenseCqualityDmaintenanceEnables management of Proxmox VE infrastructure through natural language, providing 120+ tools to control virtual machines, containers, storage, cluster resources, users, and network configurations via the Proxmox API.10022 npmMIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to manage Proxmox VE infrastructure, including VMs, containers, storage, and cluster operations via natural language.MIT
- AlicenseCqualityDmaintenanceEnables management of Proxmox VE environments, including VMs, containers, storage, and cluster operations through natural language.7649 npmMIT
- AlicenseBqualityDmaintenanceEnables AI assistants to manage Proxmox VE infrastructure, including VMs, containers, storage, network, high availability, replication, SDN, and node administration.10018 npmMIT