proxmox-mcp
Provides tools for managing Proxmox VE, including VMs, containers, storage, backups, networking, and snapshots.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@proxmox-mcplist all VMs in the cluster"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
proxmox-mcp
MCP server for full Proxmox VE management - VMs, containers, storage, backups, networking.
Installation
pip install proxmox-mcpRelated MCP server: Proxmox MCP Server
Configuration
Set environment variables:
export PROXMOX_HOST=https://192.168.1.100:8006
export PROXMOX_USER=root@pam
export PROXMOX_TOKEN_NAME=mcp-token
export PROXMOX_TOKEN_VALUE=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
export PROXMOX_VERIFY_SSL=falseUsage with Docker MCP Gateway (Recommended)
The easiest way to use proxmox-mcp is through Docker Desktop's MCP Gateway.
Prerequisites
Docker Desktop with MCP Toolkit enabled (Settings → Features in development → Enable Docker MCP Toolkit)
Installation
# Build the Docker image
docker build -t proxmox-mcp:latest .
# Create a custom catalog (if not already created)
docker mcp catalog create custom-servers
# Add the server to the catalog
docker mcp catalog add custom-servers proxmox-mcp ./proxmox-catalog.yaml
# Enable the server
docker mcp server enable proxmox-mcp
# Set your Proxmox credentials
docker mcp secret set PROXMOX_TOKEN_NAME=your-token-name
docker mcp secret set PROXMOX_TOKEN_VALUE=your-token-valueConfigure the connection
# Set Proxmox configuration
docker mcp config set proxmox.host=https://your-proxmox:8006
docker mcp config set proxmox.user=root@pam
docker mcp config set proxmox.verify_ssl=falseVerify the server is enabled
docker mcp server lsThe server will now be available through the Docker MCP Gateway to any connected client (Claude Code, Cursor, etc.).
Usage with Claude Code (Direct)
Alternatively, add to your Claude MCP config:
{
"mcpServers": {
"proxmox": {
"command": "python",
"args": ["-m", "proxmox_mcp.server"],
"env": {
"PROXMOX_HOST": "https://your-proxmox:8006",
"PROXMOX_USER": "root@pam",
"PROXMOX_TOKEN_NAME": "your-token",
"PROXMOX_TOKEN_VALUE": "your-secret",
"PROXMOX_VERIFY_SSL": "false"
}
}
}
}MCP Conformance
The server declares its real version and instructions during the
initialize handshake (not the SDK's own version), and every one of the 114
tools sets explicit tool annotations
(readOnlyHint/destructiveHint/idempotentHint/openWorldHint) - the
SDK's own defaults for an unset annotation are conservative (destructive and
open-world both default true), so clients like Claude Code would otherwise
treat every read-only pve_*_list/pve_*_status tool as if it were
destructive. Tool-handler exceptions are left to propagate rather than being
caught and returned as a "successful" {"error": ...} result, so the SDK can
turn them into a spec-conformant CallToolResult(isError=True); unknown tool
names raise a protocol-level McpError (INVALID_PARAMS) instead.
Available Tools
114 tools across 10 modules, covering the day-to-day Proxmox VE API surface. Endpoints intentionally left out: Ceph management, SDN, and interactive package upgrades (no clean non-interactive task API for the latter).
Nodes (src/proxmox_mcp/tools/nodes.py)
pve_node_list/pve_node_status- List nodes / get node status (CPU, memory, uptime)pve_node_disk_list/pve_node_disk_smart- Physical disk inventory and SMART healthpve_node_service_list/pve_node_service_state/pve_node_service_control- Inspect and start/stop/restart system services (pveproxy, pvedaemon, etc.)pve_node_apt_list_updates/pve_node_apt_refresh- List/refresh available package updates (no unattended upgrade endpoint exists)pve_node_certificates- List configured TLS certificatespve_node_journal- Read node syslog/journal entriespve_task_status/pve_task_log- Poll a background task (UPID) for progress/completion, or read its log
Virtual Machines (tools/vms.py)
Lifecycle:
pve_vm_list,pve_vm_status,pve_vm_config,pve_vm_config_update,pve_vm_start,pve_vm_stop,pve_vm_force_stop,pve_vm_restart,pve_vm_reset,pve_vm_create,pve_vm_delete,pve_vm_clone,pve_vm_migrate,pve_vm_convert_to_templateDisks:
pve_vm_mount_iso,pve_vm_unmount_iso,pve_vm_import_disk(qcow2/raw/vmdk import),pve_vm_resize_disk,pve_vm_move_disk,pve_vm_unlink_diskGuest agent:
pve_vm_exec,pve_vm_exec_status,pve_vm_get_ipConsole access:
pve_vm_vnc_ticket,pve_vm_spice_ticket
Containers / LXC (tools/containers.py)
pve_container_list,pve_container_status,pve_container_config,pve_container_config_update,pve_container_start,pve_container_stop,pve_container_force_stop,pve_container_create,pve_container_delete,pve_container_clone,pve_container_resize_disk,pve_container_migrate
Storage (tools/storage.py)
pve_storage_list,pve_storage_content,pve_storage_config- Inspect storage pools and their contentspve_storage_create,pve_storage_update,pve_storage_delete- Register/reconfigure/remove a storage pool definitionpve_storage_enable_import,pve_storage_download_url,pve_storage_upload- qcow2/disk-image import support (see below)
Network (tools/network.py)
pve_network_list,pve_network_vm- Inspect node interfaces / a VM's network configpve_network_create,pve_network_update,pve_network_delete,pve_network_apply- Manage bridges/VLANs/bonds (staged until applied)
Backups & Snapshots (tools/backup.py)
pve_backup_list,pve_backup_create- One-off backupspve_snapshot_list,pve_snapshot_create,pve_snapshot_rollback,pve_snapshot_delete- VM/container snapshots
Access Control (tools/access.py)
Users:
pve_access_user_list,pve_access_user_get,pve_access_user_create,pve_access_user_update,pve_access_user_deleteGroups:
pve_access_group_list,pve_access_group_create,pve_access_group_deleteRoles:
pve_access_role_list,pve_access_role_create,pve_access_role_deleteACLs:
pve_access_acl_list,pve_access_acl_updateAPI tokens:
pve_access_token_list,pve_access_token_create,pve_access_token_delete
Resource Pools (tools/pools.py)
pve_pool_list,pve_pool_get,pve_pool_create,pve_pool_update,pve_pool_delete
Cluster (tools/cluster.py)
pve_cluster_status,pve_cluster_resources- Cluster membership/quorum and a flat view of all resourcesHA:
pve_ha_group_list,pve_ha_group_create,pve_ha_group_delete,pve_ha_resource_list,pve_ha_resource_create,pve_ha_resource_update,pve_ha_resource_deleteReplication:
pve_replication_list,pve_replication_create,pve_replication_deleteScheduled backup jobs:
pve_backup_job_list,pve_backup_job_create,pve_backup_job_update,pve_backup_job_delete
Firewall (tools/firewall.py)
Each tool operates at cluster scope by default, node scope if node is given, or a specific VM/container's scope if node+vmid are given:
pve_firewall_rule_list,pve_firewall_rule_create,pve_firewall_rule_update,pve_firewall_rule_deletepve_firewall_options_get,pve_firewall_options_update
Importing a qcow2 Disk Image
Proxmox converts external disk images (qcow2/raw/vmdk/ova) into a VM disk as a
background task, driven by the import-from config option. There is no
single-shot "import a qcow2" API call — it's three steps:
1. Enable import content on a storage
Only file-based storages support it (dir, nfs, cifs, btrfs — not
LVM/ZFS/Ceph):
pve_storage_enable_import storage=local2. Get the qcow2 file onto that storage
Prefer pve_storage_download_url — the Proxmox node fetches the file
server-side, so multi-gigabyte images never pass through the MCP connection:
pve_storage_download_url node=pve storage=local url=https://example.com/debian-12-generic-amd64.qcow2 filename=debian12.qcow2 content=importThis returns a task UPID immediately; the download continues in the
background. Only use pve_storage_upload for small files or when a volume is
mounted directly into the MCP container (the Docker MCP Gateway does not
support volume mounts for custom servers — see project CLAUDE.md).
pve_storage_upload is disabled by default: since its file_path argument
is caller-controlled, it's confined to a directory you explicitly allowlist
via PROXMOX_MCP_UPLOAD_DIR (see .env.example) rather than being able to
read anywhere on the host.
Poll the task until it completes:
pve_task_status node=pve upid=<UPID>
# status: "stopped", exitstatus: "OK" when done3. Import the file as a VM disk
pve_vm_import_disk node=pve vmid=2001 disk=scsi0 target_storage=local-lvm source_volid=local:import/debian12.qcow2Proxmox runs qemu-img convert in a worker task and attaches the result as
scsi0. This also returns a UPID — poll it the same way. On success, set the
VM to boot from it:
pve_vm_config_update node=pve vmid=2001 boot=order=scsi0Notes:
Absolute filesystem paths (
import-from=/path/to/file.qcow2) only work for theroot@pamlogin, not API tokens — always go through storageimportcontent as shown above.The source image is treated as untrusted and validated by Proxmox before conversion; a malformed file or one with an external backing file is rejected.
If the import fails,
pve_task_logshows the worker's output.
Project VM Workflow
Complete workflow for creating and provisioning project VMs:
1. Clone from Template
pve_vm_clone node=pve vmid=101 newid=2001 name=myproject-docker2. Configure Cloud-init
pve_vm_config_update node=pve vmid=2001 ciuser=admin cipassword=password$1 ipconfig0=ip=dhcp3. Start VM
pve_vm_start node=pve vmid=20014. Get IP Address
pve_vm_get_ip node=pve vmid=2001
# Returns: {"interfaces": [{"interface": "eth0", "ip": "10.10.51.125", "prefix": 22}]}5. Execute Commands (Install Software)
# Run a command
pve_vm_exec node=pve vmid=2001 command="bash -c 'apt-get update'"
# Returns: {"pid": 12345}
# Get output
pve_vm_exec_status node=pve vmid=2001 pid=12345
# Returns: {"exited": 1, "exitcode": 0, "out-data": "..."}6. Install Docker Example
pve_vm_exec node=pve vmid=2001 command="bash -c 'curl -fsSL https://get.docker.com | sh'"7. Mount ISO Image
# Mount an ISO to a CD-ROM device
pve_vm_mount_iso node=pve vmid=2001 device=ide2 iso=local:iso/ubuntu-22.04.iso
# Returns: {"status": "mounted", "vmid": 2001, "device": "ide2", "iso": "local:iso/ubuntu-22.04.iso"}
# Mount from NAS storage
pve_vm_mount_iso node=pve vmid=2001 device=scsi1 iso=NAS_ISO:iso/Citrix_CVAD_7.iso
# Eject/unmount the ISO
pve_vm_unmount_iso node=pve vmid=2001 device=ide2
# Returns: {"status": "unmounted", "vmid": 2001, "device": "ide2"}8. Cleanup
pve_vm_stop node=pve vmid=2001
pve_vm_delete node=pve vmid=2001Docker MCP Gateway Setup (Detailed)
Since the default docker-mcp catalog is managed by Docker, fork it first:
# Fork the default catalog
docker mcp catalog fork docker-mcp my-catalog
# Add proxmox-mcp to forked catalog
docker mcp catalog add my-catalog proxmox-mcp ./proxmox-catalog.yaml
# Enable the server
docker mcp server enable proxmox-mcp
# Set all required secrets
docker mcp secret set PROXMOX_HOST=https://10.10.1.10:8006
docker mcp secret set PROXMOX_USER=root@pam
docker mcp secret set PROXMOX_TOKEN_NAME=claude
docker mcp secret set PROXMOX_TOKEN_VALUE=your-token-uuid
docker mcp secret set PROXMOX_VERIFY_SSL=falseUpdate Claude Code MCP config to use the forked catalog:
{
"mcpServers": {
"MCP_DOCKER": {
"command": "docker",
"args": ["mcp", "gateway", "stdio", "--catalog", "my-catalog"]
}
}
}Testing
pip install -e ".[dev]"
pytestThe default suite (tests/test_schema.py, test_client_smoke.py,
test_handlers_smoke.py, test_client_construction.py) never touches a real
Proxmox server - it validates every tool's schema, drives all 114 tools and
all ProxmoxClient methods through a fake API object to catch wiring bugs
(typos, bad argument names, dispatch collisions), and checks host/port/env
parsing. It runs in under a second and is safe to run anywhere.
tests/test_live_smoke.py makes real, read-only calls (list nodes/VMs/
containers/storage, cluster status) against an actual cluster. It's skipped
unless you opt in:
RUN_LIVE_PROXMOX_TESTS=1 pytest tests/test_live_smoke.py -vThis requires PROXMOX_HOST/PROXMOX_USER/PROXMOX_TOKEN_NAME/
PROXMOX_TOKEN_VALUE to be set (.env is picked up automatically). Nothing
in it creates, modifies, or deletes anything.
Security Notes
Authentication model: This server authenticates to Proxmox with a single
API token (PROXMOX_TOKEN_NAME/PROXMOX_TOKEN_VALUE) and passes every tool
call through with whatever privileges that token has - there is no per-tool
authorization inside the MCP server itself.
Trust boundary: Anyone who can invoke this MCP's tools (any client connected to it) can do anything the configured token can do against your Proxmox cluster, including user/ACL management, firewall rule changes, and VM/container/storage lifecycle operations. Treat access to this MCP server as equivalent to holding that Proxmox token directly.
Least privilege: Do not point this at a root@pam token unless you
specifically need node-level operations root@pam alone can grant (e.g. some
absolute-path imports are root@pam-only). For most use, create a dedicated
user, assign only the roles/paths it needs via pve_access_acl_update (or the
Proxmox UI) and issue an API token from that user instead. The access-control
tools in this MCP (pve_access_*) can themselves change permissions - be
deliberate about who can reach them.
Known non-goals: No SSO/MFA, no audit logging beyond what Proxmox itself logs, no rate limiting, and no confirmation prompts before destructive calls (delete/force-stop/firewall changes) - the calling client is responsible for confirming intent before invoking a destructive tool.
Host filesystem access: Every other tool operates only on the Proxmox
cluster via its API - the one exception is pve_storage_upload, whose
file_path argument names a file on the machine running this MCP server.
That's a capability beyond "do what the Proxmox token permits," so it fails
closed: it's disabled until you set PROXMOX_MCP_UPLOAD_DIR, and file_path
is confined to that directory (path traversal outside it is rejected). Only
point that variable at a directory you're comfortable exposing to whatever
can call this MCP's tools.
License
MIT
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/nick-holmquist/proxmox-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server