All projects

AI agents & MCP

Proxmox MCP

Run Proxmox VE from any AI client.

Production-grade MCP server with 27 tools for nodes, VMs, containers, storage and snapshots. Destructive actions are opt-in; stdio, SSE and HTTP transports.

Why I built it

I wanted to ask an AI which VM was eating my disk and have it actually check. A small Go server with a guard in front of destructive actions was the simplest way to get there.

Architecture

How it fits together

AI client

  • Claude Desktop

  • Cursor, Continue

  • Your own agent

proxmox-mcp

  • 27 tools

    VMs, LXCs, storage, snapshots

  • Destructive-action guard

    off unless enabled

  • API token auth

Proxmox VE

  • Nodes and guests

  • Storage

  • Snapshots and backups

Documentation

From the README

Open on GitHub

A production-grade Model Context Protocol (MCP) server written in Go that exposes 27 tools for full Proxmox VE administration. Connect any MCP-compatible AI client — Claude Desktop, Cursor, Continue, or your own — and manage your entire Proxmox infrastructure through natural language.

✨ Features

  • 🔐 API Token auth — no username/password in config, zero session management
  • 🛡️ Destructive-operation guard — stop, delete, rollback gated behind a single env flag
  • 📡 Three transports — stdio (Claude Desktop), sse, and streamable http
  • 📝 Structured logging — JSON or console output via go.uber.org/zap
  • ⚙️ 12-factor config — every setting is an environment variable, no config file required
  • 🐳 Scratch Docker image — zero-dependency binary, minimal attack surface
  • 🔄 Context-aware — every Proxmox call is cancellable via context.Context
  • 🏗️ Scalable architecture — add new tool groups with a single file + one registration call

📋 Tool Reference

Cluster (3 tools)

ToolDescription
get_cluster_statusOverall cluster health, quorum, node count
get_cluster_resourcesAll resources (VMs, containers, storage, nodes) with optional type filter
get_proxmox_versionProxmox VE server version string

Nodes (3 tools)

ToolDescription
list_nodesAll nodes with CPU, memory, and disk metrics
get_node_statusDetailed runtime status for a single node
get_node_storageAll storage pools on a node with usage statistics

QEMU Virtual Machines (14 tools)

ToolDestructiveDescription
list_vmsList all VMs on a node
get_vm_statusRuntime status of a specific VM
start_vmPower on a stopped or paused VM
shutdown_vmGraceful ACPI shutdown
reboot_vmACPI reboot signal
suspend_vmPause/freeze a running VM
resume_vmResume a paused VM
stop_vm✓Force-stop (power cord pull)
delete_vm✓Permanently delete VM and disks
clone_vmFull or linked clone
list_vm_snapshotsList all snapshots
create_vm_snapshotCreate a new snapshot
rollback_vm_snapshot✓Rollback to a snapshot
delete_vm_snapshot✓Delete a snapshot

LXC Containers (6 tools)

ToolDestructiveDescription
list_containersList all containers on a node
get_container_statusRuntime status of a container
start_containerStart a stopped container
shutdown_containerGraceful init shutdown
stop_container✓Force-stop a container
delete_container✓Delete container and its storage

Storage (2 tools)

ToolDescription
list_node_storageAll storage pools with total/used/available space
get_storage_detailDetailed info for a specific storage pool

🏗️ Project Structure

proxmox-mcp/
├── cmd/
│   └── server/
│       └── main.go              # Entry point — wiring, transport, graceful shutdown
├── internal/
│   ├── config/
│   │   └── config.go            # Viper-based config with full validation
│   ├── logger/
│   │   └── logger.go            # Structured zap logger wrapper
│   ├── proxmox/
│   │   └── client.go            # Proxmox API client wrapper (all methods)
│   └── tools/
│       ├── helpers.go           # Shared arg/response helpers + security guard
│       ├── register.go          # RegisterAll() — single entry point for all tools
│       ├── cluster.go           # Cluster tool handlers
│       ├── nodes.go             # Node tool handlers
│       ├── vms.go               # QEMU VM tool handlers
│       ├── containers.go        # LXC container tool handlers
│       └── storage.go           # Storage tool handlers
├── go.mod
├── go.sum
├── Makefile                     # Unix build targets
├── build.ps1                    # Windows PowerShell build script
├── Dockerfile                   # Multi-stage scratch image
└── README.md

🚀 Quick Start

1. Prerequisites

2. Create a Proxmox API Token

In the Proxmox web UI, navigate to:
Datacenter → Permissions → API Tokens → Add

User:                    root@pam
Token ID:                mcp
Privilege Separation:    unchecked (or configure explicit ACLs below)

💡 Least-privilege tip: Instead of root@pam, create a dedicated user (mcpuser@pam), assign the PVEAdmin role, and scope it to specific pools or nodes.

3. Clone and Build

git clone https://github.com/yourorg/proxmox-mcp.git
cd proxmox-mcp
go mod tidy

Linux / macOS:

make build
# Binary: ./bin/proxmox-mcp

Windows (PowerShell):

# Allow scripts (run once in admin PowerShell)
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned

.\build.ps1 build
# Binary: .\bin\proxmox-mcp.exe

Windows (CMD):

set CGO_ENABLED=0
go build -ldflags="-s -w" -o .\bin\proxmox-mcp.exe .\cmd\server

4. Run the Server

# Linux / macOS
export PROXMOX_MCP_PROXMOX_BASE_URL=https://192.168.1.10:8006/api2/json
export PROXMOX_MCP_PROXMOX_TOKEN_ID=root@pam!mcp
export PROXMOX_MCP_PROXMOX_SECRET=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
export PROXMOX_MCP_PROXMOX_INSECURE_SKIP_VERIFY=true   # only for self-signed certs
./bin/proxmox-mcp
# Windows PowerShell
$env:PROXMOX_MCP_PROXMOX_BASE_URL             = "https://192.168.1.10:8006/api2/json"
$env:PROXMOX_MCP_PROXMOX_TOKEN_ID             = "root@pam!mcp"
$env:PROXMOX_MCP_PROXMOX_SECRET               = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$env:PROXMOX_MCP_PROXMOX_INSECURE_SKIP_VERIFY = "true"
.\bin\proxmox-mcp.exe

⚙️ Configuration

All configuration is done via environment variables. No config file is required.

Environment VariableDefaultRequiredDescription
PROXMOX_MCP_PROXMOX_BASE_URLhttps://localhost:8006/api2/json✓Full Proxmox API URL
PROXMOX_MCP_PROXMOX_TOKEN_ID—✓API token ID (user@realm!tokenname)
PROXMOX_MCP_PROXMOX_SECRET—✓API token secret UUID
PROXMOX_MCP_PROXMOX_INSECURE_SKIP_VERIFYfalseSkip TLS verification (dev/self-signed only)
PROXMOX_MCP_PROXMOX_REQUEST_TIMEOUT30sPer-request HTTP timeout
PROXMOX_MCP_SERVER_TRANSPORTstdiostdio | sse | http
PROXMOX_MCP_SERVER_LISTEN_ADDR:8080Bind address for SSE/HTTP transports
PROXMOX_MCP_SERVER_NAMEProxmox MCP ServerAdvertised server name
PROXMOX_MCP_SERVER_VERSION1.0.0Advertised version string
PROXMOX_MCP_SERVER_GRACEFUL_SHUTDOWN_TIMEOUT30sShutdown wait time
PROXMOX_MCP_SECURITY_ALLOW_DESTRUCTIVEfalseEnable destructive operations
PROXMOX_MCP_SECURITY_ALLOWED_NODES(all)Comma-separated node whitelist
PROXMOX_MCP_LOG_LEVELinfodebug | info | warn | error
PROXMOX_MCP_LOG_FORMATjsonjson | console
PROXMOX_MCP_CONFIG_FILE—Optional path to YAML/TOML/JSON config file

Using a Config File (Optional)

# proxmox-mcp.yaml
server:
  transport: sse
  listen_addr: ":8080"

proxmox:
  base_url: "https://192.168.1.10:8006/api2/json"
  token_id: "root@pam!mcp"
  secret: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  insecure_skip_verify: true
  request_timeout: 30s

security:
  allow_destructive: false

log:
  level: info
  format: console
PROXMOX_MCP_CONFIG_FILE=./proxmox-mcp.yaml ./bin/proxmox-mcp

🔌 Client Integration

Claude Desktop

Edit ~/.config/claude/claude_desktop_config.json (Linux/macOS):

{
  "mcpServers": {
    "proxmox": {
      "command": "/absolute/path/to/proxmox-mcp",
      "env": {
        "PROXMOX_MCP_PROXMOX_BASE_URL": "https://192.168.1.10:8006/api2/json",
        "PROXMOX_MCP_PROXMOX_TOKEN_ID": "root@pam!mcp",
        "PROXMOX_MCP_PROXMOX_SECRET": "your-secret-uuid-here",
        "PROXMOX_MCP_PROXMOX_INSECURE_SKIP_VERIFY": "true",
        "PROXMOX_MCP_LOG_FORMAT": "console"
      }
    }
  }
}

Windows path — edit %APPDATA%\Claude\claude_desktop_config.json:

{
  "mcpServers": {
    "proxmox": {
      "command": "C:\\path\\to\\proxmox-mcp\\bin\\proxmox-mcp.exe",
      "env": {
        "PROXMOX_MCP_PROXMOX_BASE_URL": "https://192.168.1.10:8006/api2/json",
        "PROXMOX_MCP_PROXMOX_TOKEN_ID": "root@pam!mcp",
        "PROXMOX_MCP_PROXMOX_SECRET": "your-secret-uuid-here",
        "PROXMOX_MCP_PROXMOX_INSECURE_SKIP_VERIFY": "true"
      }
    }
  }
}

Cursor / Continue

Point the MCP server config to the binary path and supply the same environment variables as above under your IDE's MCP server settings.

SSE / HTTP Mode (Remote Access)

Start the server in sse or http transport for network-accessible deployments:

PROXMOX_MCP_SERVER_TRANSPORT=sse \
PROXMOX_MCP_SERVER_LISTEN_ADDR=:8080 \
PROXMOX_MCP_PROXMOX_BASE_URL=https://192.168.1.10:8006/api2/json \
PROXMOX_MCP_PROXMOX_TOKEN_ID=root@pam!mcp \
PROXMOX_MCP_PROXMOX_SECRET=your-secret-uuid \
./bin/proxmox-mcp

Then configure your MCP client to connect to http://your-server:8080.

🐳 Docker

Build

docker build -t proxmox-mcp:latest .

Run (SSE mode)

docker run -d \
  --name proxmox-mcp \
  -p 8080:8080 \
  -e PROXMOX_MCP_SERVER_TRANSPORT=sse \
  -e PROXMOX_MCP_SERVER_LISTEN_ADDR=:8080 \
  -e PROXMOX_MCP_PROXMOX_BASE_URL=https://192.168.1.10:8006/api2/json \
  -e PROXMOX_MCP_PROXMOX_TOKEN_ID=root@pam!mcp \
  -e PROXMOX_MCP_PROXMOX_SECRET=your-secret-uuid \
  -e PROXMOX_MCP_PROXMOX_INSECURE_SKIP_VERIFY=true \
  proxmox-mcp:latest

Docker Compose

version: "3.9"
services:
  proxmox-mcp:
    image: proxmox-mcp:latest
    restart: unless-stopped
    ports:
      - "8080:8080"
    environment:
      PROXMOX_MCP_SERVER_TRANSPORT: sse
      PROXMOX_MCP_SERVER_LISTEN_ADDR: ":8080"
      PROXMOX_MCP_PROXMOX_BASE_URL: "https://192.168.1.10:8006/api2/json"
      PROXMOX_MCP_PROXMOX_TOKEN_ID: "root@pam!mcp"
      PROXMOX_MCP_PROXMOX_SECRET: "your-secret-uuid"
      PROXMOX_MCP_PROXMOX_INSECURE_SKIP_VERIFY: "true"
      PROXMOX_MCP_LOG_FORMAT: "json"

🔒 Security

Destructive Operations

All destructive operations are disabled by default. They require an explicit opt-in:

PROXMOX_MCP_SECURITY_ALLOW_DESTRUCTIVE=true

The following tools are gated behind this flag:

  • stop_vm (force power-off)
  • delete_vm
  • rollback_vm_snapshot
  • delete_vm_snapshot
  • stop_container (force)
  • delete_container

Node Allowlist

Restrict operations to specific nodes:

PROXMOX_MCP_SECURITY_ALLOWED_NODES=pve01,pve02

API Token Best Practices

  1. Never use root@pam in production. Create a dedicated mcpuser@pam account.
  2. Assign the minimum required role — PVEAdmin scoped to specific pools, or custom roles using just the ACLs you need (e.g. VM.PowerMgmt, VM.Snapshot).
  3. Rotate the token secret periodically.
  4. Do not pass secrets via command-line arguments — use environment variables or a secrets manager.

TLS

Set PROXMOX_MCP_PROXMOX_INSECURE_SKIP_VERIFY=false (the default) and install a valid certificate on your Proxmox node in production. Let's Encrypt via ACME is supported natively by Proxmox VE.

🛠️ Development

Prerequisites

go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest

Makefile Targets (Linux/macOS)

make build     # Compile binary to ./bin/
make test      # Run tests with race detector
make lint      # Run golangci-lint
make clean     # Remove ./bin/
make all       # lint + test + build

PowerShell Targets (Windows)

.\build.ps1 build   # Compile binary to .\bin\
.\build.ps1 test    # Run tests with race detector
.\build.ps1 lint    # Run golangci-lint
.\build.ps1 clean   # Remove .\bin\
.\build.ps1 all     # lint + test + build

Adding a New Tool Group

  1. Create internal/tools/mygroup.go with a RegisterMyGroupTools(s, h) function
  2. Add RegisterMyGroupTools(s, h) to internal/tools/register.go
  3. Add corresponding methods to internal/proxmox/client.go

That's it — no other wiring required.

Adding a New Proxmox API Method

  1. Add the method to internal/proxmox/client.go following the existing pattern
  2. Add the tool handler in the appropriate internal/tools/*.go file
  3. Register the tool inside the corresponding Register*Tools() function

🔭 Observability

Log Levels

PROXMOX_MCP_LOG_LEVEL=debug   # All requests + arg tracing
PROXMOX_MCP_LOG_LEVEL=info    # Lifecycle events + tool invocations (default)
PROXMOX_MCP_LOG_LEVEL=warn    # Destructive operations + warnings only
PROXMOX_MCP_LOG_LEVEL=error   # Errors only

Log Formats

PROXMOX_MCP_LOG_FORMAT=json     # Structured JSON (default, ideal for log aggregators)
PROXMOX_MCP_LOG_FORMAT=console  # Human-readable coloured output for local dev

Sample Log Output (console format)

2026-04-09T00:30:01.123+0530  INFO  starting Proxmox MCP Server  {"name": "Proxmox MCP Server", "transport": "stdio"}
2026-04-09T00:30:01.456+0530  INFO  connected to Proxmox VE      {"url": "https://192.168.1.10:8006/api2/json"}
2026-04-09T00:30:01.457+0530  INFO  tools registered             {"allow_destructive": false}
2026-04-09T00:30:05.012+0530  INFO  tool: list_nodes
2026-04-09T00:30:06.234+0530  INFO  tool: start_vm               {"node": "pve01", "vmid": 101}
2026-04-09T00:30:10.789+0530  WARN  tool: stop_vm (force)        {"node": "pve01", "vmid": 101}

📦 Dependencies

PackageVersionPurpose
luthermonson/go-proxmoxv0.2.0Proxmox VE API client
mark3labs/mcp-gov0.32.0MCP server framework
spf13/viperv1.19.0Configuration management
go.uber.org/zapv1.27.0Structured logging

🗺️ Roadmap

  • VM Config editor — update CPU, memory, network via update_vm_config
  • Backup management — trigger vzdump backups and list backup jobs
  • User & ACL management — create users, assign roles, manage permissions
  • Network SDN — manage VNets, zones, and VLAN mappings
  • Firewall rules — manage node and VM-level firewall rules
  • ISO / Template management — download ISOs, list templates
  • HA management — configure and query HA groups and resources
  • Prometheus metrics endpoint — expose tool call latency and error rates

🐛 Troubleshooting

ErrorCauseFix
connecting to ... : unauthorizedWrong token ID or secretDouble-check TOKEN_ID format: user@realm!tokenname
x509: certificate signed by unknown authoritySelf-signed Proxmox certSet PROXMOX_MCP_PROXMOX_INSECURE_SKIP_VERIFY=true (dev only)
operation "delete_vm" is disabledDestructive guardSet PROXMOX_MCP_SECURITY_ALLOW_DESTRUCTIVE=true
go: command not found (Windows)Go not in PATHRestart PowerShell after installing Go
go mod tidy fails first runModule cache raceRun go mod tidy a second time
Access denied on build.ps1Execution policyRun Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
Server starts but no tools appearWrong transport in clientMatch client URL scheme to PROXMOX_MCP_SERVER_TRANSPORT

🙏 Acknowledgements

AI agents & MCP

More like this