diff --git a/src/proxmox_mcp/server.py b/src/proxmox_mcp/server.py index efcd9be..faf93eb 100644 --- a/src/proxmox_mcp/server.py +++ b/src/proxmox_mcp/server.py @@ -1,10 +1,7 @@ from __future__ import annotations import json -import os -from typing import Any -import httpx from mcp.server.fastmcp import FastMCP from proxmox_mcp import __version__ @@ -16,144 +13,18 @@ mcp = FastMCP( "proxmox", instructions=( "Proxmox VE 9 MCP. Saved targets load from PROXMOX_TARGETS_PATH. " - "Call proxmox_connect(url, token_id, token_secret, name=...) or proxmox_use_target. " - "Exec tools require PROXMOX_ALLOW_WRITES=true." + "Call proxmox_connect(url, token_id, token_secret, verify_ssl=false, name=...) " + "or proxmox_use_target. Exec tools require PROXMOX_ALLOW_WRITES=true." ), ) -def _get_active_client() -> httpx.Client | None: - """Return an authenticated httpx client for the active target, or None.""" - target = registry.active() - if not target: - return None - verify = os.environ.get("PROXMOX_VERIFY_SSL", "true").lower() in ("1", "true", "yes") - client = httpx.Client( - base_url=target.url, - verify=verify, - headers={"Authorization": f"PVEAPIToken={target.token_id}={target.token_secret}"}, - timeout=30.0, - ) - return client - - -@mcp.tool() -def proxmox_list_all_guests() -> str: - """List all QEMU VMs and LXC containers across all Proxmox cluster nodes. - - This tool uses the cluster resources endpoint, which does not require a node - parameter. It returns a combined list of all VMs and containers regardless - of which node they reside on. - """ - client = _get_active_client() - if not client: - return json.dumps({"error": "No active target. Call proxmox_connect or proxmox_use_target first."}) - - try: - # Query cluster resources for both VMs and containers - resp = client.get("/api2/json/cluster/resources", params={"type": "vm"}) - resp.raise_for_status() - data = resp.json().get("data", []) - - # Filter: vmid with status and type - guests = [] - for entry in data: - if entry.get("type") in ("qemu", "lxc"): - guests.append({ - "vmid": entry.get("vmid"), - "node": entry.get("node"), - "name": entry.get("name"), - "type": entry.get("type"), - "status": entry.get("status"), - "mem": entry.get("mem"), - "maxmem": entry.get("maxmem"), - "cpu": entry.get("cpu"), - "maxcpu": entry.get("maxcpu"), - "disk": entry.get("disk"), - "maxdisk": entry.get("maxdisk"), - "uptime": entry.get("uptime"), - }) - return json.dumps(guests, indent=2) - except Exception as exc: - return json.dumps({"error": str(exc)}) - finally: - client.close() - - -@mcp.tool() -def proxmox_debug_guest_inventory(node: str | None = None) -> str: - """Return the raw JSON from the Proxmox API for debugging guest listing. - - If a node is given, queries /nodes/{node}/qemu and /nodes/{node}/lxc separately. - Otherwise, queries the cluster resources endpoint. - """ - client = _get_active_client() - if not client: - return json.dumps({"error": "No active target. Call proxmox_connect or proxmox_use_target first."}) - - try: - result = {} - if node: - # Per-node endpoints - for gtype in ("qemu", "lxc"): - resp = client.get(f"/api2/json/nodes/{node}/{gtype}") - resp.raise_for_status() - result[gtype] = resp.json().get("data", []) - else: - # Cluster resources - resp = client.get("/api2/json/cluster/resources", params={"type": "vm"}) - resp.raise_for_status() - result = resp.json() - return json.dumps(result, indent=2, default=str) - except Exception as exc: - return json.dumps({"error": str(exc)}) - finally: - client.close() - - -@mcp.tool() -def proxmox_list_qemu(node: str) -> str: - """List all QEMU VMs on a specific Proxmox node.""" - client = _get_active_client() - if not client: - return json.dumps({"error": "No active target. Call proxmox_connect or proxmox_use_target first."}) - - try: - resp = client.get(f"/api2/json/nodes/{node}/qemu") - resp.raise_for_status() - vms = resp.json().get("data", []) - return json.dumps(vms, indent=2) - except Exception as exc: - return json.dumps({"error": str(exc)}) - finally: - client.close() - - -@mcp.tool() -def proxmox_list_lxc(node: str) -> str: - """List all LXC containers on a specific Proxmox node.""" - client = _get_active_client() - if not client: - return json.dumps({"error": "No active target. Call proxmox_connect or proxmox_use_target first."}) - - try: - resp = client.get(f"/api2/json/nodes/{node}/lxc") - resp.raise_for_status() - lxcs = resp.json().get("data", []) - return json.dumps(lxcs, indent=2) - except Exception as exc: - return json.dumps({"error": str(exc)}) - finally: - client.close() - - @mcp.tool() def proxmox_get_config() -> str: - from proxmox_mcp.targets import registry - return json.dumps( { "allow_writes": settings.allow_writes, + "verify_ssl_default": settings.verify_ssl, "active_target": registry.active().name if registry.active() else None, "targets": registry.list(), "version": __version__,