# mcqemu An MCP server that lets LLM agents manage QEMU virtual machines: launch and stop VMs, inspect them over QMP, manage disk images with qemu-img, take live snapshots, and run commands inside guests through qemu-guest-agent. ## Requirements - Linux with QEMU installed (`qemu-system-*` and `qemu-img` on PATH) - `/dev/kvm` access for hardware acceleration (optional — TCG emulation works without it, just slower) - Python 3.11+ managed with [uv](https://docs.astral.sh/uv/) ## Install ```bash # From this checkout uv sync # Add to Claude Code claude mcp add mcqemu -- uv run --directory /path/to/mcqemu mcqemu ``` ## What it can do | Group | Tools | |---|---| | Lifecycle | `launch_vm`, `stop_vm`, `pause_vm`, `resume_vm`, `attach_vm`, `forget_vm` | | Sandboxes | `sandbox_vm` (overlay + launch + wait-for-agent in one call), `sandbox_destroy` | | Inspect | `list_vms`, `vm_info` | | Live snapshots | `vm_snapshot_create` / `restore` / `delete` / `list` | | See & drive | `vm_screenshot` (PNG), `vm_send_keys`, `vm_type_text`, `vm_click`, `vm_serial_read` | | Disk images | `image_create`, `image_info`, `image_convert`, `image_resize`, `image_snapshot_*` | | Guest agent | `guest_ping`, `guest_info`, `guest_exec`, `guest_file_read`, `guest_file_write` | VMs are daemonized QEMU processes with QMP control sockets, so they survive MCP server restarts. The registry lives in `~/.local/share/mcqemu/`, sockets in `$XDG_RUNTIME_DIR/mcqemu/`. Guest tools (`guest_*`) need `qemu-guest-agent` installed inside the guest OS; the host-side virtio-serial channel is wired on every launch, so installing the agent in the guest is the only step. Port forwards accept `"2222:22"` (explicit, collision-checked up front), `"auto:22"`, or just `"22"` — auto forms pick a free host port and the launch result reports what was chosen. ## Quick start Disposable sandbox from any base image with `qemu-guest-agent` inside: ``` sandbox_vm(base_image="~/vms/ubuntu-agent.qcow2") # -> overlay created, VM booted, agent waited for, free port forwarded to 22 guest_exec(name="sandbox", command="uname", args=["-a"]) sandbox_destroy(name="sandbox") # stops VM, deletes overlay; base untouched ``` Installing an OS from scratch: ``` image_create(path="~/vms/test.qcow2", size="10G") launch_vm(name="test", disks=["~/vms/test.qcow2"], iso="~/isos/alpine.iso", port_forwards=["auto:22"]) # ... drive the installer with vm_screenshot / vm_type_text / vm_send_keys ... stop_vm(name="test") launch_vm(name="test", disks=["~/vms/test.qcow2"]) guest_exec(name="test", command="uname", args=["-a"]) ``` ## Development ```bash uv run pytest # unit tests (QMP and subprocess mocked) uv run pytest -m integration # boots a real tiny VM (needs QEMU installed) uv run ruff check . ```