Files
proxmox-mcp-custom/IMPLEMENTATION.md
Ben 9c7e2d41dc
All checks were successful
Build and Push Proxmox MCP Docker Image / build (push) Successful in 7s
Initial commit: Custom Proxmox MCP with SSE wrapper
2025-12-14 20:52:58 +00:00

4.8 KiB

Custom Proxmox MCP Server Implementation

Architecture Overview

This project implements a Model Context Protocol (MCP) server for Proxmox VE using a "Hybrid" design pattern. It combines specific, high-value tools with raw API access to ensure both usability and comprehensive coverage.

Core Components

  1. Transport:

    • Protocol: Server-Sent Events (SSE) over HTTP.
    • Framework: mcp (official Python SDK) using FastMCP.
    • Server: uvicorn (ASGI server).
    • Host Binding: 0.0.0.0:8000 (exposed for Docker).
  2. Proxmox Integration:

    • Client Library: proxmoxer (Python wrapper for Proxmox API).
    • Authentication: API Token or Username/Password.
      • User: Must be full user@realm (e.g., proxmox-mcp@pam).
      • Token ID: Just the token name (e.g., token), NOT the full ID.
    • SSL: Configurable verification (default false for homelabs).
  3. Deployment:

    • Container: Docker (multi-stage build with uv).
    • Registry: Gitea Container Registry (gitea.ext.ben.io).
    • Orchestration: Portainer (Docker Compose stack).
    • CI/CD: Gitea Actions (build & push on commit).

Current Status (Dec 14, 2025)

  • Infrastructure: Gitea build pipeline and Docker registry are fully operational.
  • Server: proxmox-mcp-custom container is running and accessible via Gemini CLI.
  • Connectivity: Direct curl tests confirmed Proxmox API connectivity and credential validity.
  • Resolved Issues:
    • Host Header: Added TransportSecuritySettings with MCP_ALLOWED_HOSTS env var to allow reverse proxy access.
    • Token Auth: Fixed user string format (was incorrectly user@token_id, now just user).
    • Local Testing: Added docker-compose.dev.yml, Makefile, and .env support for local development.

The Hybrid Tool Strategy

Instead of wrapping every Proxmox API endpoint (of which there are hundreds), we expose two layers of tools:

Layer 1: Curated Tools (High Frequency)

These tools simplify common tasks for the LLM.

  • list_nodes(): Returns cluster node status.
  • get_cluster_resources(): Returns all VMs, LXCs, and storage.

Layer 2: Raw Access (The "Escape Hatch")

  • proxmox_api_call(path, method, data): A generic tool that allows the LLM to construct any API call supported by proxmoxer.
    • Example: path="nodes/pve1/qemu/100/status/start", method="POST"
    • Benefit: Zero maintenance. If Proxmox adds a feature, the LLM can use it immediately without code changes.

Current Implementation Details

server.py

  • Uses mcp.server.fastmcp.FastMCP to define the server and tools.
  • Connects to Proxmox using proxmoxer.ProxmoxAPI.
  • Exposes mcp.sse_app to uvicorn for execution.
  • Configures TransportSecuritySettings for DNS rebinding protection with allowed hosts.

Challenges & Workarounds

  • Host Header Validation: Resolved by configuring TransportSecuritySettings with MCP_ALLOWED_HOSTS.
  • Dependency Management: We use uv for fast, reliable builds in Docker.
  • API Client: proxmoxer requires requests (added to pyproject.toml).

Next Steps

  1. Resolve the Invalid Host header error - Fixed with TransportSecuritySettings.
  2. Update Portainer stack with corrected PROXMOX_TOKEN_ID (just token name, not full ID).
  3. Connect Gemini CLI via https://proxmox-mcp.ext.ben.io/sse.

Local Testing Challenges

A significant challenge in this development environment is the lack of direct local testing capabilities. Due to the nature of operating within a sandboxed agent and the separation between the development VM (where this agent runs) and the target Docker/Portainer host, the standard iterative development loop (code -> test -> debug) is heavily impacted:

  • No Direct uvicorn Execution: I cannot directly run the Python server locally to quickly test changes.
  • Remote Docker Environment: Each code change requires:
    1. Committing and pushing to Gitea.
    2. Waiting for Gitea Actions to build and push the Docker image.
    3. Redeploying the Docker stack on the Portainer host.
    4. Analyzing remote container logs for feedback.
  • Limited Debugging: The inability to attach a debugger or inspect live execution locally forces a heavy reliance on log analysis.
  • Slow Feedback Loop: This multi-step remote process introduces significant delays, prolonging the time it takes to identify and fix issues (as evidenced by the numerous iterations for portainer-mcp and proxmox-mcp-custom).

This necessitates careful reasoning, documentation review, and a systematic approach to debugging, often leading to more turns than would be typical in a local development setup.