pve-mcp
Provides tools for interacting with Proxmox VE, including cluster status and resources, guest status/power/config/snapshots, VM creation/cloning/migration/destruction, guest-agent execution, storage, vzdump backups, tasks, optional node SSH, and schema-validated access to Proxmox API endpoints.
Click on "Deploy 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., "@pve-mcp list all VMs and LXC containers with their status"
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.
pve-mcp
MCP server for Proxmox VE. Curated tools for everyday work, plus schema-validated access to every API endpoint.
Schema:
src/pve_mcp/data/pve-api.json.gz, generated from a node's/usr/share/pve-docs/api-viewer/apidoc.js(currently PVE 9.2.24, 680 endpoints). Regenerate after a PVE upgrade:scp root@<node>:/usr/share/pve-docs/api-viewer/apidoc.js schema-src/ && python scripts/gen_schema.py schema-src/apidoc.js <version>Generic:
pve_api_search,pve_api_describe,pve_api(validates params, waits for tasks,dry_run).Curated: cluster status/resources, guest status/power/config/snapshots, create/clone/migrate/destroy, guest-agent exec, storage, vzdump backups, tasks, optional node SSH.
Install in your agent
It works with any MCP client that can start a stdio command. It needs uv. uvx fetches the pinned release, so no clone or virtualenv is needed. Pick your agent below.
Variable | Meaning | Example |
| Proxmox host or IP |
|
| API token id (user@realm!name) |
|
| API token secret |
|
Optional: PVE_ALLOW_WRITES=true (writes), PVE_VERIFY_SSL (true or a CA path), PVE_SSH_ENABLED. Without PVE_ALLOW_WRITES the server is read-only. Create the token under Datacenter → Permissions → API Tokens. For read-only use, give it the PVEAuditor role on /.
A different project uses the name
pve-mcpon PyPI. Install from this repository as shown, not withpip install pve-mcp.
The VS Code buttons ask for each value, keeping secrets out of files. The Cursor button writes placeholders: edit them in ~/.cursor/mcp.json afterwards. Elsewhere, replace the example values.
claude mcp add proxmox -s user -e PVE_HOST=pve.example.lan -e PVE_TOKEN_ID=root@pam!mcp -e PVE_TOKEN_SECRET=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -- uvx --from git+https://github.com/bigbatmanorg/pve-mcp@v0.1.0 pve-mcpSettings → Developer → Edit Config (claude_desktop_config.json):
{
"mcpServers": {
"proxmox": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/bigbatmanorg/pve-mcp@v0.1.0",
"pve-mcp"
],
"env": {
"PVE_HOST": "pve.example.lan",
"PVE_TOKEN_ID": "root@pam!mcp",
"PVE_TOKEN_SECRET": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
}
}
}Use the button above, or add this to .vscode/mcp.json (workspace) or to the user mcp.json (command
MCP: Open User Configuration):
{
"inputs": [
{
"type": "promptString",
"id": "pve_host",
"description": "Proxmox host or IP",
"password": false
},
{
"type": "promptString",
"id": "pve_token_id",
"description": "API token id (user@realm!name)",
"password": false
},
{
"type": "promptString",
"id": "pve_token_secret",
"description": "API token secret",
"password": true
}
],
"servers": {
"proxmox": {
"type": "stdio",
"command": "uvx",
"args": [
"--from",
"git+https://github.com/bigbatmanorg/pve-mcp@v0.1.0",
"pve-mcp"
],
"env": {
"PVE_HOST": "${input:pve_host}",
"PVE_TOKEN_ID": "${input:pve_token_id}",
"PVE_TOKEN_SECRET": "${input:pve_token_secret}"
}
}
}
}Use the button above, or add this to ~/.cursor/mcp.json (global) or .cursor/mcp.json (project):
{
"mcpServers": {
"proxmox": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/bigbatmanorg/pve-mcp@v0.1.0",
"pve-mcp"
],
"env": {
"PVE_HOST": "pve.example.lan",
"PVE_TOKEN_ID": "root@pam!mcp",
"PVE_TOKEN_SECRET": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
}
}
}Add this to ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"proxmox": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/bigbatmanorg/pve-mcp@v0.1.0",
"pve-mcp"
],
"env": {
"PVE_HOST": "pve.example.lan",
"PVE_TOKEN_ID": "root@pam!mcp",
"PVE_TOKEN_SECRET": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
}
}
}codex mcp add proxmox --env PVE_HOST=pve.example.lan --env PVE_TOKEN_ID=root@pam!mcp --env PVE_TOKEN_SECRET=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -- uvx --from git+https://github.com/bigbatmanorg/pve-mcp@v0.1.0 pve-mcpOr add this to ~/.codex/config.toml:
[mcp_servers.proxmox]
command = "uvx"
args = ["--from", "git+https://github.com/bigbatmanorg/pve-mcp@v0.1.0", "pve-mcp"]
env = { PVE_HOST = "pve.example.lan", PVE_TOKEN_ID = "root@pam!mcp", PVE_TOKEN_SECRET = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" }Add this to ~/.gemini/settings.json (or to .gemini/settings.json in a project):
{
"mcpServers": {
"proxmox": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/bigbatmanorg/pve-mcp@v0.1.0",
"pve-mcp"
],
"env": {
"PVE_HOST": "pve.example.lan",
"PVE_TOKEN_ID": "root@pam!mcp",
"PVE_TOKEN_SECRET": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
}
}
}Deep Agents CLI: add this to ~/.deepagents/.mcp.json (all projects) or to .mcp.json in a project. ${VAR} values are read from your shell or ~/.deepagents/.env, so secrets stay out of the file.
{
"mcpServers": {
"proxmox": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/bigbatmanorg/pve-mcp@v0.1.0",
"pve-mcp"
],
"env": {
"PVE_HOST": "${PVE_HOST}",
"PVE_TOKEN_ID": "${PVE_TOKEN_ID}",
"PVE_TOKEN_SECRET": "${PVE_TOKEN_SECRET}"
}
}
}
}Python library (pip install deepagents langchain-mcp-adapters):
import asyncio
import os
from deepagents import create_deep_agent
from langchain_mcp_adapters.client import MultiServerMCPClient
client = MultiServerMCPClient({
"proxmox": {
"transport": "stdio",
"command": "uvx",
"args": ["--from", "git+https://github.com/bigbatmanorg/pve-mcp@v0.1.0", "pve-mcp"],
"env": {
"PVE_HOST": os.environ["PVE_HOST"],
"PVE_TOKEN_ID": os.environ["PVE_TOKEN_ID"],
"PVE_TOKEN_SECRET": os.environ["PVE_TOKEN_SECRET"],
},
}
})
async def main():
tools = await client.get_tools()
agent = create_deep_agent(model="anthropic:claude-sonnet-5-5", tools=tools)
result = await agent.ainvoke({"messages": [{"role": "user", "content": "What can you do?"}]})
print(result["messages"][-1].content)
asyncio.run(main())Save this as agent.yaml, then run docker agent run agent.yaml:
agents:
root:
model: anthropic/claude-sonnet-5-5
description: Assistant with the proxmox MCP tools
instruction: Use the proxmox tools to answer the user's requests.
toolsets:
- type: mcp
command: uvx
args:
- "--from"
- "git+https://github.com/bigbatmanorg/pve-mcp@v0.1.0"
- "pve-mcp"
env:
PVE_HOST: "pve.example.lan"
PVE_TOKEN_ID: "root@pam!mcp"
PVE_TOKEN_SECRET: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"Add this to ~/.hermes/config.yaml, then run /reload-mcp in a chat:
mcp_servers:
proxmox:
command: uvx
args: ["--from", "git+https://github.com/bigbatmanorg/pve-mcp@v0.1.0", "pve-mcp"]
env:
PVE_HOST: "pve.example.lan"
PVE_TOKEN_ID: "root@pam!mcp"
PVE_TOKEN_SECRET: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"MCP Servers → Configure (cline_mcp_settings.json / mcp_settings.json):
{
"mcpServers": {
"proxmox": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/bigbatmanorg/pve-mcp@v0.1.0",
"pve-mcp"
],
"env": {
"PVE_HOST": "pve.example.lan",
"PVE_TOKEN_ID": "root@pam!mcp",
"PVE_TOKEN_SECRET": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
}
}
}Add this to settings.json:
{
"context_servers": {
"proxmox": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/bigbatmanorg/pve-mcp@v0.1.0",
"pve-mcp"
],
"env": {
"PVE_HOST": "pve.example.lan",
"PVE_TOKEN_ID": "root@pam!mcp",
"PVE_TOKEN_SECRET": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
}
}
}Add this to opencode.json (project) or ~/.config/opencode/opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"proxmox": {
"type": "local",
"command": [
"uvx",
"--from",
"git+https://github.com/bigbatmanorg/pve-mcp@v0.1.0",
"pve-mcp"
],
"environment": {
"PVE_HOST": "pve.example.lan",
"PVE_TOKEN_ID": "root@pam!mcp",
"PVE_TOKEN_SECRET": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
},
"enabled": true
}
}
}Run goose configure → Add Extension → Command-line Extension, with the command uvx --from git+https://github.com/bigbatmanorg/pve-mcp@v0.1.0 pve-mcp. Or add this to
~/.config/goose/config.yaml:
extensions:
proxmox:
type: stdio
enabled: true
cmd: uvx
args: ["--from", "git+https://github.com/bigbatmanorg/pve-mcp@v0.1.0", "pve-mcp"]
envs:
PVE_HOST: "pve.example.lan"
PVE_TOKEN_ID: "root@pam!mcp"
PVE_TOKEN_SECRET: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"Most clients take the standard mcpServers JSON shown for Claude Desktop. Some use servers instead.
To install once instead of fetching on each start:
uv tool install git+https://github.com/bigbatmanorg/pve-mcp@v0.1.0then use "command": "pve-mcp", "args": [].
From a checkout: "command": "uv", "args": ["run", "--directory", "/abs/path/pve-mcp", "pve-mcp"].
Related MCP server: ProxmoxMCP-Plus
Safety
Setting | Effect |
default | read-only: only GET calls are sent |
| POST/PUT allowed |
| also required for DELETE, stop/reset, rollback, node power |
| enables |
Task-returning calls wait for the task and fail with its log if it fails.
Configuration
PVE_HOST, PVE_PORT (8006), PVE_TOKEN_ID (user@realm!name), PVE_TOKEN_SECRET,
PVE_VERIFY_SSL (false, true, or a CA bundle path such as a copy of /etc/pve/pve-root-ca.pem),
PVE_TIMEOUT, PVE_SSH_USER, PVE_SSH_KEY, PVE_SSH_PORT, PVE_NODE_HOSTS (node:addr,...).
Tests
uv run pytest # unit tests (mocked HTTP)
PVE_LAB=1 uv run pytest -m lab # lifecycle tests on the lab onlyLab tests create and delete real objects; run them only against a disposable instance (PVE_LAB=1 with LABPVE_HOST, LABPVE_TOKEN_ID, LABPVE_TOKEN_SECRET).
License
AGPL-3.0-or-later. The bundled schema (src/pve_mcp/data/pve-api.json.gz) is generated from Proxmox VE's pve-docs API viewer data, which is AGPL-3.0 licensed, Copyright Proxmox Server Solutions GmbH.
Available Tools
20 toolspve_agent_execA
Run a command inside a VM through the QEMU guest agent and return exit code and output. command is argv, e.g. ["systemctl", "is-active", "nginx"]. Requires the agent to be installed and enabled.
Inputs: vmid (required), command (required), timeout, input_data. Returns: object
pve_apiB
Call any PVE API endpoint, e.g. pve_api("GET", "/nodes/pve1/qemu/100/config"). Params are validated against the schema first. Task-returning calls are waited for unless wait=false. dry_run=true validates and shows the request without sending it.
Inputs: path (required), method (required), wait, params, +3 more.
pve_api_describeA
Show parameters, return shape and permissions for an endpoint. path may be a template (/nodes/{node}/qemu) or concrete (/nodes/pve1/qemu). verbose=true includes property-string sub-keys.
Inputs: path (required), method, verbose. Returns: object
pve_api_searchB
Search the PVE API schema by words in the path or description (e.g. "firewall rules", "sdn vnet").
Inputs: query (required), limit, method. Returns: object
pve_backupC
Back up guests with vzdump to a storage. Runs one job per node that hosts the guests.
Inputs: vmids (required), storage (required), mode, notes, +2 more. Returns: result
pve_cloneB
Clone a VM or container (templates give linked clones unless full=true). target is the destination node.
Inputs: vmid (required), full, name, newid, +4 more. Returns: object
pve_cluster_statusB
Cluster name, quorum, nodes (online, IP), PVE version, and whether writes are enabled here.
Inputs: no named parameters. Returns: object
pve_create_guestA
Create a VM (type="qemu") or container (type="lxc") on a node. params follow the PVE create API, e.g. VM: {"name": "web", "memory": 2048, "cores": 2, "scsi0": "local-lvm:32", "net0": "virtio,bridge=vmbr0", "ostype": "l26", "scsihw": "virtio-scsi-single"}; CT: {"ostemplate": "local:vztmpl/debian-13...tar.zst", "hostname": "ct1", "rootfs": "local-lvm:8", "net0": "name=eth0,bridge=vmbr0,ip=dhcp"}. Use pve_api_describe("/nodes/{node}/qemu", "POST") for every option. vmid defaults to the next free id.
Inputs: node (required), type (required), params (required), vmid, +3 more. Returns: object
pve_destroy_guestA
Delete a VM or container and its disks. It must be stopped. Needs confirm=true.
Inputs: vmid (required), purge, confirm, timeout, +1 more.
pve_guestB
Status of a VM or container (node and type are found automatically), plus its config and snapshots.
Inputs: vmid (required), include_config. Returns: object
pve_guest_configA
Read a guest's config, or change it: set={"memory": 4096, "net1": "virtio,bridge=vmbr0"}, delete=["ide2"]. pending=true shows changes waiting for a reboot. Pass the digest from a read to refuse the change if someone else edited the config meanwhile.
Inputs: vmid (required), set, delete, digest, +1 more.
pve_guest_powerA
Change a guest's power state and wait for it to finish. stop and reset are hard (need confirm=true); shutdown is a clean ACPI/init shutdown.
Inputs: vmid (required), action (required), wait, confirm, +1 more. Returns: object
pve_migrateA
Migrate a guest to another node. Running VMs migrate live when online=true; containers restart.
Inputs: vmid (required), target (required), online, timeout, +1 more.
pve_next_vmidB
The next free VM/CT id in the cluster.
Inputs: no named parameters. Returns: result
pve_node_sshA
Run a shell command on a node over SSH, for what the API cannot do (pct exec, logs, files). Needs PVE_SSH_ENABLED=true and PVE_ALLOW_WRITES=true, since commands can change the system.
Inputs: node (required), command (required), timeout. Returns: object
pve_resourcesB
Every guest, storage, node or SDN zone in the cluster, with usage figures (cluster/resources).
Inputs: type. Returns: result
pve_snapshotA
List, create, roll back or delete snapshots. rollback and delete need confirm=true. vmstate=true also saves RAM (VMs only).
Inputs: vmid (required), action, confirm, timeout, +3 more.
pve_storageB
Without storage: storage list with usage (per node, or cluster-wide). With storage: its contents, optionally filtered by content type (images, rootdir, iso, vztmpl, backup, snippets, import).
Inputs: node, content, storage.
pve_taskB
Status and log tail of a task by UPID. wait=true blocks until it finishes (up to timeout).
Inputs: upid (required), wait, timeout, log_lines. Returns: object
pve_tasksB
Recent tasks on one node, or across the cluster when node is omitted.
Inputs: node, vmid, limit, running, +1 more. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 20 tools
Most tools target a distinct action (create, clone, migrate, destroy, power, snapshot, backup). There is some overlap in the read paths: pve_guest aggregates status+config+snapshots, which overlaps pve_guest_config and pve_snapshot, and pve_resources overlaps pve_cluster_status and pve_storage. The descriptions do clarify each tool's primary focus, so misselection risk is moderate rather than high.
All names share the pve_ prefix and snake_case, which gives a predictable family. However, the second segment mixes noun-only forms (pve_storage, pve_tasks, pve_guest, pve_snapshot) with verb_noun forms (pve_create_guest, pve_destroy_guest, pve_guest_power), so the grammar is not uniform even though it reads clearly.
20 tools is at the high end of the comfortable range, but the domain (VMs, containers, storage, snapshots, migrations, tasks, schema introspection) legitimately requires this breadth. Each tool maps to a real workflow rather than a trivial variant, so the count is justified though slightly heavy.
Lifecycle coverage is strong: create, clone, migrate, destroy, power, config, snapshot, backup, task inspection, plus a generic pve_api escape hatch and schema search/describe for anything not wrapped. Minor gaps: no dedicated backup restore and no first-class network/SDN/firewall tools (only reachable via pve_api or ssh), which agents can work around but may not discover easily.
Maintenance
Related MCP Connectors
Read-only MCP access to a documented IT fleet: state, changes, posture. 15 tools.
Remote MCP for 1,500+ APIs. Vault-managed credentials; OAuth or API key. Search, load, and execute.
327 dev tools via REST API and MCP. Generate Dockerfiles, schemas, K8s, APIs, and more.
Cloud cost, inventory and governance on AWS/Azure/GCP. Read-only by default, optional scoped writes
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables comprehensive management of Proxmox Virtual Environment through 35 tools for VMs, containers, storage, backups, snapshots, and cluster operations via the Proxmox VE API.26 npm22MIT
- AlicenseNot gradedqualityCmaintenanceEnables comprehensive management of Proxmox virtualization environments, including VM and container lifecycle, snapshots, backups, monitoring, and OpenAPI integration.12MIT
- AlicenseNot gradedqualityCmaintenanceEnables read-only interaction with Proxmox VE API, providing tools to query nodes, guests, storage, firewall, backups, and recent tasks.5MIT
- AlicenseNot gradedqualityBmaintenanceExposes 338 tools for the Proxmox Virtual Environment API, enabling users to inspect and control nodes, QEMU VMs, LXC containers, storage and backups, clustering and HA, users and permissions, firewall rules, disks, Ceph, ACME certificates, SDN, notifications, and resource pools. Includes lifecycle actions, snapshots, migration, metrics, task tracking, and guest-agent command execution, with an optional read-only mode that blocks all writes.MIT