fix: implement proxmox_list_qemu and proxmox_list_lxc tools

This commit is contained in:
Agentic OS
2026-06-13 20:59:37 +00:00
parent dab31bf8d3
commit ed42e17318

View File

@@ -1,11 +1,15 @@
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__
from proxmox_mcp.config import settings
from proxmox_mcp.targets import registry
from proxmox_mcp.tools import register_all
mcp = FastMCP(
@@ -18,6 +22,131 @@ mcp = FastMCP(
)
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