Skip to main content
Glama
README.md
# 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:start -->
## Install in your agent

[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install_proxmox-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=proxmox&inputs=%5B%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22pve_host%22%2C%22description%22%3A%22Proxmox%20host%20or%20IP%22%2C%22password%22%3Afalse%7D%2C%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22pve_token_id%22%2C%22description%22%3A%22API%20token%20id%20%28user%40realm%21name%29%22%2C%22password%22%3Afalse%7D%2C%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22pve_token_secret%22%2C%22description%22%3A%22API%20token%20secret%22%2C%22password%22%3Atrue%7D%5D&config=%7B%22type%22%3A%22stdio%22%2C%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22git%2Bhttps%3A//github.com/bigbatmanorg/pve-mcp%40v0.1.0%22%2C%22pve-mcp%22%5D%2C%22env%22%3A%7B%22PVE_HOST%22%3A%22%24%7Binput%3Apve_host%7D%22%2C%22PVE_TOKEN_ID%22%3A%22%24%7Binput%3Apve_token_id%7D%22%2C%22PVE_TOKEN_SECRET%22%3A%22%24%7Binput%3Apve_token_secret%7D%22%7D%7D)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install_proxmox-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=proxmox&inputs=%5B%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22pve_host%22%2C%22description%22%3A%22Proxmox%20host%20or%20IP%22%2C%22password%22%3Afalse%7D%2C%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22pve_token_id%22%2C%22description%22%3A%22API%20token%20id%20%28user%40realm%21name%29%22%2C%22password%22%3Afalse%7D%2C%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22pve_token_secret%22%2C%22description%22%3A%22API%20token%20secret%22%2C%22password%22%3Atrue%7D%5D&config=%7B%22type%22%3A%22stdio%22%2C%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22git%2Bhttps%3A//github.com/bigbatmanorg/pve-mcp%40v0.1.0%22%2C%22pve-mcp%22%5D%2C%22env%22%3A%7B%22PVE_HOST%22%3A%22%24%7Binput%3Apve_host%7D%22%2C%22PVE_TOKEN_ID%22%3A%22%24%7Binput%3Apve_token_id%7D%22%2C%22PVE_TOKEN_SECRET%22%3A%22%24%7Binput%3Apve_token_secret%7D%22%7D%7D&quality=insiders)
[![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=proxmox&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJnaXQraHR0cHM6Ly9naXRodWIuY29tL2JpZ2JhdG1hbm9yZy9wdmUtbWNwQHYwLjEuMCIsInB2ZS1tY3AiXSwiZW52Ijp7IlBWRV9IT1NUIjoicHZlLmV4YW1wbGUubGFuIiwiUFZFX1RPS0VOX0lEIjoicm9vdEBwYW0hbWNwIiwiUFZFX1RPS0VOX1NFQ1JFVCI6Inh4eHh4eHh4LXh4eHgteHh4eC14eHh4LXh4eHh4eHh4eHh4eCJ9fQ%3D%3D)

It works with any MCP client that can start a stdio command. It needs [uv](https://docs.astral.sh/uv/). `uvx` fetches the pinned release, so no clone or virtualenv is needed. Pick your agent below.

| Variable | Meaning | Example |
|---|---|---|
| `PVE_HOST` | Proxmox host or IP | `pve.example.lan` |
| `PVE_TOKEN_ID` | API token id (user@realm!name) | `root@pam!mcp` |
| `PVE_TOKEN_SECRET` | API token secret | `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx` |

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-mcp` on PyPI. Install from this repository as shown, not with `pip 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.

<details>
<summary><b>Claude Code</b></summary>

```bash
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-mcp
```

</details>

<details>
<summary><b>Claude Desktop</b></summary>

Settings → Developer → Edit Config (`claude_desktop_config.json`):

```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"
      }
    }
  }
}
```

</details>

<details>
<summary><b>VS Code / GitHub Copilot</b></summary>

Use the button above, or add this to `.vscode/mcp.json` (workspace) or to the user `mcp.json` (command
*MCP: Open User Configuration*):

```json
{
  "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}"
      }
    }
  }
}
```

</details>

<details>
<summary><b>Cursor</b></summary>

Use the button above, or add this to `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (project):

```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"
      }
    }
  }
}
```

</details>

<details>
<summary><b>Windsurf</b></summary>

Add this to `~/.codeium/windsurf/mcp_config.json`:

```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"
      }
    }
  }
}
```

</details>

<details>
<summary><b>OpenAI Codex CLI</b></summary>

```bash
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-mcp
```

Or add this to `~/.codex/config.toml`:

```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" }
```

</details>

<details>
<summary><b>Gemini CLI</b></summary>

Add this to `~/.gemini/settings.json` (or to `.gemini/settings.json` in a project):

```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"
      }
    }
  }
}
```

</details>

<details>
<summary><b>DeepAgents</b></summary>

**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.

```json
{
  "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`):

```python
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())
```

</details>

<details>
<summary><b>Docker Agent</b></summary>

Save this as `agent.yaml`, then run `docker agent run agent.yaml`:

```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"
```

</details>

<details>
<summary><b>Hermes Agent</b></summary>

Add this to `~/.hermes/config.yaml`, then run `/reload-mcp` in a chat:

```yaml
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"
```

</details>

<details>
<summary><b>Cline / Roo Code / Kilo Code</b></summary>

MCP Servers → Configure (`cline_mcp_settings.json` / `mcp_settings.json`):

```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"
      }
    }
  }
}
```

</details>

<details>
<summary><b>Zed</b></summary>

Add this to `settings.json`:

```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"
      }
    }
  }
}
```

</details>

<details>
<summary><b>opencode</b></summary>

Add this to `opencode.json` (project) or `~/.config/opencode/opencode.json`:

```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
    }
  }
}
```

</details>

<details>
<summary><b>Goose</b></summary>

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`:

```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"
```

</details>

<details>
<summary><b>Other clients, a permanent install, a local checkout</b></summary>

Most clients take the standard `mcpServers` JSON shown for Claude Desktop. Some use `servers` instead.

To install once instead of fetching on each start:

```bash
uv tool install git+https://github.com/bigbatmanorg/pve-mcp@v0.1.0
```

then use `"command": "pve-mcp"`, `"args": []`.

From a checkout: `"command": "uv"`, `"args": ["run", "--directory", "/abs/path/pve-mcp", "pve-mcp"]`.

</details>

<!-- install:end -->

## Safety

| Setting | Effect |
|---|---|
| default | read-only: only GET calls are sent |
| `PVE_ALLOW_WRITES=true` | POST/PUT allowed |
| `confirm=true` (per call) | also required for DELETE, stop/reset, rollback, node power |
| `PVE_SSH_ENABLED=true` | enables `pve_node_ssh` (also needs writes) |

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 only

Lab 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.