libvirt-mcp
Provides tools for managing KVM/QEMU virtual machines via libvirt, including inspection, lifecycle control, snapshots, and domain management operations.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
libvirt-mcp
A Model Context Protocol (MCP) server for managing KVM/QEMU virtual machines on remote
libvirt hosts. Talks libvirt RPC over SSH — no agent on the hypervisor, no need to
install anything on the target host beyond the standard libvirtd.
Functionally a "virt-manager for LLMs": inspect, start/stop, snapshot, clone, and delete KVM/QEMU domains through 13 MCP tools.
Tools
Group | Tools |
Inspection |
|
Lifecycle |
|
Snapshots |
|
Management |
|
Destructive operations (force_destroy_domain, snapshot_revert, snapshot_delete,
delete_domain) require an explicit confirm=True argument so an LLM can't fire them
by accident.
Related MCP server: boxes-mcp
Architecture
┌──────────────┐ ┌──────────────────────┐
│ MCP client │ ── stdio (JSON-RPC) ──▶ │ libvirt-mcp │
│ Claude Code, │ │ (Docker container) │
│ Desktop, … │ │ • libvirt-python │
└──────────────┘ │ • mcp SDK │
└──────────┬───────────┘
│
│ qemu+ssh://user@host/system
│ (uses host's ~/.ssh/)
▼
┌──────────────────────┐
│ Hypervisor │
│ • libvirtd │
│ • qemu-kvm │
└──────────────────────┘The MCP server runs inside a Docker container (so libvirt-dev headers don't need to
be installed on your machine). It bind-mounts your ~/.ssh read-only and uses standard
libvirt SSH transport, inheriting ~/.ssh/config, agent forwarding, jump hosts, etc.
Setup
1. Pull the image
The container image is published as ghcr.io/rzippert/libvirt-mcp (public — no auth
required, even though the source repo is private):
docker pull ghcr.io/rzippert/libvirt-mcp:latestTags published:
latest— head ofmainX.Y.ZandX.Y— from git tagsvX.Y.Z(thevprefix is dropped per Docker convention)main,sha-<short>— for traceability
2. Create your config
mkdir -p ~/.config/libvirt-mcp
cat > ~/.config/libvirt-mcp/config.toml <<'EOF'
default_profile = "primary"
[profiles.primary]
uri = "qemu+ssh://user@hypervisor.example.com/system"
description = "Primary KVM hypervisor"
EOF
$EDITOR ~/.config/libvirt-mcp/config.tomlThe libvirt URI is standard. SSH keys come from your host's ~/.ssh/. Make sure you
can already connect:
ssh user@hypervisor.example.com virsh -c qemu:///system list --all3. Wire it up to an MCP client
Claude Code
claude mcp add libvirt --scope user -- \
docker run -i --rm \
-v "$HOME/.ssh:/home/ubuntu/.ssh:ro" \
-v "$HOME/.config/libvirt-mcp/config.toml:/etc/libvirt-mcp/config.toml:ro" \
--network host \
-e LIBVIRT_MCP_CONFIG=/etc/libvirt-mcp/config.toml \
ghcr.io/rzippert/libvirt-mcp:latestVerify with claude mcp list. Remove with claude mcp remove libvirt --scope user.
Claude Desktop
Edit claude_desktop_config.json:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"libvirt": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-v", "/Users/youruser/.ssh:/home/ubuntu/.ssh:ro",
"-v", "/Users/youruser/.config/libvirt-mcp/config.toml:/etc/libvirt-mcp/config.toml:ro",
"--network", "host",
"-e", "LIBVIRT_MCP_CONFIG=/etc/libvirt-mcp/config.toml",
"ghcr.io/rzippert/libvirt-mcp:latest"
]
}
}
}Replace /Users/youruser with your home directory. On Windows use forward slashes or
double-escape backslashes. Restart Claude Desktop after editing.
VS Code (GitHub Copilot Chat MCP)
Create .vscode/mcp.json in your workspace (project-scoped) or add to user settings:
{
"servers": {
"libvirt": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-v", "${userHome}/.ssh:/home/ubuntu/.ssh:ro",
"-v", "${userHome}/.config/libvirt-mcp/config.toml:/etc/libvirt-mcp/config.toml:ro",
"--network", "host",
"-e", "LIBVIRT_MCP_CONFIG=/etc/libvirt-mcp/config.toml",
"ghcr.io/rzippert/libvirt-mcp:latest"
]
}
}
}VS Code expands ${userHome} and ${workspaceFolder}. Open the Copilot Chat panel →
MCP servers → enable libvirt.
Configuration reference
~/.config/libvirt-mcp/config.toml (or override with LIBVIRT_MCP_CONFIG):
default_profile = "primary" # used when a tool is called without `profile=`
[profiles.<name>]
uri = "qemu+ssh://user@host/system" # standard libvirt URI
description = "Free-form description for humans"Config search order:
$LIBVIRT_MCP_CONFIGenv var~/.config/libvirt-mcp/config.toml./config.dev.toml./config.toml
Safety model
Allow-list validation on domain names (
^[a-z0-9][a-z0-9-]{0,30}$), bridge names, and absolute paths (no..segments).Inspection tools open read-only libvirt connections; state-changing tools open read-write connections only when invoked.
Confirmation gates on destructive operations:
force_destroy_domain,snapshot_revert,snapshot_delete,delete_domainall requireconfirm=True.No subprocess on the hypervisor: every operation is pure libvirt RPC (no
qemu-img, novirt-install, novirshshell-out). Disk volumes are created and deleted through libvirt's storage volume API, reusing any active dir-pool that covers the target path or transparently creating a transient one.
Development
git clone git@github.com:rzippert/libvirt-mcp.git
cd libvirt-mcp
cp config.example.toml config.dev.toml && $EDITOR config.dev.toml
docker compose build
docker compose run --rm dev bashInside the dev container, source on the host (bind-mounted at /workspace) shadows the
installed package via PYTHONPATH, so edits take effect immediately. Exercise tools
directly:
python -c "from libvirt_mcp.tools.readonly import list_domains; \
import json; print(json.dumps(list_domains(), indent=2))"Project layout:
libvirt_mcp/
├── __main__.py # python -m libvirt_mcp → mcp.run() (stdio)
├── server.py # FastMCP instance
├── connections.py # config loader + connect() context manager
├── states.py # VIR_DOMAIN_* → string
└── tools/
├── readonly.py # inspection
├── lifecycle.py # start/shutdown/reboot/force_destroy
├── snapshot.py # snapshot CRUD (revert/delete gated)
└── management.py # clone_from_template, delete_domainPublishing happens automatically via .github/workflows/publish.yml on push to main
and on v* tags (multi-arch: linux/amd64, linux/arm64).
License
GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later). See LICENSE.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
This server cannot be deployed
Maintenance
Related MCP Connectors
Manage servers through SSH.
Securely control computers you explicitly pair through files, terminals, processes, screenshots, desktop UI/input, clipboard, browser automation, diagnostics, and document tools.
Remote shell and detached long-running jobs on your own machines — no SSH, open ports or VPN.
Manage remote servers, SSH terminals, files, databases and proxies with scoped access and approvals.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables comprehensive management of Proxmox Virtual Environment through 35 tools for VMs, containers, storage, backups, snapshots, and cluster operations via the Proxmox VE API.25 npm22MIT
- AlicenseAqualityDmaintenanceEnables management of GNOME Boxes virtual machines through libvirt/virsh with lifecycle and snapshot operations.1311 npmMIT
- AlicenseNot gradedqualityCmaintenanceEnables managing SSH-managed clusters with tools for executing commands, file operations, and tmux sessions across multiple nodes.1MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to control and automate Incus/QEMU virtual machines via SSH, supporting mouse/keyboard, screenshots, commands, and lifecycle management.MIT