Metadata-Version: 2.5
Name: proxmox-model-context-protocol
Version: 0.1.0
Summary: MCP server for full management of a Proxmox VE hypervisor, with local safety barriers
Author-email: Jakub Krajewski <MCP.Proxmox@gmail.com>
License-Expression: Apache-2.0
License-File: LICENSE
License-File: NOTICE
Keywords: llm,mcp,model-context-protocol,proxmox,proxmox-ve,pve,virtualization
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: System :: Systems Administration
Classifier: Typing :: Typed
Requires-Python: >=3.12
Requires-Dist: asyncssh>=2.21
Requires-Dist: httpx>=0.28
Requires-Dist: mcp<3,>=2.2
Requires-Dist: pydantic-settings>=2.10
Requires-Dist: pydantic>=2.11
Requires-Dist: python-dotenv>=1.1
Description-Content-Type: text/markdown

# proxmox-model-context-protocol

An MCP (Model Context Protocol) server that lets an AI assistant such as Claude manage a
Proxmox VE hypervisor.

It has 118 tools for guests, snapshots, backups, storage, networking, firewall, SDN,
users and ACLs, node administration and commands inside guests. `pve_api_call` reaches
any other API endpoint. The server starts read-only.

**Status: alpha.** Tool names, parameters and configuration may change between
releases. Tested on single-node Proxmox VE 9.1 and 9.2.

The server uses an API token with full privileges. Proxmox VE does not limit what the
model can do with it; all safeguards described below run locally in this server. Keep
clients read-only unless they need to change things, and review `critical.env`.

## Contents

- [Features](#features)
- [Safety model](#safety-model)
- [Requirements](#requirements)
- [Quick start](#quick-start)
- [Connecting an MCP client](#connecting-an-mcp-client)
- [Write mode and critical operations](#write-mode-and-critical-operations)
- [Commands inside guests and on the node](#commands-inside-guests-and-on-the-node)
- [Configuration reference](#configuration-reference)
- [Command line](#command-line)
- [Limitations](#limitations)
- [Security and license](#security-and-license)

## Features

| Area | Examples |
|---|---|
| Inventory and monitoring | cluster resources, guest and node status, metrics, tasks and task logs, node journal |
| Guests | create a VM or container, clone, start, shut down, stop, reboot, delete, convert to a template |
| Configuration | guest config, disk resize and move, migration, pending changes |
| Snapshots and backups | snapshots, rollback, backups, backup jobs and schedules, restore, retention, guests without a backup |
| Storage | storage definitions, content, download from a URL, upload, appliance templates, volume protection |
| Networking | node interfaces with a review of pending changes, firewall rules, aliases and IP sets, SDN zones, VNets and subnets |
| Node | services, updates, APT repositories, DNS, `/etc/hosts`, time zone, reboot and shutdown; certificates and disks read-only |
| Access control | users, tokens, groups, roles, ACLs, effective permissions |
| Inside guests | `pve_ct_exec` (containers), `pve_vm_exec` (VMs, through the QEMU guest agent), reading and writing files |
| Node upgrades | upgrade simulation, upgrade in a detached systemd unit, kernel pinning |
| Other endpoints | `pve_api_call`; `pve_api_explore` and `pve_api_schema` read the node's API schema without calling anything |

The number of registered tools depends on the configuration: 44 in read-only mode, 114 in
write mode, 118 with guest commands. `proxmox-model-context-protocol tools` lists them.

### Tool groups

Each registered tool adds its description to the model's context. `PROXMOX_TOOLSETS`
(a comma-separated list) registers only the groups a client needs:

| Group | Read tools | Write tools (write mode) |
|---|---|---|
| core (always) | inventory, guest status and config, storage and backup lists, tasks, metrics, connection check, classification, API schema, audit log, `pve_api_call` | none |
| `guests` | QEMU guest agent status | power, snapshots, create, clone, delete, configuration, disks, migration, templates |
| `backup` | backup jobs, schedules, guests without a backup | backups, jobs, restore |
| `storage` | none | storage definitions, downloads, uploads, volumes, retention |
| `network` | interfaces, firewall, SDN | interfaces, firewall, SDN |
| `node` | services, updates, repositories, certificates, disks, journal | services, APT, DNS, hosts, time zone, reboot, upgrade, kernel |
| `access` | users, ACLs, roles, permissions | users, tokens, groups, roles, ACLs |
| `exec` | none | commands and files inside guests (also needs `PROXMOX_EXEC`) |

Unset or `all` registers every group; `core` registers only the core. An unknown name
stops the server. Tool groups only reduce the context size. They are not a safety
control: `pve_api_call` is part of the core, and the mode and flags decide what can
change.

## Safety model

1. **Mode.** Without `PROXMOX_MODE=write` the write tools are not registered and
   `pve_api_call` sends only `GET` requests. Set the mode per MCP client.
2. **Classification.** Each request is classified as `READ`, `WRITE`, `DESTRUCTIVE` or
   `CRITICAL` by method, path and parameters. `GET /nodes/{node}/status` is a read;
   `POST` to the same path with `command=reboot` reboots the node.
   `pve_classify_operation` shows the class of a request without sending it.
3. **Critical operation flags.** Each `CRITICAL` category (node power, guest deletion,
   network, firewall, ACLs, storage, disks and others) has a `PROXMOX_ALLOW_<CATEGORY>`
   flag in `critical.env`. Without the flag the category is unavailable, including its
   dry run.
4. **Confirmation.** A critical operation also needs `confirm` set to the exact API path
   (for a guest command, the exact command text).
5. **Dry run.** Write tools and `pve_api_call` accept `dry_run=true`. The server then
   reports what it would send and sends nothing.
6. **VMID lists.** `PROXMOX_ALLOWED_VMIDS` and `PROXMOX_DENIED_VMIDS` limit write
   operations to some guests. The deny list takes precedence.
7. **Self-lockout protection.** Changes to the server's own user, token, ACLs, groups and
   roles, and to `root@pam`, are always refused, also in a dry run. Make those changes
   in the Proxmox web GUI.
8. **Canonical paths.** The safeguards check the path that Proxmox will route:
   percent-encoding is decoded first (`%73tatus`, `node%2Fstatus`). Paths with `.`,
   `..` or empty segments, a `?` query string or double encoding are refused.
9. **No retry after an uncertain write.** If a write may have reached Proxmox (for
   example, a read timeout after sending), the server reports `OUTCOME UNKNOWN` and does
   not send it again.
10. **No shell on the node.** Guest commands and node upgrades go over SSH to a guard
    script that runs only a fixed set of commands (`pct exec`, the upgrade, kernel
    pinning). `pve_api_call` refuses the node and guest consoles (`termproxy`,
    `vncshell`, `vncproxy`, `spiceshell`, `spiceproxy`, `vncwebsocket`), the QEMU
    monitor, `/nodes/{node}/execute` and the guest agent's exec and file calls.
11. **Guest commands.** Direct reads of secret files inside guests (`/etc/shadow`, SSH
    keys, private keys) are refused. The command parser only catches mistakes; it is
    not a security boundary. For guest commands the real limits are `PROXMOX_EXEC`, the
    category flags and your approval in the MCP client.
12. **Audit log.** Every operation is written to a local JSONL log, including requests
    blocked locally, dry runs and errors. Passwords, console tickets and new token
    secrets are masked in tool results and in the log. `pve_audit_log` shows the log.

## Requirements

- Proxmox VE with HTTPS API access. Tested on PVE 9.1 and 9.2, single node.
- Python 3.12 or newer. [uv](https://docs.astral.sh/uv/) is recommended; `uvx` runs the
  server without installing it first.
- An MCP client: Claude Code, Claude Desktop or another client that starts stdio servers.
- For guest commands in containers and node upgrades: root access to the node once, to
  install the SSH guard and a dedicated account.

## Quick start

### 1. Create the configuration directory

```bash
uvx proxmox-model-context-protocol init
```

`init` creates `.env` and `critical.env` in:

| System | Configuration | Audit log |
|---|---|---|
| Linux | `~/.config/proxmox-model-context-protocol` (`$XDG_CONFIG_HOME`) | `~/.local/state/proxmox-model-context-protocol` (`$XDG_STATE_HOME`) |
| macOS | `~/Library/Application Support/proxmox-model-context-protocol` | `~/Library/Logs/proxmox-model-context-protocol` |
| Windows | `%USERPROFILE%\.proxmox-model-context-protocol` | `%USERPROFILE%\.proxmox-model-context-protocol\state` |

`proxmox-model-context-protocol config --open` opens the directory.
`PROXMOX_MCP_CONFIG_DIR` sets a different one. The directory holds the API token and the
SSH key, so keep it private.

The `critical.env` created by `init` enables all critical categories. Read the warning
at the top of the file and set to `disabled` what the server should never do.

### 2. Create an API token

On the node (web GUI > node > Shell, as root):

```bash
pveum user add mcp@pve --comment "MCP"
pveum acl modify / --users 'mcp@pve' --roles Administrator
pveum user token add mcp@pve full --privsep 0
```

`--privsep 0` gives the token the user's `Administrator` role on `/`. Copy the secret
shown by the last command; Proxmox does not show it again. You can revoke this token at
any time without affecting `root@pam`.

If the token lacks privileges, Proxmox returns empty lists instead of errors.
`proxmox-model-context-protocol check` lists missing privileges.

### 3. Fill in `.env`

```ini
PROXMOX_HOST=192.0.2.10:8006
PROXMOX_TOKEN_ID=mcp@pve!full
PROXMOX_TOKEN_SECRET=<the token secret>
```

Then get the certificate fingerprint:

```bash
uvx proxmox-model-context-protocol fingerprint
```

Compare it with the fingerprint in the web GUI (node > System > Certificates) and add
the printed `PROXMOX_TLS_FINGERPRINT=...` line to `.env`. Update it when the node
certificate changes. Instead of a fingerprint you can use `PROXMOX_TLS_CA_FILE`, or the
system trust store if the certificate is publicly trusted.

### 4. Check the connection

```bash
uvx proxmox-model-context-protocol check
```

The report shows the connection, TLS, token privileges, file locations and, if
configured, SSH.

## Connecting an MCP client

### Claude Desktop extension

1. Create the extension file:

   ```bash
   uvx proxmox-model-context-protocol mcpb
   ```

   It writes `proxmox-model-context-protocol-<version>.mcpb` to the current directory
   (`--output` picks another). The extension installs the same version from PyPI.
2. In Claude Desktop open Settings > Extensions > Advanced settings > Install Extension
   and select the file. On Windows do not double-click it: Windows can pass Claude its
   short 8.3 name (`PROXMO~1.MCP`), and Claude then attaches the file to a chat instead
   of installing it.
3. Fill in the host, token ID and token secret. The secret is stored in the system
   credential store; do not type it into a chat. Empty optional fields fall back to
   `.env` in the configuration directory.
4. Turn the extension on with its switch. Claude does not enable an extension while a
   required field is empty.

Claude Desktop installs Python and the dependencies itself, so the first start takes a
while. The extension starts read-only. In write mode, two switches in the extension
settings control whether critical operations and guest commands are available; both are
on by default, override `critical.env`, and critical calls still need `confirm`.
Container commands also need the SSH setup below. The tools are named
`mcp__Proxmox_VE__<tool>`; use that prefix in permission rules.

### Claude Code

Read-only:

```bash
claude mcp add proxmox -- uvx proxmox-model-context-protocol
```

With write mode:

```bash
claude mcp add proxmox --env PROXMOX_MODE=write -- uvx proxmox-model-context-protocol
```

### Claude Desktop configuration file

In `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "proxmox": {
      "command": "uvx",
      "args": ["proxmox-model-context-protocol"]
    }
  }
}
```

For write mode add `"env": {"PROXMOX_MODE": "write"}` to the entry. Edit the file only
while Claude Desktop is fully closed; a running instance overwrites it.

### Other clients

Run `proxmox-model-context-protocol` (or `uvx proxmox-model-context-protocol`) as a
stdio server. The configuration is read from the configuration directory, not from the
working directory.

## Write mode and critical operations

With `PROXMOX_MODE=write` the server can create and delete guests, change networking,
ACLs and storage, and reboot the node. Set it in the client configuration rather than in
`.env`, so that only the clients that need it get write access.

Flags in `critical.env`:

| Flag | Covers |
|---|---|
| `PROXMOX_ALLOW_NODE_POWER` | node reboot and shutdown |
| `PROXMOX_ALLOW_NODE_STOPALL`, `_SUSPENDALL`, `_MIGRATEALL` | actions on all guests of a node |
| `PROXMOX_ALLOW_CLUSTER_BULK_ACTIONS` | start, shutdown, suspend and migrate of guests across the cluster |
| `PROXMOX_ALLOW_CLUSTER_CONFIG` | cluster creation and membership |
| `PROXMOX_ALLOW_CLUSTER_OPTIONS`, `_NODE_CONFIG` | datacenter options, node configuration |
| `PROXMOX_ALLOW_CRITICAL_SERVICES` | stopping or restarting pveproxy, pvedaemon, sshd, HA services |
| `PROXMOX_ALLOW_HA` | High Availability resources, rules and arming |
| `PROXMOX_ALLOW_NODE_DISKS` | wipe, GPT, ZFS and LVM on physical disks |
| `PROXMOX_ALLOW_NODE_NETWORK`, `_NODE_HOSTS`, `_NODE_DNS` | node interfaces, `/etc/hosts`, DNS |
| `PROXMOX_ALLOW_NODE_CERTIFICATES` | node TLS certificate; a new one invalidates the pinned fingerprint |
| `PROXMOX_ALLOW_APT_REPOSITORIES` | the node's package sources |
| `PROXMOX_ALLOW_SDN_APPLY` | applying SDN changes |
| `PROXMOX_ALLOW_CLUSTER_FIREWALL`, `_NODE_FIREWALL` | cluster and node firewall |
| `PROXMOX_ALLOW_CEPH` | Ceph |
| `PROXMOX_ALLOW_STORAGE_DEFINITIONS` | adding, changing and removing storage |
| `PROXMOX_ALLOW_VOLUME_DELETE` | deleting volumes and backups, pruning backups |
| `PROXMOX_ALLOW_ACCESS_CONTROL` | users, tokens, ACLs, roles |
| `PROXMOX_ALLOW_GUEST_DELETE` | deleting a VM or container |
| `PROXMOX_ALLOW_PRIVILEGED_CONTAINER` | creating a privileged container (`unprivileged=0`) |
| `PROXMOX_ALLOW_GUEST_TEMPLATE` | converting a guest to a template (cannot be undone) |
| `PROXMOX_ALLOW_GUEST_RESTORE_OVERWRITE` | restoring over an existing guest |
| `PROXMOX_ALLOW_CUSTOM_PROTECTED` | paths listed in `PROXMOX_EXTRA_PROTECTED_PATHS` |
| `PROXMOX_ALLOW_EXEC_*` | risky guest commands: power, packages, deletion, services, disks, system files, shell scripts |
| `PROXMOX_ALLOW_NODE_UPGRADE`, `_NODE_BOOT_CONFIG` | node upgrade and kernel pinning over SSH |

A flag is on when set to `enabled`, `1`, `true`, `yes` or `on`. Any other value or a
missing variable turns it off. Environment variables override the file. A flag does not
replace `confirm`; both are required.

Before an unfamiliar write operation, have the assistant use `pve_api_schema`,
`pve_classify_operation` with the same parameters, or `dry_run=true`. A write method
called without parameters runs with its default parameters.

## Commands inside guests and on the node

These tools are registered only with `PROXMOX_MODE=write` and `PROXMOX_EXEC=enabled`:
`pve_ct_exec`, `pve_vm_exec`, `pve_guest_file_read`, `pve_guest_file_write`.

**Virtual machines** use the QEMU guest agent through the API; no SSH is needed. The
agent must allow `guest-exec`. RHEL-based images block it by default.
`pve_vm_agent_status` shows what the agent allows. On AlmaLinux and RHEL 10 the
allowed commands are listed in `/etc/sysconfig/qemu-ga`:

```bash
sudo sed -i 's/^FILTER_RPC_ARGS="--allow-rpcs=/&guest-exec,guest-exec-status,guest-file-open,guest-file-close,guest-file-read,guest-file-write,guest-file-seek,guest-file-flush,/' /etc/sysconfig/qemu-ga
sudo systemctl restart qemu-guest-agent
```

**Containers** and **node upgrades** use SSH to the node. A guard script on the node
runs only a fixed set of commands. Set it up once:

```bash
uvx proxmox-model-context-protocol ssh-setup --append-env
uvx proxmox-model-context-protocol ssh-guard
uvx proxmox-model-context-protocol ssh-account
```

1. `ssh-setup` creates the client key in `ssh/` in the configuration directory and pins
   the node's host key. `--append-env` adds `PROXMOX_SSH_HOST_KEY` and
   `PROXMOX_SSH_ALLOWED_IP` to `.env`.
2. `ssh-guard` prints the guard script, its SHA-256 and the steps to install it on the
   node as root.
3. `ssh-account` prints a script that creates the `proxmox-mcp` account. Its only
   `sudo` right is running the guard, and its key works only from your IP address. Then
   set `PROXMOX_SSH_USER=proxmox-mcp` in `.env` and run `check`.

Adding a new kind of node command requires a new guard version, which you install on the
node yourself.

### Claude Code in auto mode

The auto-mode classifier in Claude Code can block `pve_ct_exec`, `pve_vm_exec` and the
guest file tools before they reach the server, and the model cannot override it. For
guest commands, switch the session to a permission mode that asks for approval; you then
see and approve each command.

To keep auto mode, add the tool to `~/.claude/settings.json` yourself:

```json
{
  "permissions": {
    "allow": ["mcp__proxmox__pve_ct_exec"]
  }
}
```

`proxmox` is the server name from your client configuration (`Proxmox_VE` for the
extension). The rule applies to every project and session, and the model then runs
container commands without asking. The model also fills in `confirm`, so `confirm`
prevents mistakes but not deliberate actions. For guests that matter, use manual
approval. Add `pve_vm_exec` and the file tools the same way if needed.

## Configuration reference

Variables can be set in `.env` or in the process environment; the environment takes
precedence. The `.env` template created by `init` describes each option.

| Variable | Default | Meaning |
|---|---|---|
| `PROXMOX_HOST` | none | `host` or `host:port` (port 8006 by default) |
| `PROXMOX_TOKEN_ID`, `PROXMOX_TOKEN_SECRET` | none | API token |
| `PROXMOX_TLS_FINGERPRINT`, `PROXMOX_TLS_CA_FILE`, `PROXMOX_TLS_INSECURE` | system store | TLS verification, in this order of precedence |
| `PROXMOX_MODE` | read-only | `write` registers the write tools |
| `PROXMOX_EXEC` | disabled | `enabled` registers the guest command tools (write mode only) |
| `PROXMOX_TOOLSETS` | all | tool groups to register, see [Tool groups](#tool-groups) |
| `PROXMOX_ALLOWED_VMIDS`, `PROXMOX_DENIED_VMIDS` | none | VMID lists for write operations |
| `PROXMOX_EXTRA_PROTECTED_PATHS` | none | additional path patterns treated as critical |
| `PROXMOX_CRITICAL_FILE` | `critical.env` next to `.env` | another flag file |
| `PROXMOX_SSH_USER`, `PROXMOX_SSH_PORT`, `PROXMOX_SSH_KEY` | `root`, 22, `ssh/id_ed25519` | SSH connection |
| `PROXMOX_SSH_HOST_KEY`, `PROXMOX_SSH_ALLOWED_IP` | none | pinned node host key; your IP address for the key restriction |
| `PROXMOX_EXEC_TIMEOUT`, `PROXMOX_EXEC_MAX_OUTPUT` | 60 s, 64 KiB | limits for guest commands |
| `PROXMOX_AUDIT_ENABLED`, `PROXMOX_AUDIT_LOG` | on, state directory | audit log |
| `PROXMOX_TIMEOUT`, `PROXMOX_MAX_RETRIES`, `PROXMOX_CACHE_TTL` | 15 s, 2, 5 s | API client |
| `LOG_LEVEL` | `INFO` | log level; logs always go to stderr |

## Command line

| Command | Purpose |
|---|---|
| `proxmox-model-context-protocol` | run the MCP server on stdio (same as `serve`) |
| `... init` | create the configuration directory with `.env` and `critical.env` |
| `... config [--open]` | show the configuration directory, optionally open it |
| `... fingerprint` | print the node certificate SHA-256 |
| `... check` | check the connection, TLS, privileges and SSH |
| `... tools` | list the registered tools |
| `... call <tool> '<json>'` | call a tool from the terminal |
| `... ssh-setup [--append-env]` | create the SSH key and pin the node host key |
| `... ssh-guard` | print the SSH guard and install steps |
| `... ssh-account [--name NAME]` | print the script for a dedicated SSH account |
| `... mcpb [--output DIR]` | write the Claude Desktop extension for this version |
| `... migrate [--apply]` | move files from an older installation that kept them in a source checkout |

Example: `proxmox-model-context-protocol call pve_list_vms '{}'`. Write tools in the
terminal need `PROXMOX_MODE=write` in the environment.

## Limitations

- Tested only on single-node Proxmox VE 9.1 and 9.2. The API tools take a node
  argument, but multi-node clusters have not been tested. Container commands and node
  upgrades reach only the node at `PROXMOX_HOST`.
- Commands in VMs work only in Linux guests.
- Proxmox Backup Server has no dedicated tools; a PBS storage can still be used like
  any other storage.
- The token's privileges are not a safety control; the local safeguards are.
- Guest lists come from a Proxmox cache that refreshes every few seconds. After a state
  change, use `pve_vm_config`. The server itself checks the live status before acting.

## Security and license

`SECURITY.md` describes the threat model and how to report a vulnerability.
`CHANGELOG.md` lists changes. Licensed under the Apache License 2.0 (`LICENSE`).

Copyright 2026 Jakub Krajewski. Contact: MCP.Proxmox@gmail.com.

This software, its tests and documentation were written with substantial help from an
AI system (Claude, by Anthropic). The author directed, reviewed and tested the work. See
`NOTICE` (Article 50 of Regulation (EU) 2024/1689, the EU AI Act).
