One Rust MCP server for many Proxmox VE clusters — a mechub project
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Topics declared
- ✓Documented (README)
git clone https://github.com/mechubsec/rustproxmoxmcp{
"mcpServers": {
"rustproxmoxmcp": {
"command": "rustproxmoxmcp"
}
}
}MCP Servers overview
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="docs/assets/mechub-mark.svg">
<img src="docs/assets/mechub-mark-light.svg" width="72" alt="mechub mark">
</picture>
</p>
<h1 align="center">rustproxmoxmcp</h1>
<p align="center"><strong>One Rust MCP server for many Proxmox VE clusters</strong><br>
<em>a mechub project — sovereign network-security automation</em></p>
> **Unofficial / community project.** This is an independent community project and does not claim affiliation with or endorsement by Proxmox Server Solutions GmbH. Product names and trademarks are used only to identify the systems with which the software interoperates.
---
## Status: 0.11.0 — the tool surface is complete but for one gap
**50 callable tools**: 31 read, 18 `low`, and `apply_proxmox_change_set` as the
single `destructive` entry point. Seven further names --- `delete_vm`,
`delete_container`, `delete_snapshot`, `delete_backup`, `delete_iso`,
`restore_backup`, `rollback_snapshot` --- are **authorization scopes, not
tools**: a token grants them by name and reaches them through
`plan_proxmox_destroy`. `KNOWN_TOOLS` therefore holds 57 entries.
### What is still missing
- **`execute_vm_command`.** Deliberate. The design spec makes it conditional on
`mecmcp-policy` compiling an allow/deny rule set over the command subject, and
that is not wired. Arbitrary command execution inside every guest is remote
code execution as a tool call; it ships with a policy engine or not at all.
The remaining gap is tracked in #57. Everything else the third-party `proxmox-mcp` offers
has an equivalent here --- see `docs/MIGRATING-FROM-PROXMOX-MCP.md`, which also
lists the arguments that changed shape.
### Change control
Destructive work goes through plan → approve → apply. The plan renders a
server-generated preview and records the action; the approval binds the plan
digest over `(owner, device, expected fingerprint, actions)`; the apply
re-checks the guest's fingerprint and refuses one that moved.
Two things worth stating plainly, because both are easy to assume wrongly:
- **The approval binds the preview.** Since mecmcp 0.23.0 the approval digest
covers the stored preview's hash alongside the plan, so an approver commits to
the exact text they were shown as well as to the operation and its parameters.
The coordinator refuses any later write that swaps or drops that preview once
an approval exists (#56).
This reverses what earlier revisions of this section said. Before 0.23.0 the
preview was stored with its own hash but was not part of the digest, so an
approver committed to the action and the preview was merely rendered from it.
- **`--lab-mode` is the *protection* override, not a blanket waiver.** It
supplies the override a protected guest needs, so on a lab-mode server a
**protected** guest is approved on creation with no second principal, while an
**ordinary** guest still requires one and self-approval is refused. That
inversion surprises people.
`--waivers-file` (default `/etc/proxmoxmcp/waivers.json`, mode 0600,
service-owned) carries time-boxed operator waivers. Both overrides originate
outside the tool call: **there is deliberately no `grant_waiver` tool and no
`force` argument**, because an override a caller can pass is not an override.
- **A waiver lifts protection only, never the second approver.** A matching
waiver lets a plan against a protected guest proceed past the protection
gate; the resulting change set still goes through the normal
plan → approve → apply flow and still needs a distinct human approver (or
`--lab-mode`, which is the one path that also waives approval). The
waiver's reason and ticket are printed in the stored preview so the
approver can see why protection was lifted before deciding whether to
also approve.
#### `waivers.json` schema
```json
{
"version": 1,
"waivers": [
{
"cluster": "pve3",
"vmid": 905,
"until": "2026-12-31T23:59:59Z",
"reason": "decommission per CHG-1234",
"ticket": "CHG-1234",
"ops": ["destroy_guest"],
"principal": "ops-token"
}
]
}
```
- **`ops` is required and non-empty.** A waiver file version 1 entry with no
`ops` field, or an empty list, is refused at load -- the server will not
start with a waiver that covers no operation. This is a breaking,
intentionally fail-closed change from pre-MEC-447 waiver files, which had
no `ops` field at all: re-add every entry with the exact operation(s) it
should cover before upgrading.
- **`principal` is optional.** When set, the waiver only matches that one
token name; when absent, it matches any caller. This names the token that
**plans** the operation, not the one that approves or applies it --
`approve_proxmox_change_set` and `get_proxmox_change_set` evaluate the
waiver against the planner recorded on the change set, because the
two-person rule requires the approver to be a distinct principal from the
planner. A `principal`-bound waiver therefore refuses an apply run by a
caller other than the planner, which is the intended fail-closed outcome,
not a bug.
- **The `op` strings `ops` must name** depend on which path the waiver
covers:
- A destructive operation planned through `plan_proxmox_destroy`: the
`op` argument passed to that call (`destroy_guest`, `delete_snapshot`,
`rollback_snapshot`, `delete_backup`, `delete_iso`, `restore_backup`,
`migrate`, `update_vm_config`).
- A restore that targets a *new* VMID (`restore_backup_new_vmid`): the
fixed string `restore_new_vmid`, naming the archive owner guest the
waiver protects, not the new VMID.
- A service-interrupting `low`-tier tool (for example `stop_vm`,
`stop_container`, `reboot_vm`): the tool's own name.
- An HA rule change planned through `plan_ha_rule_change`: `ha_rule_`
followed by that call's `op` (`ha_rule_create`, `ha_rule_update`,
`ha_rule_delete`).
- A firewall change planned through `plan_firewall_change`: `firewall_`
followed by the object and the operation (`firewall_rule_create`,
`firewall_options_update`, `firewall_ipset_entry_delete`).
A waiver that misspells or omits the operation it was meant for matches
nothing -- the call is refused the same as if no waiver existed.
- **`approve_proxmox_change_set` requires a human approver token.** The
server passes the caller's token `actor_type` through to mecmcp, which
refuses any approval from an `agent` or unattributed (stdio) caller --
only `actor_type: human` can approve. Mint the approver's token with
`rust-proxmoxmcp token add ... --actor-type human`. `actor_type` is a
claim the operator makes at mint time, not something the server proves;
a token tagged `human` but handed to an LLM agent defeats the gate.
### What's implemented
- **Multi-cluster inventory:** One server, many clusters. Each cluster gets its own API token and protection policy.
- **Two-stage authorization:**
1. **Stage 1** (before the catalog call): Bearer token validation, tool and cluster scope checks.
2. **Stage 2** (guest-addressed tools only): Guest resolution, grant evaluation (VMID range, tag, pool selectors), and fail-closed protection.
- **Protection union:** A guest is protected if it appears in `protected_vmids` **or** carries a tag from `protected_tags`. A protected guest is refused by every destructive and service-interrupting tool unless a waiver or lab mode supplies an override. (Read tools see protected guests normally.)
- **A guest-addressed tool never accepts the node from the caller.** It resolves it on every call, and again at apply, because guests migrate. Node-, storage- and task-scoped tools (`get_node_status`, `get_storage`, `list_backups`, `list_isos`, `list_templates`, `list_tasks`, `get_task_status`, `download_iso`, `get_node_firewall_rules`, `get_node_firewall_options`) do take a `node`, because a node is what they address --- there is no guest to resolve one from. The exception that matters is `create_vm`/`create_container`: they name a *guest* but the guest does not exist yet, so the caller supplies the node, and it is the one place a guest-addressed call can reach the wrong host. `stop_task` is deliberately not in that list: it reads the node from the UPID.
- **Catalog-driven dispatch:** Every read tool's HTTP method, path template, query flag, and type filter is declared once in `catalog.rs`.
- **In-flight recovery:** A change set left `Applying` with a task handle is re-probed at startup, so an apply interrupted by a restart resolves rather than staying unresolved forever.
- **SIGHUP reload:** `systemctl reload` reloads `clusters.json` in place without dropping in-flight calls. A failed reload logs and retains the previous snapshot.
- **Per-cluster CA pinning:** Each cluster can name a `ca_pem_path`. There is **no insecure-skip-verify at any layer**, so a cluster with a private CA needs its CA installed and must be addressed by a name its certificate covers.
- **Audit logging:** JSON-structured logs with optional PII redaction (HMAC-keyed or drop). Every tool call logs cluster, guest, tier, and protection status.
### The 31 read tools
| Tool | Scope | Description |
|------|-------|-------------|
| `get_cluster_status` | cluster | Quorum and node membership |
| `get_nodes` | cluster | All nodes with status and resource totals |
| `get_node_status` | node | Detailed status for one node |
| `get_vms` | cluster | All QEMU guests with node, status, tags (paginated: `offset`/`limit`, default 500, max 700) |
| `get_containers` | cluster | All LXC guests with node, status, tags (paginated: `offset`/`limit`, default 500, max 700) |
| `get_vm_config` | guest (QEMU only) | Configuration including Proxmox digest, with `description`/`cicustom`/`args` content redacted on a best-effort basis -- credential-shaped text is stripped, but this is not a safe place to store secrets (sshkeys and network config preservedWhat people ask about rustproxmoxmcp
What is mechubsec/rustproxmoxmcp?
+
mechubsec/rustproxmoxmcp is mcp servers for the Claude AI ecosystem. One Rust MCP server for many Proxmox VE clusters — a mechub project It has 1 GitHub stars and its last recorded update is dated 2026-10-17.
How do I install rustproxmoxmcp?
+
You can install rustproxmoxmcp by cloning the repository (https://github.com/mechubsec/rustproxmoxmcp) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is mechubsec/rustproxmoxmcp safe to use?
+
Our security agent has analyzed mechubsec/rustproxmoxmcp and assigned a Trust Score of 95/100 (tier: Verified). See the full breakdown of passed checks and flags on this page.
Who maintains mechubsec/rustproxmoxmcp?
+
mechubsec/rustproxmoxmcp is maintained by mechubsec. The last recorded GitHub activity is dated 2026-10-17, with 0 open issues.
Are there alternatives to rustproxmoxmcp?
+
Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.
Deploy rustproxmoxmcp to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/mechubsec-rustproxmoxmcp)<a href="https://claudewave.com/repo/mechubsec-rustproxmoxmcp"><img src="https://claudewave.com/api/badge/mechubsec-rustproxmoxmcp" alt="Featured on ClaudeWave: mechubsec/rustproxmoxmcp" width="320" height="64" /></a>More MCP Servers
Reverse engineer anything with agents, from app behavior down to native binaries.
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
🕷️ A Web Scraping framework that handles everything from a single request to a full-scale crawl! Don't be shy, join here: https://discord.gg/EMgGbDceNQ and follow here for daily tips and tricks: https://x.com/Scrapling_dev