# 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 (`user@pam!token_id`) or Username/Password. * **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). ## 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. ### Challenges & Workarounds * **Host Header Validation:** The `mcp` SDK enforces strict Host header checks by default. We are currently configuring `FastMCP` settings to allow external access (e.g., `proxmox-mcp.ext.ben.io`). * **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 by correctly configuring `mcp.settings.allowed_hosts` or middleware. 2. Deploy the final image to Portainer. 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.