io.github.AIops-tools/proxmox-aiops
This server provides governed Proxmox VE operations across VMs, containers, backups, snapshots, disks, cluster/storage/firewall/HA, diagnostics, and undo/audit tracking.
Inspect cluster nodes, resources, status, tasks/logs, VMIDs, pools, storage, firewall, and HA state.
Manage QEMU VMs: list/get/config, start/stop/shutdown/reboot, reconfigure, clone/delete/migrate, resize/move disks, snapshots create/delete/list/rollback, and guest-agent ping.
Manage LXC containers: list, start, and stop.
Create/list/restore backups with dry-run, force-overwrite guard, and async task tracking.
Run read-only diagnostics/RCA for node pressure and guest health.
Apply recorded undo tokens and inspect audit/risk-tier metadata.
Provides tools for managing Proxmox VE VMs and containers, including list, get, config, start, stop, shutdown, reboot, reconfigure, clone, delete, migrate, snapshot operations, and cluster/storage operations.
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., "@io.github.AIops-tools/proxmox-aiops list all VMs on pve-lab"
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 AIops
Audit availability: Real writes require a committed
pendingaudit row and stop before contacting the platform if storage is unavailable. Reads and previews may continue with a warning; new audit rows store outcome summaries rather than full responses.
Disclaimer: Community-maintained open-source project. Not affiliated with, endorsed by, or sponsored by Proxmox Server Solutions GmbH. "Proxmox" is a trademark of its owner. MIT licensed.
AI-powered Proxmox VE VM and container lifecycle operations with a built-in
governance harness — unified audit log, token/runaway budget
guard, undo-token recording, and descriptive risk-tier labels. Self-contained:
no external dependencies beyond proxmoxer and the MCP SDK. Coverage is not
yet exhaustive across every Proxmox operation.
Verification status: live-verified against real Proxmox VE 8.4.19 across three rounds — read-only surfaces, the QEMU write surface, and a two-node cluster (quorum, live migration,
move-disk, a backup that actually succeeded). Rounds 2 and 3 each found a real bug the mocks could not see. See docs/VERIFICATION.md for exactly what was proven and what is still uncovered.
What works
CLI (
proxmox-aiops ...):vm list/get/config/start/stop/shutdown/reboot/reconfigure/clone/delete/migrate,vm resize-disk/move-disk/agent-ping,vm snapshot-create/snapshot-delete/snapshot-list/snapshot-rollback,backup create/list/restore,ct list/start/stop,cluster nodes/status/task-status/resources/node-status/task-log/next-vmid,ha status/resources,pool list/members,firewall vm-rules/cluster-status,storage list/content,diagnose node-pressure/guest-health,undo list/apply,init,secret set/list/rm/migrate/rotate-password,doctor,mcp.MCP server (
proxmox-aiops mcporproxmox-aiops-mcp): 43 tools, every one wrapped with the bundled@governed_toolharness.Diagnostics / RCA (read-only):
diagnose node-pressureranks cluster nodes by CPU/memory/root-fs pressure;diagnose guest-healthscans VMs/containers for stopped guests, memory saturation, and disks near full. Every finding cites the measured number that tripped it and a concrete action — transparent heuristics, not a black-box verdict.Credentials:
proxmox-aiops init(onboarding wizard) andproxmox-aiops secret ...manage an encrypted secret store — no plaintext passwords inconfig.yaml.Reversibility: write ops with a clean inverse (start/stop/shutdown/reconfigure/clone/migrate/snapshot-create/move-disk, container start/stop, and restore-into-a-free-vmid) record an inverse undo descriptor; irreversible ops (delete, snapshot-rollback, forced restore) declare none and are tagged
highrisk. Disk resize is grow-only (shrink refused).Async tasks: Proxmox writes return a task UPID — poll completion with
cluster task-status/ read lines withcluster task-log(the runaway budget guard prevents poll loops from running away).
Related MCP server: proxmox-mcp
What this tool does, and does not, decide
It delivers Proxmox VE operations — reads and writes — accurately and efficiently, and records every one of them. It does not decide whether a write is allowed to happen. That is the agent's judgement, or the permission of the account you connect it with: use a Proxmox VE user or API token granted only read privileges (no VM./Datastore. write roles), and the writes fail at the server — the place that actually owns the permission.
So there is no read-only switch, no policy file, no approval gate to configure. The one thing the
tool guarantees is that nothing is silent: every call, over MCP and over the CLI alike, lands an
audit row in ~/.proxmox-aiops/audit.db, and destructive writes still capture their before-state
and record an inverse where one exists.
Each tool declares a
risk_level, carried into the audit row as a descriptive tier (none/confirm/review) — so a reviewer can see at a glance that a row was a high-risk delete. It is a label, not a gate.
Running a smaller / local model? See agent-guardrails.md — it lists the guardrails this tool now enforces for you (so you don't spend prompt budget restating them) and gives a ready-made system prompt for what's left.
Quick start
As a Claude Code plugin
One install gives an agent both the skill and the MCP server:
/plugin marketplace add AIops-tools/marketplace
/plugin install proxmox-aiops@aiops-toolsThe MCP server is fetched with uv and pinned to the
package version this plugin declares, so an audit row can be traced back to the
code that wrote it. Credentials are still configured with proxmox-aiops init — see below.
As an OpenClaw plugin
The same bundle is published on ClawHub, where one install delivers the skill and its MCP server together:
openclaw plugins install clawhub:@zw008/proxmox-aiops
openclaw skills info proxmox-aiops # expect: Visible to model: yesRestart the OpenClaw gateway afterwards so it loads the plugin. The MCP server is
fetched with uv, pinned to this exact release, so
uvx has to be on PATH — without it the skill still installs but reports
Visible to model: no. Credentials are configured exactly as below.
As a CLI or standalone MCP server
uv tool install proxmox-aiops
mkdir -p ~/.proxmox-aiops
# create ~/.proxmox-aiops/config.yaml with a targets: list
# put secrets in ~/.proxmox-aiops/.env (chmod 600)
proxmox-aiops doctorExample ~/.proxmox-aiops/config.yaml:
targets:
- name: pve-lab
host: 10.0.0.10
user: "claude@pve!ops" # API token: user@realm!tokenid — a dedicated,
# least-privilege user, NOT root@pam
node: pve1
auth_kind: token
verify_ssl: false # self-signed lab certs only~/.proxmox-aiops/.env (chmod 600): PROXMOX_PVE_LAB_SECRET=<token-uuid>
Audit & safety
All operations are logged to a local SQLite audit DB under ~/.proxmox-aiops/
(relocatable via PROXMOX_AIOPS_HOME). Every write tool passes through the
governance harness: token/runaway budget guard, risk-tier tagging, and audit
logging. Destructive CLI commands (vm stop,
vm delete, vm snapshot-delete, vm snapshot-rollback, ct stop) require
double confirmation and support --dry-run (notably backup restore, which is
high risk). API-returned text is run through a prompt-injection sanitizer.
Contributing & feature requests
Coverage is intentionally focused. Missing a device, action, or feature you need? Open an issue or pull request at github.com/AIops-tools/Proxmox-AIops — feature requests, contributions, and comments are all welcome.
License: MIT.
Available Tools
43 toolsbackup_listARead-only
[READ] List backup archives on a storage (optionally filtered by vmid).
Args: storage: Storage id to list backups from. vmid: Optional guest id filter. target: Proxmox target name from config. node: Node name; omit to use the configured default node.
Inputs: storage (required), node, vmid, target.
backup_restoreADestructive
[WRITE] Restore a QEMU VM from a backup archive. HIGH RISK. Returns task UPID.
With force=True this OVERWRITES an existing VM (destructive, no undo). Restoring into a free vmid records a delete as the safe inverse. Confirm with the user before calling. Pass dry_run=True to preview: it runs the same existing-VM guard (a preview that would be refused for overwriting without force refuses too) and reports whether it would overwrite or create.
Args: vmid: Target VM id to restore into. archive: Backup volume id / archive path (see backup_list). storage: Storage to place the restored disks on. force: Overwrite vmid if it already exists (destructive). dry_run: If True, preview (runs the existing-VM guard) without restoring. target: Proxmox target name from config. node: Node name; omit to use the configured default node.
Inputs: vmid (required), archive (required), storage (required), node, +3 more.
cluster_firewall_statusARead-only
[READ] Cluster-wide firewall options (notably whether it is enabled).
Args: target: Proxmox target name from config.
Inputs: target.
cluster_resourcesARead-only
[READ] Aggregate /cluster/resources view of VMs, nodes, and storage.
Single-call cluster-wide inventory. Use this to enumerate everything before drilling into vm_get / node_status.
Args: resource_type: Optional filter — 'vm', 'node', or 'storage'. target: Proxmox target name from config.
Inputs: target, resource_type.
cluster_statusARead-only
[READ] Return cluster membership + quorum status.
The type=cluster row's quorate field indicates whether the cluster
currently has quorum.
Args: target: Proxmox target name from config.
Inputs: target.
ct_listARead-only
[READ] List LXC containers with name, vmid, status, cpu, mem.
Args: target: Proxmox target name from config; omit to use the default. node: Node name; omit to use the configured default / all nodes.
Inputs: node, target.
ct_startADestructive
[WRITE] Start an LXC container. Returns the task UPID. Inverse: ct_stop.
Pass dry_run=True to preview.
Args: vmid: Numeric container id (see ct_list). dry_run: If True, preview without starting. target: Proxmox target name from config. node: Node name; omit to auto-locate the container.
Inputs: vmid (required), node, target, dry_run.
ct_stopADestructive
[WRITE] Stop an LXC container. Returns the task UPID. Inverse: ct_start.
Pass dry_run=True to preview.
Args: vmid: Numeric container id (see ct_list). dry_run: If True, preview without stopping. target: Proxmox target name from config. node: Node name; omit to auto-locate the container.
Inputs: vmid (required), node, target, dry_run.
guest_health_rcaARead-only
[READ] Scan VMs and containers for stopped guests, memory saturation, and disks near full.
Pulls the /cluster/resources guest view (qemu + lxc) and reports worst-first findings plus the list of stopped guests, each finding citing the measured number and a concrete remediation.
Args: target: Proxmox target name from config; omit to use the default.
Inputs: target.
ha_resource_listBRead-only
[READ] HA-managed resources (VMs/CTs); empty when HA is not configured.
Args: target: Proxmox target name from config.
Inputs: target.
ha_statusARead-only
[READ] Current HA status entries, or a not-configured signal.
Returns {"configured": bool, "entries": [...]}. Do NOT infer "HA is set up" from a non-empty entries list: every quorate cluster reports a quorum row, and master/lrm rows once the HA stack has run, with zero resources defined. "configured" is true only when HA actually manages something; when it is false a message explains that the rows describe the stack itself.
Args: target: Proxmox target name from config.
Inputs: target.
next_vmidCRead-only
[READ] Return a free VMID for a new guest (/cluster/nextid).
Args: target: Proxmox target name from config.
Inputs: target.
node_listBRead-only
[READ] List Proxmox cluster nodes with status, cpu load, and memory.
Args: target: Proxmox target name from config; omit to use the default.
Inputs: target.
node_pressure_rcaARead-only
[READ] Rank cluster nodes by CPU / memory / root-fs pressure.
Pulls the /cluster/resources node view and flags each node over the CPU (85%), memory (90%), or disk (85%) thresholds, worst-first, citing the measured percentage and a concrete action for every finding.
Args: target: Proxmox target name from config; omit to use the default.
Inputs: target.
node_statusARead-only
[READ] Detailed status for one node: cpu, load average, memory, uptime.
Args: node: Node name (see node_list). target: Proxmox target name from config.
Inputs: node (required), target.
pool_listBRead-only
[READ] List resource pools (poolid + comment).
Args: target: Proxmox target name from config.
Inputs: target.
pool_membersBRead-only
[READ] List the members of a pool (VMs, CTs, storage).
Args: poolid: Pool id (see pool_list). target: Proxmox target name from config.
Inputs: poolid (required), target.
storage_contentARead-only
[READ] List volumes on a storage pool (ISOs, disk images, backups, templates).
Args: storage: Storage pool id (see storage_list). content: Optional filter — 'iso', 'images', 'backup', 'vztmpl'. target: Proxmox target name from config. node: Node name; omit to use the configured default node.
Inputs: storage (required), node, target, content.
storage_listARead-only
[READ] List storage pools on a node (id, type, total/used/avail bytes).
Args: target: Proxmox target name from config; omit to use the default. node: Node name; omit to use the target's configured default node.
Inputs: node, target.
task_logARead-only
[READ] Fetch the log lines of an async task by its UPID.
Returns {"lines": [...], "returned": N, "limit": L, "truncated": bool}. When truncated is true there are more lines than were returned — raise limit or narrow the query rather than assuming you have the whole log.
Args: upid: The task UPID. limit: Max log lines to return. target: Proxmox target name from config. node: Node the task runs on; omit to parse it from the UPID.
Inputs: upid (required), node, limit, target.
task_statusARead-only
[READ] Poll a Proxmox async task (clone / migrate / backup) by its UPID.
Use after a write that returned a task UPID to check completion instead of re-issuing the operation. The node is parsed from the UPID when omitted.
Args: upid: The task UPID returned by an async write tool. target: Proxmox target name from config. node: Node the task runs on; omit to parse it from the UPID.
Inputs: upid (required), node, target.
undo_applyADestructive
[WRITE][risk=medium] Apply a recorded undo by dispatching its inverse tool.
The inverse runs through its own governed tool, so its own risk tier is recorded on the audit row there. Pass dry_run=True to preview the inverse call without executing it. A token can only be applied once.
Args:
undo_id: The undoId from undo_list (or an _undo_id in a write result).
dry_run: If True, preview the inverse tool + params without running it.
target: Passed through to the inverse tool when it accepts a target.
Inputs: undo_id (required), target, dry_run.
undo_listARead-only
[READ] List recorded, not-yet-applied undo tokens (most recent first).
Each entry names the original tool, the inverse tool that undo_apply
would run, and a human note. Use the undoId with undo_apply.
Returns {"undos": [...], "returned": N, "limit": L, "truncated": bool}.
truncated is measured (one extra row is fetched), not guessed from a
length coincidence: when it is true there are MORE tokens than shown, so
re-run with a higher limit rather than reporting the list as complete.
Each entry carries effectVerified. False means the original write lost
its response, so the change it reverses is PROBABLE, not confirmed — check
the live state before applying, and do not report the result as a restore
of a state that may never have been reached.
Args: limit: Max rows to return (default 50, capped at 500). target: Unused (undo state is host-local); accepted for CLI uniformity.
Inputs: limit, target.
vm_agent_pingARead-only
[READ] Ping a VM's QEMU guest agent to check it is installed and responsive.
A non-running or absent agent yields responsive=False with an explanation rather than an error.
Args: vmid: Numeric Proxmox VM id. target: Proxmox target name from config. node: Node name; omit to auto-locate the VM.
Inputs: vmid (required), node, target.
vm_backupADestructive
[WRITE] Create a vzdump backup of a VM/CT to a storage. Returns task UPID.
Args: vmid: Numeric Proxmox guest id (VM or container). storage: Backup-capable storage id (see storage_list / storage_content). mode: 'snapshot' (default, no downtime), 'suspend', or 'stop'. target: Proxmox target name from config. node: Node name; omit to auto-locate the guest.
Inputs: vmid (required), storage (required), mode, node, +1 more.
vm_cloneADestructive
[WRITE] Clone a VM to a new vmid. Returns the task UPID. Inverse: vm_delete(newid).
Cloning is asynchronous — poll completion with task_status, do not re-issue. Pass dry_run=True to preview.
Args: vmid: Source VM id to clone from. newid: New (unused) VM id for the clone. name: Optional name for the clone. dry_run: If True, preview without cloning. target: Proxmox target name from config. node: Node name; omit to auto-locate the source VM.
Inputs: vmid (required), newid (required), name, node, +2 more.
vm_configBRead-only
[READ] Return a VM's config (cores, memory, ostype, boot order).
Args: vmid: Numeric Proxmox VM id. target: Proxmox target name from config. node: Node name; omit to auto-locate the VM.
Inputs: vmid (required), node, target.
vm_deleteADestructive
[WRITE] Permanently destroy a VM. IRREVERSIBLE — no undo token.
Confirm with the user before calling. Audited to ~/.proxmox-aiops/audit.db. Pass dry_run=True to preview.
Args: vmid: Numeric Proxmox VM id to destroy. dry_run: If True, preview without destroying. target: Proxmox target name from config. node: Node name; omit to auto-locate the VM.
Inputs: vmid (required), node, target, dry_run.
vm_firewall_rules_listARead-only
[READ] List the firewall rules attached to a VM.
Args: vmid: Numeric Proxmox VM id. target: Proxmox target name from config. node: Node name; omit to auto-locate the VM.
Inputs: vmid (required), node, target.
vm_getARead-only
[READ] Return current status detail for a single VM by vmid.
Args: vmid: Numeric Proxmox VM id (see vm_list). target: Proxmox target name from config. node: Node name; omit to auto-locate the VM across nodes.
Inputs: vmid (required), node, target.
vm_listARead-only
[READ] List QEMU VMs with name, vmid, status, cpu, mem.
Scans the given node, the configured default node, or all cluster nodes. Use vm_get for full status of a single VM.
Args: target: Proxmox target name from config; omit to use the default. node: Node name; omit to use the target's configured node / all nodes.
Inputs: node, target.
vm_list_snapshotsBRead-only
[READ] List snapshots for a VM (name + description).
Args: vmid: Numeric Proxmox VM id. target: Proxmox target name from config. node: Node name; omit to auto-locate the VM.
Inputs: vmid (required), node, target.
vm_migrateADestructive
[WRITE] Migrate a VM to another node. Returns task UPID. Inverse: migrate back.
Asynchronous — poll completion with task_status. Pass dry_run=True to preview.
Args: vmid: Numeric Proxmox VM id. target_node: Destination node name. online: True (default) for live migration; False to migrate while stopped. dry_run: If True, preview without migrating. target: Proxmox target name from config. node: Source node name; omit to auto-locate the VM.
Inputs: vmid (required), target_node (required), node, online, +2 more.
vm_move_diskADestructive
[WRITE] Move a VM disk to another storage. Returns task UPID. Async.
Records a reverse move as the undo token when the source storage is known. Pass dry_run=True to read the disk's current placement and preview the move.
Args: vmid: Numeric Proxmox VM id. disk: Disk key, e.g. 'scsi0'. storage: Destination storage id. delete: Remove the source copy after the move completes. dry_run: If True, preview the from→to move without moving anything. target: Proxmox target name from config. node: Node name; omit to auto-locate the VM.
Inputs: disk (required), vmid (required), storage (required), node, +3 more.
vm_rebootADestructive
[WRITE] Reboot a VM (graceful). No undo token — reboot has no inverse.
Args: vmid: Numeric Proxmox VM id. target: Proxmox target name from config. node: Node name; omit to auto-locate the VM.
Inputs: vmid (required), node, target.
vm_reconfigureADestructive
[WRITE] Change a VM's cores and/or memory (MiB). Inverse: restore prior values.
Provide at least one of cores / memory. The previous values are captured so the harness records a reverse reconfigure as the undo token. Pass dry_run=True to read the current cores/memory and preview the change.
Args: vmid: Numeric Proxmox VM id. cores: New vCPU core count (omit to leave unchanged). memory: New memory in MiB (omit to leave unchanged). dry_run: If True, preview what would change without applying it. target: Proxmox target name from config. node: Node name; omit to auto-locate the VM.
Inputs: vmid (required), node, cores, memory, +2 more.
vm_resize_diskADestructive
[WRITE] Grow a VM disk. GROW-ONLY — shrink requests are refused.
No undo token: growing a disk cannot be reversed. Pass dry_run=True to preview.
Args: vmid: Numeric Proxmox VM id. disk: Disk key, e.g. 'scsi0', 'virtio0', 'sata0'. size: '+G' increment (e.g. '+10G') or a larger absolute size. dry_run: If True, preview without resizing. target: Proxmox target name from config. node: Node name; omit to auto-locate the VM.
Inputs: disk (required), size (required), vmid (required), node, +2 more.
vm_shutdownADestructive
[WRITE] Graceful ACPI shutdown of a VM (vs the hard vm_stop). Inverse: vm_start.
Pass dry_run=True to preview.
Args: vmid: Numeric Proxmox VM id. dry_run: If True, preview without shutting down. target: Proxmox target name from config. node: Node name; omit to auto-locate the VM.
Inputs: vmid (required), node, target, dry_run.
vm_snapshot_createADestructive
[WRITE] Create a named snapshot of a VM. Inverse: vm_snapshot_delete.
Pass dry_run=True to preview.
Args: vmid: Numeric Proxmox VM id. name: Snapshot name (must be unique for the VM). dry_run: If True, preview without creating. target: Proxmox target name from config. node: Node name; omit to auto-locate the VM.
Inputs: name (required), vmid (required), node, target, +1 more.
vm_snapshot_deleteADestructive
[WRITE] Delete a named snapshot from a VM. Destroys a rollback point — no undo.
Pass dry_run=True to preview.
Args: vmid: Numeric Proxmox VM id. name: Snapshot name to delete (see vm_snapshot_list). dry_run: If True, preview without deleting. target: Proxmox target name from config. node: Node name; omit to auto-locate the VM.
Inputs: name (required), vmid (required), node, target, +1 more.
vm_snapshot_rollbackADestructive
[WRITE] Roll a VM back to a snapshot. IRREVERSIBLE — discards changes since then.
No undo token (the discarded state cannot be recovered). Confirm with the user. Pass dry_run=True to preview.
Args: vmid: Numeric Proxmox VM id. name: Snapshot name to roll back to (see vm_list_snapshots). dry_run: If True, preview without rolling back. target: Proxmox target name from config. node: Node name; omit to auto-locate the VM.
Inputs: name (required), vmid (required), node, target, +1 more.
vm_startADestructive
[WRITE] Start a VM. Returns the Proxmox task UPID. Inverse: vm_stop.
Args: vmid: Numeric Proxmox VM id. target: Proxmox target name from config. node: Node name; omit to auto-locate the VM.
Inputs: vmid (required), node, target.
vm_stopADestructive
[WRITE] Hard-stop (power off) a VM. Returns the task UPID. Inverse: vm_start.
This is an immediate power-off (not a graceful guest shutdown); the guest filesystem may be left dirty. Audited to ~/.proxmox-aiops/audit.db. Pass dry_run=True to preview.
Args: vmid: Numeric Proxmox VM id. dry_run: If True, preview without stopping. target: Proxmox target name from config. node: Node name; omit to auto-locate the VM.
Inputs: vmid (required), node, target, dry_run.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 43 tools
Most tools map to a distinct resource and action, and descriptions clarify overlaps such as vm_get/vm_config and vm_stop/vm_shutdown/vm_reboot. Some broader inventory tools overlap (cluster_resources vs node_list/vm_list/ct_list), but an agent can generally distinguish intended use.
Names are almost entirely snake_case with predictable resource prefixes and verb/action patterns (vm_start, ct_stop, node_list, task_status). Minor deviations like vm_list_snapshots vs vm_snapshot_create and vm_firewall_rules_list keep it from perfect consistency.
43 tools is well beyond the 25+ threshold and includes redundant read surfaces such as cluster_resources vs individual list tools, plus backup_list overlapping storage_content. Proxmox is broad, but the set still feels over-expanded and would benefit from consolidation.
Core VM lifecycle coverage is strong (start/stop/shutdown/reboot/clone/migrate/snapshot/backup/restore/disk operations), but CT coverage is mostly limited to list/start/stop. VM creation from scratch and firewall rule write operations are absent, leaving notable lifecycle gaps.
Maintenance
Related MCP Connectors
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
AI-powered incident management and server monitoring via MCP.
Devopness MCP server for DevOps happiness! Empower AI Agents to deploy apps and infra, to any cloud.
Related MCP Servers
- AlicenseBqualityCmaintenanceA Model Context Protocol (MCP) server for Proxmox Virtual Environment that enables AI assistants to manage virtual machines, containers, nodes, and resources through natural language interactions.104MIT
- AlicenseNot gradedqualityDmaintenanceMCP server for full Proxmox VE management - VMs, containers, storage, backups, networking.2MIT
- FlicenseNot gradedqualityDmaintenanceMCP server for Proxmox VE that enables AI assistants to inspect and manage LXC containers, VMs, snapshots, and resource pools via the Proxmox API.-
- AlicenseAqualityDmaintenanceMCP server for managing Proxmox VE resources, VM/CT lifecycle, snapshots, backups, and clones via natural language.23MIT