vm_status
Check the status of an Incus virtual machine or container to monitor its running state, IP address, resource usage, and available snapshots.
Instructions
Get the status of a VM/container (Incus).
Returns state (running/stopped), IP address, resource usage,
and available snapshots.
Args:
vm: Name of the VM or container.
Returns:
Formatted status information or error message.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| vm | Yes |
Implementation Reference
- src/sympathy_mcp/lifecycle.py:143-208 (handler)The core implementation of vm_status that queries Incus CLI to get VM status information. Validates the VM name, runs 'incus list <vm> --format json', parses the JSON response, extracts network addresses, snapshots, and resource usage, then returns a VMInfo object.async def vm_status(vm: str) -> VMInfo: """Get detailed status of a VM/container. Uses `incus list <vm> --format json` for structured data. """ _validate_vm_name(vm) result = await _run_incus("list", vm, "--format", "json") if result.exit_code != 0: raise RuntimeError( f"Failed to get status for {vm}: {result.stderr.strip()}" ) try: instances = json.loads(result.stdout) except json.JSONDecodeError as e: raise RuntimeError(f"Failed to parse incus output: {e}") if not instances: raise RuntimeError(f"VM/container '{vm}' not found") # Find exact match (incus list does prefix matching) instance = None for inst in instances: if inst.get("name") == vm: instance = inst break if instance is None: raise RuntimeError(f"VM/container '{vm}' not found") # Extract network info ipv4 = "" ipv6 = "" state = instance.get("state", {}) networks = state.get("network", {}) for iface_name, iface in networks.items(): if iface_name == "lo": continue for addr in iface.get("addresses", []): if addr.get("family") == "inet" and addr.get("scope") == "global": ipv4 = ipv4 or addr.get("address", "") elif addr.get("family") == "inet6" and addr.get("scope") == "global": ipv6 = ipv6 or addr.get("address", "") # Extract snapshots snapshot_names = [] for snap in instance.get("snapshots", []) or []: if isinstance(snap, dict): snapshot_names.append(snap.get("name", "")) elif isinstance(snap, str): snapshot_names.append(snap) return VMInfo( name=instance.get("name", vm), status=instance.get("status", "Unknown"), type=instance.get("type", "unknown"), architecture=instance.get("architecture", ""), ipv4=ipv4, ipv6=ipv6, pid=state.get("pid", 0), processes=state.get("processes", 0), memory_usage=state.get("memory", {}).get("usage", 0), cpu_usage=state.get("cpu", {}).get("usage", 0), snapshots=snapshot_names, )
- src/sympathy_mcp/server.py:264-281 (registration)MCP tool registration for vm_status. Uses the @mcp.tool() decorator to expose the function as an MCP tool, wraps the underlying _vm_status implementation, catches exceptions, and formats the VMInfo object into a human-readable string.@mcp.tool() async def vm_status(vm: str) -> str: """Get the status of a VM/container (Incus). Returns state (running/stopped), IP address, resource usage, and available snapshots. Args: vm: Name of the VM or container. Returns: Formatted status information or error message. """ try: info = await _vm_status(vm) return _format_vm_info(info) except (ValueError, RuntimeError, OSError) as e: return f"ERROR: {e}"
- src/sympathy_mcp/lifecycle.py:31-45 (schema)VMInfo dataclass defining the schema for VM status information. Includes fields for name, status, type, IP addresses, architecture, PID, processes, memory usage, CPU usage, and snapshots list.class VMInfo: """Status information for a single VM/container.""" name: str status: str # Running, Stopped, etc. type: str # container or virtual-machine ipv4: str = "" ipv6: str = "" architecture: str = "" pid: int = 0 processes: int = 0 memory_usage: int = 0 cpu_usage: int = 0 snapshots: list[str] = field(default_factory=list)
- src/sympathy_mcp/server.py:69-94 (helper)Helper function that formats a VMInfo object into a human-readable string for the MCP tool response. Converts memory usage to MB, CPU time to seconds, and formats all fields with labels.def _format_vm_info(info: VMInfo) -> str: """Format VMInfo as a readable string.""" lines = [ f"Name: {info.name}", f"Status: {info.status}", f"Type: {info.type}", ] if info.architecture: lines.append(f"Architecture: {info.architecture}") if info.ipv4: lines.append(f"IPv4: {info.ipv4}") if info.ipv6: lines.append(f"IPv6: {info.ipv6}") if info.pid: lines.append(f"PID: {info.pid}") if info.processes: lines.append(f"Processes: {info.processes}") if info.memory_usage: mb = info.memory_usage / (1024 * 1024) lines.append(f"Memory: {mb:.1f} MB") if info.cpu_usage: secs = info.cpu_usage / 1_000_000_000 lines.append(f"CPU Time: {secs:.2f}s") if info.snapshots: lines.append(f"Snapshots: {', '.join(info.snapshots)}") return "\n".join(lines)
- src/sympathy_mcp/lifecycle.py:54-62 (helper)Validation helper that ensures VM/container names are safe and valid. Checks that the name is not empty and matches the regex pattern requiring it to start with a letter and contain only alphanumeric characters and hyphens.def _validate_vm_name(name: str) -> None: """Validate that a VM/container name is safe.""" if not name or not name.strip(): raise ValueError("VM name cannot be empty") if not _VALID_NAME.match(name): raise ValueError( f"Invalid VM name '{name}': must start with a letter, " "contain only alphanumeric characters and hyphens" )