Skip to content

Latest commit

 

History

History
254 lines (186 loc) · 8.74 KB

File metadata and controls

254 lines (186 loc) · 8.74 KB

Operator Guide

This guide covers how to configure, run, and operate ProxmoxMCP-Plus.

Runtime Modes

ProxmoxMCP-Plus can be used in two main ways:

  • MCP stdio mode: assistants launch the server directly and call tools over MCP
  • MCP Streamable HTTP mode: the server exposes a native MCP endpoint at /mcp
  • OpenAPI mode: FastAPI wraps the MCP server and exposes HTTP endpoints for other clients

The core tool set is the same in both modes. The difference is only the transport.

Prerequisites

  • Python 3.11 or newer
  • Access to a Proxmox VE API endpoint
  • A Proxmox API token with the permissions your workflows need
  • Network access from the machine running ProxmoxMCP-Plus to the Proxmox API

Optional:

  • SSH access from the MCP host to Proxmox nodes if you want LXC command execution tools

Configuration File

The main config file is proxmox-config/config.json.

Start from the example:

cp proxmox-config/config.example.json proxmox-config/config.json

The main sections are:

  • proxmox: host, port, TLS verification, service type
  • api_tunnel: optional SSH local forward for the Proxmox API
  • auth: Proxmox API user and token
  • logging: log level, format, optional log file
  • mcp: MCP host, port, transport, and optional transport Host/Origin allowlists
  • security: currently includes dev_mode
  • jobs: SQLite path for persistent job tracking
  • command_policy: rules for execute_* tools and high-risk mutating operations
  • ssh: optional SSH settings for LXC command execution

Environment Variable Fallback

If PROXMOX_MCP_CONFIG is not set or the file is missing, the loader falls back to environment variables.

Common variables:

  • PROXMOX_HOST
  • PROXMOX_PORT
  • PROXMOX_USER
  • PROXMOX_TOKEN_NAME
  • PROXMOX_TOKEN_VALUE
  • PROXMOX_VERIFY_SSL
  • PROXMOX_SERVICE
  • LOG_LEVEL
  • MCP_HOST
  • MCP_PORT
  • MCP_TRANSPORT
  • MCP_DNS_REBINDING_PROTECTION
  • MCP_ALLOWED_HOSTS
  • MCP_ALLOWED_ORIGINS
  • PROXMOX_DEV_MODE
  • COMMAND_POLICY_MODE
  • PROXMOX_JOBS_SQLITE_PATH

Minimal Local Start

uv venv
uv pip install -e ".[dev]"
$env:PROXMOX_MCP_CONFIG="D:\\PycharmProject\\ProxmoxMCP-Plus\\proxmox-config\\config.json"
python main.py

If startup succeeds, the server stays attached to stdio and waits for MCP clients.

Native MCP Streamable HTTP Mode

Set the MCP transport to STREAMABLE_HTTP and bind to an address reachable by the client:

MCP_API_KEY="$(openssl rand -hex 32)" \
MCP_HOST=0.0.0.0 MCP_PORT=8000 MCP_TRANSPORT=STREAMABLE_HTTP \
python -m proxmox_mcp.server

The MCP endpoint is:

http://<host>:8000/mcp

This is the correct target for MCP clients that support Streamable HTTP. It is separate from the OpenAPI service on port 8811.

Clients should send Authorization: Bearer <MCP_API_KEY>. If MCP_API_KEY is unset, the endpoint remains unauthenticated for backward compatibility and the server logs a security warning. PROXMOX_API_KEY does not protect this endpoint.

For reverse proxy deployments, configure the external hostnames explicitly instead of disabling DNS rebinding protection:

MCP_HOST=0.0.0.0 \
MCP_PORT=8000 \
MCP_TRANSPORT=STREAMABLE_HTTP \
MCP_API_KEY="$MCP_API_KEY" \
MCP_DNS_REBINDING_PROTECTION=true \
MCP_ALLOWED_HOSTS=mcp.example.com:*,localhost:* \
MCP_ALLOWED_ORIGINS=https://mcp.example.com \
python -m proxmox_mcp.server

OpenAPI Mode

You can run the OpenAPI wrapper directly:

export PROXMOX_API_KEY="$(openssl rand -hex 32)"
python -m proxmox_mcp.openapi_proxy --host 0.0.0.0 --port 8811 -- python main.py

OpenAPI mode refuses to start without PROXMOX_API_KEY unless PROXMOX_ALLOW_NO_AUTH=true is set for local unauthenticated development. HTTP clients should send the key as Authorization: Bearer <PROXMOX_API_KEY>.

Available routes:

  • / returns basic service metadata
  • /docs serves Swagger UI
  • /openapi.json serves the generated schema
  • /livez returns minimal unauthenticated process liveness
  • /readyz returns 503 until the proxy is connected to the MCP backend, then 200
  • /health is a readiness alias for /readyz
  • /metrics exposes Prometheus-style request metrics
  • /jobs exposes direct job query and control routes when a local JobStore is available

Docker Compose Deployment

The repository includes docker-compose.yml and Dockerfile.

Default Compose behavior:

  • Builds the local image
  • Mounts ./proxmox-config read-only into /app/proxmox-config
  • Exposes 8811
  • Keeps OpenAPI mode as the default Docker runtime
  • Sets PROXMOX_MCP_CONFIG=/app/proxmox-config/config.json
  • Requires PROXMOX_API_KEY from your shell or Compose .env file
  • Adds a container liveness health check against http://localhost:8811/livez

Start it with:

export PROXMOX_API_KEY="${PROXMOX_API_KEY:-$(openssl rand -hex 32)}"
docker compose up -d --build

To run the native MCP Streamable HTTP service from Docker Compose:

export MCP_API_KEY="${MCP_API_KEY:-$(openssl rand -hex 32)}"
docker compose --profile mcp-http up -d proxmox-mcp-http

Then connect Streamable HTTP MCP clients to http://<docker-host>:8000/mcp and send Authorization: Bearer <MCP_API_KEY>.

The same image can also be run directly:

docker run --rm -p 8000:8000 \
  -e PROXMOX_MCP_MODE=mcp-http \
  -e MCP_HOST=0.0.0.0 \
  -e MCP_PORT=8000 \
  -e MCP_TRANSPORT=STREAMABLE_HTTP \
  -e MCP_API_KEY="$MCP_API_KEY" \
  -v "$(pwd)/proxmox-config/config.json:/app/proxmox-config/config.json:ro" \
  ghcr.io/rekklesna/proxmoxmcp-plus:latest

Operating Checklist

Before exposing the service to users:

  • Confirm the Proxmox API token has only the permissions you intend to expose
  • Keep proxmox.verify_ssl=true unless you are explicitly in development mode
  • Keep security.dev_mode=false outside local testing
  • Set PROXMOX_API_KEY for OpenAPI mode; only use PROXMOX_ALLOW_NO_AUTH=true for local unauthenticated development
  • Set MCP_API_KEY for every remotely reachable native MCP HTTP deployment
  • For MCP HTTP behind a proxy, keep MCP_DNS_REBINDING_PROTECTION=true and set MCP_ALLOWED_HOSTS to the exact public hostnames
  • Restrict ingress to networks you control
  • Monitor /livez for process liveness and authenticated /health or /readyz for backend readiness
  • Monitor /metrics if you scrape the service with Prometheus-compatible tooling
  • Persist the configured jobs.sqlite_path on durable storage if job history matters across restarts
  • Store logs somewhere persistent if you need auditability

Command Execution Features

There are two command execution paths:

  • execute_vm_command: uses QEMU Guest Agent inside VMs
  • execute_container_command: uses SSH to the Proxmox node and then pct exec inside containers

Container command execution is optional and only appears when an ssh section exists in the config.

For setup details, see Container Command Execution.

Long-Running Job Operations

Asynchronous Proxmox actions now register a persistent job record. This applies to operations such as:

  • VM create, start, stop, shutdown, reset, and delete
  • container create, start, stop, restart, and delete
  • snapshot create, delete, and rollback
  • backup create, restore, and delete
  • ISO download and delete

Operational guidance:

  • Treat job_id as the stable identifier you hand back to users, agents, and automation systems.
  • Treat task_id or UPID as Proxmox internals that may change after a retry.
  • Keep jobs.sqlite_path on a persistent volume in Docker or any long-lived service deployment.
  • Use /jobs/{job_id}/poll or MCP poll_job to refresh progress from Proxmox.
  • Use /jobs/{job_id}/retry only after reviewing last_error, result, and audit_log.

First Verification Flow

After deployment, test in this order:

  1. Start the service and confirm there are no config validation errors
  2. Call read-only tools first: get_nodes, get_vms, get_storage, get_cluster_status
  3. In OpenAPI mode, confirm /livez responds and authenticated /health and /docs requests work
  4. Confirm /jobs responds if you expect persistent job tracking
  5. If you enabled SSH-backed container commands, confirm execute_container_command appears in the tool list
  6. Only then test mutating tools such as create, start, delete, snapshot, or backup

Logs and Health

  • Application logging is configured under the logging section
  • main.py prints early startup messages to stderr to make bootstrap failures visible
  • The OpenAPI wrapper reports degraded until it is connected to the MCP subprocess
  • authenticated /health reports whether direct job routes are enabled in the OpenAPI process

Related Pages