MCP server for QNAP Virtualization Station (QVS) - manage virtual machines, snapshots, and disks
Project description
mcp-server-qnap-qvs
MCP server for QNAP Virtualization Station (QVS) — manage virtual machines, snapshots, disks, and more on your QNAP NAS via the QVS REST API.
Note: This is not an official QNAP product. The QVS REST API is undocumented — this project is based on reverse-engineering the web UI and the qnap-qvs-sdk-for-go project.
Prerequisites
Before you start, you need:
- QNAP NAS with an x86 CPU (Intel or AMD with VT-x/AMD-V). ARM models do not support Virtualization Station.
- Virtualization Station installed from the QNAP App Center.
- Admin credentials — the username and password you use to log into the QNAP web UI. The server uses these to authenticate with the Virtualization Station API.
- Network access — the machine running the server needs HTTPS access to your NAS (port 443 by default).
- Python 3.10+ on the machine running the server.
Optional: QEMU Guest Agent
If you want the server to report VM IP addresses (via get_vm_ips and get_overview), install the QEMU guest agent inside each VM:
# For Ubuntu/Debian VMs:
sudo apt install qemu-guest-agent
sudo systemctl enable --now qemu-guest-agent
Without the guest agent, IP-related tools will return a helpful message explaining what's needed. Everything else works without it.
Compatibility
| Component | Tested | Expected |
|---|---|---|
| QTS | — | 5.1.0+ |
| QuTS hero | h5.2.8 | h5.1.0+ |
| Virtualization Station | 4.1.x | 3.x+ |
| NAS hardware | x86 (AMD Ryzen) | x86 with VT-x/AMD-V |
Features
39 tools across 7 categories:
- VM lifecycle — start, shutdown, force-stop, reset, suspend, resume
- VM management — create, update settings (CPU, memory, name, auto-start), delete, clone, export, import
- VM info — details, state, IPs, adapters, graphics/VNC, CD-ROMs, USBs
- Disk & ISO — list disks, resize, delete, mount/unmount ISOs, scan for ISOs, download ISOs from URL
- Snapshots — list, create, revert, delete
- Analysis — resource overview dashboard (host CPU/RAM utilization, per-VM summary with networking), QVS audit logs, shutdown progress
- Safety — all destructive operations require explicit
confirm=true
Install
# Via uvx (recommended)
uvx mcp-server-qnap-qvs
# Or via pip
pip install mcp-server-qnap-qvs
# Or via Docker (for remote/NAS deployment)
docker pull ghcr.io/arnstarn/mcp-server-qnap-qvs:latest
How Authentication Works
There are two separate authentication layers:
1. Server ↔ QNAP NAS (required)
The server authenticates to your QNAP's Virtualization Station API using your NAS admin credentials. This happens automatically — you just provide the credentials via environment variables:
| Variable | Description | Required |
|---|---|---|
QNAP_HOST |
NAS hostname or IP address | Yes |
QNAP_PORT |
HTTPS port (default: 443) |
No |
QNAP_USERNAME |
QTS admin username | Yes |
QNAP_PASSWORD |
QTS admin password | Yes |
QNAP_VERIFY_SSL |
Verify TLS certificate (default: false) |
No |
Most QNAP devices use self-signed certificates, so QNAP_VERIFY_SSL=false is typical. Set it to true if you've installed a valid certificate.
2. MCP Client ↔ Server (SSE mode only)
When running in SSE mode (remote/Docker), the server requires a Bearer token so only authorized MCP clients can connect:
| Variable | Description | Required |
|---|---|---|
MCP_AUTH_TOKEN |
A secret string you choose (like a password) | No |
- If you set
MCP_AUTH_TOKEN: use that same value as the Bearer token in your MCP client config. - If you don't set it: the server generates a random token on startup and prints it to the log. Copy it from there.
- Stdio mode (local, default): no token needed — the MCP client runs the server as a local process.
Configuration
Option A: Local Mode (stdio)
The server runs on your machine. Claude Code spawns it as a subprocess — no network, no token needed.
Claude Code (~/.claude.json):
{
"mcpServers": {
"qnap-qvs": {
"command": "uvx",
"args": ["mcp-server-qnap-qvs"],
"env": {
"QNAP_HOST": "your-nas.local",
"QNAP_USERNAME": "admin",
"QNAP_PASSWORD": "your-password",
"QNAP_VERIFY_SSL": "false"
}
}
}
}
Claude Desktop (claude_desktop_config.json): same format as above.
Option B: Remote Mode (SSE)
The server runs on the NAS (or any Docker host) and MCP clients connect over the network.
Start the server:
# Via Docker (recommended for NAS deployment)
docker run -d \
-p 8445:8445 \
-e QNAP_HOST=localhost \
-e QNAP_USERNAME=admin \
-e QNAP_PASSWORD=your-password \
-e QNAP_VERIFY_SSL=false \
-e MCP_AUTH_TOKEN=your-secret-token \
ghcr.io/arnstarn/mcp-server-qnap-qvs:latest
# Or via Docker Compose
cp .env.example .env # Edit .env with your credentials
docker-compose up -d
# Or directly with env vars
MCP_TRANSPORT=sse MCP_AUTH_TOKEN=your-secret-token mcp-server-qnap-qvs
When running on the NAS itself, set QNAP_HOST=localhost since the server and the API are on the same machine.
Connect your MCP client:
{
"mcpServers": {
"qnap-qvs": {
"url": "http://your-nas.local:8445/sse",
"headers": {
"Authorization": "Bearer your-secret-token"
},
"transportType": "sse"
}
}
}
Option C: QNAP Container Station
- Open Container Station on your QNAP NAS
- Pull
ghcr.io/arnstarn/mcp-server-qnap-qvs:latestor import thedocker-compose.yml - Set environment variables (
QNAP_HOST=localhost,QNAP_USERNAME,QNAP_PASSWORD,MCP_AUTH_TOKEN) - The server runs on port 8445 — connect from any MCP client on your network
Option D: QPKG (App Center)
Install the QPKG directly on your QNAP NAS. It runs as a Docker container via Container Station.
Step 1: Add the repository
- Open App Center on your QNAP
- Click the Settings icon (gear, top-right)
- Go to App Repository
- Add this URL:
https://raw.githubusercontent.com/arnstarn/mcp-server-qnap-qvs/main/qpkg/repo.xml - Click Apply
Step 2: Install
- Search for "MCP QVS Server" in App Center
- Click Install
- Wait for the Docker image to download (first install only)
Step 3: Configure credentials
The QPKG creates a .env file with placeholder values. You need to edit it with your actual QNAP credentials.
SSH into your NAS and edit the .env file:
ssh your-username@your-nas.local
# Find the install path
QPKG_DIR=$(getcfg mcp-server-qnap-qvs Install_Path -f /etc/config/qpkg.conf)
# Edit the .env file (use vi, nano, or echo)
cat > "$QPKG_DIR/.env" << 'EOF'
QNAP_HOST=localhost
QNAP_PORT=443
QNAP_USERNAME=your-admin-username
QNAP_PASSWORD=your-admin-password
QNAP_VERIFY_SSL=false
MCP_AUTH_TOKEN=pick-any-secret-string-here
EOF
# Restart the service to pick up the new config
/etc/init.d/mcp-server-qnap-qvs.sh restart
Replace your-admin-username and your-admin-password with the credentials you use to log into the QNAP web UI. The MCP_AUTH_TOKEN is any secret string you choose — you'll use it as the Bearer token in your MCP client config.
Step 4: Connect your MCP client
{
"mcpServers": {
"qnap-qvs": {
"url": "http://your-nas.local:8445/sse",
"headers": {
"Authorization": "Bearer pick-any-secret-string-here"
},
"transportType": "sse"
}
}
}
Use the same MCP_AUTH_TOKEN value you set in Step 3.
Updating: When a new version is released, the App Center will show an update. Or pull the latest Docker image manually:
ssh your-username@your-nas.local
CS_DIR=$(getcfg container-station Install_Path -f /etc/config/qpkg.conf)
${CS_DIR}/bin/docker pull ghcr.io/arnstarn/mcp-server-qnap-qvs:latest
/etc/init.d/mcp-server-qnap-qvs.sh restart
Environment Variables Reference
| Variable | Description | Default | Used In |
|---|---|---|---|
QNAP_HOST |
NAS hostname or IP | — | Both modes |
QNAP_PORT |
NAS HTTPS port | 443 |
Both modes |
QNAP_USERNAME |
QTS admin username | — | Both modes |
QNAP_PASSWORD |
QTS admin password | — | Both modes |
QNAP_VERIFY_SSL |
Verify TLS cert | false |
Both modes |
MCP_TRANSPORT |
Transport mode: stdio or sse |
stdio |
— |
MCP_HOST |
SSE listen address | 0.0.0.0 |
SSE only |
MCP_PORT |
SSE listen port | 8445 |
SSE only |
MCP_AUTH_TOKEN |
Bearer token for SSE auth | (auto-generated) | SSE only |
Available Tools
Read-Only (14 tools)
| Tool | Description |
|---|---|
list_vms |
List all VMs with full details |
get_vm |
Get detailed info for a single VM |
get_vm_states |
Lightweight status overview of all VMs |
get_vm_ips |
Get VM IP addresses (requires QEMU guest agent in the VM) |
list_vm_disks |
List disks attached to a VM |
get_vm_adapters |
Network interfaces — MAC, model, bridge |
get_vm_graphics |
VNC console info — port, password status |
get_vm_cdroms |
CD-ROM drives and mounted ISOs |
get_vm_usbs |
USB passthrough devices |
list_images |
Available ISO images on the NAS |
get_qvs_logs |
QVS audit/event logs (paginated) |
get_overview |
Dashboard — VM count, host resources, utilization %, per-VM summary with networking |
get_stopping_progress |
Monitor bulk shutdown operations |
VM Lifecycle (6 tools)
| Tool | Description | Confirm? |
|---|---|---|
start_vm |
Start a stopped VM | No |
shutdown_vm |
Graceful ACPI shutdown | Yes |
force_shutdown_vm |
Immediate force stop | Yes |
reset_vm |
Hard restart | Yes |
suspend_vm |
Suspend to memory | No |
resume_vm |
Resume suspended VM | No |
VM Management (6 tools)
| Tool | Description | Confirm? |
|---|---|---|
create_vm |
Create a new VM with CPU, memory, disk, OS type | Yes |
update_vm |
Change name, CPU, memory, auto-start, description | Yes |
delete_vm |
Permanently destroy a VM and its disks | Yes |
clone_vm |
Clone a VM with a new name | Yes |
export_vm |
Export a VM to a NAS path | Yes |
import_vm_file |
Import a VM from an OVA/OVF file on the NAS | Yes |
Disks & ISOs (6 tools)
| Tool | Description | Confirm? |
|---|---|---|
resize_disk |
Expand a virtual disk | Yes |
delete_disk |
Remove and delete a disk | Yes |
mount_iso |
Mount an ISO to a VM's CD-ROM | Yes |
unmount_iso |
Eject an ISO from a VM's CD-ROM | Yes |
check_iso |
Scan a shared folder for available ISO files | — |
download_iso |
Download an ISO from a URL to the NAS | Yes |
Snapshots (4 tools)
| Tool | Description | Confirm? |
|---|---|---|
list_snapshots |
List snapshots for a VM | — |
create_snapshot |
Create a VM snapshot | Yes |
revert_snapshot |
Revert VM to a snapshot | Yes |
delete_snapshot |
Delete a snapshot | Yes |
Safety
All destructive operations require confirm=true. Without it, the tool returns a preview of what it would do — no changes are made. This prevents accidental VM deletions, shutdowns, or snapshot reverts.
Troubleshooting
"QEMU guest agent is not installed or not running"
The get_vm_ips tool and the IP section of get_overview require the QEMU guest agent running inside the VM. Install it:
# Ubuntu/Debian
sudo apt install qemu-guest-agent && sudo systemctl enable --now qemu-guest-agent
# CentOS/RHEL
sudo yum install qemu-guest-agent && sudo systemctl enable --now qemu-guest-agent
All other tools work without the guest agent.
"VM is not running"
IP addresses can only be retrieved from running VMs. Start the VM first with start_vm.
Connection refused / timeout
- Verify the NAS is reachable:
curl -k https://your-nas.local:443 - Check that Virtualization Station is installed and running in the QNAP App Center
- If using a non-default HTTPS port, set
QNAP_PORTaccordingly
Login failed
- Verify your credentials work on the QNAP web UI
- The username and password are for the QNAP system admin account (the same one you use to log into QTS/QuTS hero)
Development
git clone https://github.com/arnstarn/mcp-server-qnap-qvs.git
cd mcp-server-qnap-qvs
pip install -e ".[dev]"
# Run tests
pytest
# Lint
ruff check src/ tests/
# Build QPKG (requires Docker)
docker build -t qpkg-builder -f qpkg/Dockerfile.builder .
docker run --rm -v "$(pwd)/qpkg:/work" qpkg-builder
API Reference
The QVS REST API is not officially documented. This project's API knowledge comes from:
- tmeckel/qnap-qvs-sdk-for-go — Go SDK auto-generated from QNAP's internal OpenAPI specs
- QTS HTTP API Authentication v5.1.0 — Official QNAP auth docs
- Browser DevTools inspection of the Virtualization Station web UI
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mcp_server_qnap_qvs-0.9.2.tar.gz.
File metadata
- Download URL: mcp_server_qnap_qvs-0.9.2.tar.gz
- Upload date:
- Size: 133.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a050bc37a1b3bf2a48e3dfcdd7fe4bb328597b93d7c5a63af21d7926367f51b7
|
|
| MD5 |
827aa011819b710ff99971100c3ed62a
|
|
| BLAKE2b-256 |
99baeb76dc83b96b3f3a8e5f78272509fa0716ca05cb0fdca54394db32b09264
|
File details
Details for the file mcp_server_qnap_qvs-0.9.2-py3-none-any.whl.
File metadata
- Download URL: mcp_server_qnap_qvs-0.9.2-py3-none-any.whl
- Upload date:
- Size: 38.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6a2b5cb9cd15ce16ee12e1d5520c221a274d72d1bf8768bd292123e27cdad954
|
|
| MD5 |
31f5c6c438dc203477881fffc30507a7
|
|
| BLAKE2b-256 |
c31d7ca37e32de040ee5636d8ade64bbe402e79a7c8a729e354948baba005423
|