Better Unraid MCP
Provides Docker management on the Unraid host: container status and logs, per-container resource usage, starting and stopping containers, image updates, port conflict detection, and boot autostart ordering, along with live Docker stats.
Talks to an Unraid server's built-in GraphQL API to monitor and manage the box: array status and parity checks, disks and SMART health, logs and syslog tailing, Docker containers, VMs via libvirt, notifications, UPS status, ZFS pools/datasets/snapshots, plugins/API keys, and host operations like reboot and shutdown, plus live WebSocket resources for array, Docker, system and UPS metrics. Destructive operations are gated behind confirm/acknowledge_risk flags, and a read-only mode can restrict the server to viewing only.
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.
Better Unraid MCP
Monitor and manage your Unraid server in plain English, from any MCP client.
Features · Quick start · Tools · MCP features · Configuration · HTTP transport · Security · Development
Better Unraid MCP is a Model Context Protocol server for the Unraid GraphQL API. Connect it to Claude Desktop, Claude Code, Codex, Gemini CLI, or any other MCP client and ask things like "why is my array degraded?", "tail the syslog", or "restart the Plex container".
Features
Ask a plain question and get a real answer from your server. "Why is my array degraded?" turns into calls to array_status and disk_list, and you find out which disk is unhappy and what SMART thinks of it without opening an SSH session or clicking through WebGUI tabs.
The 67 tools cover most of what you would normally do over SSH or in the WebGUI:
Diagnose problems in one conversation: unread alerts, CPU and memory pressure, network errors, disk temperatures, SMART health
Read any log on the server: list them all, tail the syslog, or page through the middle of a huge file
Manage Docker: container status and logs, per-container resource usage, start and stop, image updates, port conflict detection, boot autostart order
Control VMs through libvirt, from a graceful shutdown to a hard reset
Run the array: start or stop it, manage parity checks, review parity history, check the mover
Triage notifications: read, archive, and clear the alerts you have been putting off
Watch the UPS during an outage: battery charge, runtime estimate, load
Go past the API when you need to (optional, via SSH): read any file on the host, such as
/boot/logs/syslog-previous, or run a confirmed one-off commandWork with ZFS: pool health, datasets, snapshots (create, destroy, rollback), and ARC usage
Reach the host when the API can't: processes, GPU metrics, disk spin, SMART deep reports, User Scripts, VM snapshots
Manage the platform itself: API keys, native
.plgplugin installs, mover control, reboot and shutdownWatch things live: WebSocket-fed resources for parity progress, Docker stats, system metrics (CPU, memory, network, temperature), UPS, array state, notifications, and log following (
unraid://live/*,unraid://logs/{path})Reach the rest of the API with raw
graphql_queryand a confirm-gatedgraphql_mutationwhile dedicated tools catch up
The tools are deliberately paranoid. A destructive tool refuses to run unless the request includes confirm: true, so a stray sentence in a chat can't stop your array. The operations that can really hurt (stopping the array, hard-killing a VM, rebooting the host) also need acknowledge_risk: true. If your client supports MCP elicitation, you get an interactive confirmation prompt instead. Every read works with a viewer-level API key, and MCP_READ_ONLY=true takes every state-changing tool out of the listing.
You don't install anything on the Unraid server. The MCP server runs on your machine, talks to Unraid's built-in GraphQL API with one API key, and starts with a single npx command.
Related MCP server: mcp-homelab
Quick start
1. Create an Unraid API key
On your Unraid server (7.2 or newer), go to Settings > Management Access > API Keys and create a key. Or from the Unraid terminal:
unraid-api apikey --createThe key controls your server, so treat it like a password and give it the least privilege you need. A viewer-level key is enough for every read-only tool.
2. Add the server to your MCP client
claude mcp add better-unraid \
-e UNRAID_API_URL=https://tower.local/graphql \
-e UNRAID_API_KEY=your-api-key \
-- npx -y better-unraid-mcp@latestAdd an entry to the mcpServers object in your claude_desktop_config.json:
{
"mcpServers": {
"better-unraid": {
"command": "npx",
"args": ["-y", "better-unraid-mcp@latest"],
"env": {
"UNRAID_API_URL": "https://tower.local/graphql",
"UNRAID_API_KEY": "your-api-key"
}
}
}
}codex mcp add better-unraid \
--env UNRAID_API_URL=https://tower.local/graphql \
--env UNRAID_API_KEY=your-api-key \
-- npx -y better-unraid-mcp@latestOr add a server table to ~/.codex/config.toml:
[mcp_servers.better-unraid]
command = "npx"
args = ["-y", "better-unraid-mcp@latest"]
env = { UNRAID_API_URL = "https://tower.local/graphql", UNRAID_API_KEY = "your-api-key" }Add an entry to the mcpServers object in ~/.gemini/settings.json:
{
"mcpServers": {
"better-unraid": {
"command": "npx",
"args": ["-y", "better-unraid-mcp@latest"],
"env": {
"UNRAID_API_URL": "https://tower.local/graphql",
"UNRAID_API_KEY": "your-api-key"
}
}
}
}If your server uses a self-signed TLS certificate on the LAN, also set UNRAID_ALLOW_SELF_SIGNED=true. To turn on the SSH-backed tools (reading files like /boot/logs/syslog-previous, ZFS, running one-off commands, and the rest of the tools marked SSH below), also pass the UNRAID_SSH_* variables described under Configuration. @latest keeps you on the newest release; pin a version (for example better-unraid-mcp@0.1.1) if you want fully predictable behavior.
Other ways to install
All of them run the same server, and none of them install anything on the Unraid box.
Option | Details |
Claude Desktop, one click | Download |
Claude Code plugin marketplace |
|
Docker (remote HTTP transport) |
|
MCP Registry | Listed as |
Cautious quickstart (read-only)
Not ready to let a model touch anything? Add MCP_READ_ONLY=true to the environment above and the server registers only the read-only tools. The state-changing tools aren't refused at call time; they never appear at all. Pair that with a VIEWER-role API key and nothing in this server can change your machine.
3. Verify your setup
Before wiring up a client, run the built-in doctor with the same environment:
UNRAID_API_URL=https://tower.local/graphql UNRAID_API_KEY=... npx better-unraid-mcp doctorIt prints one line per check (GraphQL reachability and versions, schema skew against the server's API version, SSH when configured, rate limiting, and read-only mode) and exits non-zero when something is broken:
✓ Reachable in 12 ms — Unraid 7.3.2, API 4.37.4+ad268301, online=true.
✓ Vendored schema matches the server API (4.37.4 vs 4.37.4+ad268301).
⚠ SSH: not configured (optional). Host tools (...) are unavailable; set UNRAID_SSH_* to enable them.
✓ Client-side rate limiting active: 90 request burst, 9/s refill.
✓ read-only mode: disabled — mutating tools are registered (each behind its confirm gate).
doctor: OK4. Try it
Ask your client:
"What's the status of my Unraid array?"
Tools
Read-only tools never change anything. Destructive tools always require confirm: true; without it they refuse and leave your server alone.
Category | Tools |
14 | |
3 | |
9 | |
4 | |
8 | |
4 | |
4 | |
4 | |
7 | |
1 | |
2 | |
2 | |
1 | |
2 | |
2 |
Speed and safety
The SSH channel is one kept-alive connection: it connects lazily, sends keepalive probes, reconnects on its own, and closes after UNRAID_SSH_IDLE_SECONDS of idle time, so commands don't pay for a new handshake each time. GraphQL requests reuse a keep-alive HTTP agent and have a hard 30-second timeout, and idempotent queries get a small jittered retry on transient failures. The busiest reads (system_metrics, array_status, docker_container_list) come from a 5-second snapshot cache, and detailed output includes data_age_ms so you can see how fresh the data is. Long-running shell_exec and docker_container_update calls send MCP progress notifications when the client asks for them (stdio or session-mode HTTP).
All tool output goes through secret redaction: your configured API key, SSH password, and bearer token, plus credential-shaped key/value pairs and JWTs, come back as [redacted]. A client-side rate limiter keeps request bursts inside the Unraid API's throttle, and oversized JSON results are truncated into an envelope that still parses with JSON.parse.
System and storage
Tool | Type | Description |
| read-only | OS, kernel, uptime, hostname, and CPU summary. |
| read-only | Array state, capacity, current parity-check status, and per-disk health. |
| read-only | Recent parity checks (date, status, errors, speed). |
| read-only | Physical disks with model, size, SMART status, temperature, and partitions. |
| read-only | Full smartctl attribute report for one disk (SSH). |
| mutation | Spins a disk up or down (SSH; |
| read-only | User shares with usage; filter by name. |
| read-only | Whether the mover (cache-to-array migration) is running, plus its schedule. |
| read-only | One severity-scored health rollup (OK / WARNING / CRITICAL) across array, capacity, disks and temperatures, parity, notifications, UPS, and pending container updates. Start here. |
| read-only | Self-test of this MCP server's plumbing: GraphQL reachability and latency, API key validity, versions, schema skew (vendored schema vs the server's API version), SSH connectivity, rate-limit config, and read-only mode. Run it first when something misbehaves; it is also available as |
| read-only | GPU utilization over SSH: full metrics from nvidia-smi, a one-line summary (frequency, idle share, engine load, GPU clients) parsed from intel_gpu_top, or a clear report when neither is present. |
| read-only | The host's busiest processes by CPU or memory (SSH). |
| destructive | Starts or stops the mover over SSH (requires |
| destructive | Reboots or shuts down the whole server over SSH. Requires |
Array control
Both tools require an API key with the ADMIN role. They report that the request was issued; run array_status afterward to confirm the result.
Tool | Type | Description |
| destructive | Starts or stops the array. Stopping takes every share, container, and VM offline, so |
| destructive | Adds a disk to the array (checks first that the array is STOPPED), mounts or unmounts an array disk, or clears disk statistics. The Unraid API (4.37+) no longer supports removing a disk, so use the web UI for that. Requires |
| destructive | Starts (optionally correcting), pauses, resumes, or cancels a parity check. |
Docker
Tool | Type | Description |
| read-only | Containers with state, image, and update availability; filter by name. |
| read-only | Recent log lines for a container, with tail and time-based paging. |
| read-only | Docker networks (driver, scope, IPv6/internal/attachable). |
| read-only | Container and LAN port conflicts. |
| read-only | Per-container CPU, memory, network, and block IO usage, hungriest first. Uses a fresh sample from the live WebSocket subscription when one exists and otherwise falls back to |
| destructive | Start, stop, pause, unpause, or restart a container (restart uses the API's native restart mutation, API 4.37+). |
| destructive | Permanently deletes a container (irreversible) and optionally its image. Needs Unraid 7.3+. |
| destructive | Pulls the latest image and recreates containers, by id or all with updates. Needs Unraid 7.3+. |
| destructive | Sets which containers start on boot without losing the existing boot order. Needs Unraid 7.3+. |
Virtual machines
Tool | Type | Description |
| read-only | Virtual machines with run state; filter by name. |
| destructive | Start, stop, pause, resume, forceStop, reboot, or reset a VM by name or id. |
| read-only | Lists a VM's libvirt snapshots through virsh (SSH; the GraphQL API doesn't expose them). |
| destructive | Creates an EXTERNAL disk snapshot through virsh, the same way Unraid 7 does. Requires |
Notifications
Tool | Type | Description |
| read-only | Unread and archived counts broken down by importance. |
| read-only | Notifications by type ( |
| read-only | Deduplicated unread warnings and alerts: the "needs attention now" view. |
| mutation | Archives or unarchives notifications (reversible, no confirmation needed). The API swallows per-id failures, so verify with |
| mutation | Marks one notification as unread again (reversible, no confirmation needed). |
| mutation | Creates a notification (no confirmation needed). |
| mutation | Re-syncs cached overview counts from disk (no confirmation needed). |
| destructive | Permanently deletes notifications (irreversible). |
Observability
Tool | Type | Description |
| read-only | The server's log files with size and last-modified time. |
| read-only | Tails or windows a log file (default 100 lines, max 2000), with paging hints. |
| read-only | Point-in-time CPU load, memory pressure, per-interface network rates, and server time. Temperature data is opt-in. |
| read-only | Recent CPU, memory, and network history from the opt-in in-memory recorder ( |
Plugins
Tool | Type | Description |
| read-only | Installed API plugins and OS |
| destructive | Installs API plugins by npm package name, then restarts the Unraid API. |
| destructive | Uninstalls API plugins by npm package name, then restarts the Unraid API. |
| destructive | Installs a native Unraid OS plugin from a |
ZFS (SSH)
ZFS ships with Unraid 6.12+. These tools say so plainly when no pools exist.
Tool | Type | Description |
| read-only | Pool health and capacity, plus ARC memory usage. |
| read-only | Datasets with used and available space and mountpoints; optional pool filter. |
| read-only | Snapshots with size and creation time; optional dataset filter. |
| destructive | Create, destroy, or roll back a snapshot. Rollback discards everything after the snapshot, so this requires |
Host configuration (SSH)
The GraphQL API has nothing for services, share changes, or unassigned devices, so these tools use the same mechanisms as the web UI: the /etc/rc.d/rc.* scripts, emhttpd's form handler through emcmd, and the Unassigned Devices plugin. Every write is checked by reading the result back.
Tool | Type | Description |
| read-only | Running, stopped, or not-installed state of samba, nfs, sshd, docker, libvirt, and tailscale. |
| destructive |
|
| read-only | Disks outside the array, pools, and flash, with partitions, filesystems, and mount points. |
| destructive | Mounts or unmounts an unassigned partition through the Unassigned Devices plugin ( |
| destructive | Creates a user share through emhttpd with a validated subset of settings (comment, allocator, cache mode and pool, SMB export and security), then checks the written |
| destructive | Changes that same subset of settings on an existing share, leaves the other settings alone, and checks the result by reading it back. Requires |
| destructive | Deletes an EMPTY share's configuration. It never deletes files and refuses while the share holds data. Requires |
Backup (SSH)
Tool | Type | Description |
| destructive | Archives the flash (USB boot) device into a user share as |
User Scripts (SSH)
Tool | Type | Description |
| read-only | Lists scripts managed by the User Scripts plugin. |
| destructive | Runs one user script with the plugin's noexec-safe runner. A user script is arbitrary root code, so this requires |
API keys
These tools hand the model the credentials that control access to your server, so use them with the same care as the keys themselves.
Tool | Type | Description |
| read-only | Lists configured API keys (name, roles, permissions, created). Key values are never selected or returned. |
| destructive | Creates, updates, adds or removes roles on, or deletes API keys. Requires |
UPS
Tool | Type | Description |
| read-only | Live UPS telemetry from apcupsd: status ( |
Host shell (optional, needs SSH)
The GraphQL API can't reach everything: old boot logs under /boot/logs, /proc, one-off commands. These tools fill that gap over SSH. They are off by default and turn on only when you set the UNRAID_SSH_* variables (see Configuration); without them they refuse and explain how to set it up. docker_stats also falls back to this channel when no fresh live sample is available.
Tool | Type | Description |
| read-only | Tails any absolute file path on the host (default 200 lines, max 2000). An optional |
| destructive | Runs an arbitrary command as the SSH user (typically root). Every call requires |
Raw GraphQL (advanced)
These cover the parts of the Unraid API that no dedicated tool wraps yet, such as users and registration. Use a dedicated tool when one exists, because the dedicated tools handle server quirks that these passthroughs don't. The full schema ships with the package at schema/unraid.graphql.
Tool | Type | Description |
| read-only | Runs an arbitrary GraphQL query and returns the raw JSON. Query operations only; output is capped. Validated against the vendored schema before sending, with did-you-mean hints; |
| destructive | Runs an arbitrary GraphQL mutation. Requires |
Tool behavior is checked against the vendored Unraid API 4.37.4 schema and covered by unit tests at 100% coverage. The read-only tools have been run against a live Unraid 7.3 server, but the write paths haven't been widely exercised on live servers yet. Treat destructive tools with care, and pleaseopen an issue if anything misbehaves.
MCP features beyond tools
The server is built on the MCP TypeScript SDK v2 (protocol revision 2026-07-28). Clients on older revisions are negotiated down automatically.
Feature | Details |
Interactive confirmation (elicitation) | When your client supports MCP elicitation (over stdio or session-mode HTTP), gated tools show a real confirmation prompt instead of refusing; the riskiest actions show the warning with two checkboxes. The |
Resources |
|
Live resources | Subscribe to |
Prompts | Four guided workflows: |
Structured output |
|
Complete annotations | Every tool declares |
Configuration
Variable | Required | Default | Description |
| yes | Full Unraid GraphQL endpoint, including | |
| yes | API key from Quick start step 1. | |
| no |
|
|
| no |
| Port for the |
| no |
| Bind address for the |
| no | Comma-separated | |
| no |
| Set |
| no |
| Set |
| no |
| Set |
| http | Required for the | |
| no |
| Explicit opt-in to run the |
| no |
|
|
| no | Turns on every tool marked SSH above, plus the SSH fallback for | |
| no |
| SSH port. |
| no |
| SSH user. Unraid administration is normally done as |
| no | SSH password. Prefer | |
| no | Path to an SSH private key file (readable by the MCP server process). | |
| no |
| Idle seconds before the persistent SSH connection closes (it reconnects when next needed). |
| no |
| Set |
See .env.example for a copy-paste template.
Remote HTTP transport
For remote or hosted clients, run over Streamable HTTP instead of stdio:
MCP_TRANSPORT=http \
MCP_HTTP_BEARER_TOKEN=some-long-random-token \
UNRAID_API_URL=https://tower.local/graphql \
UNRAID_API_KEY=your-api-key \
npx -y better-unraid-mcp@latestThe MCP endpoint is then POST http://host:3000/mcp, and every request must carry the token:
curl -X POST http://host:3000/mcp \
-H "Authorization: Bearer some-long-random-token" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'By default the endpoint is stateless: each POST gets a complete JSON response, and server-initiated messages (progress notifications, elicitation prompts, live-resource updates) are unavailable. Set MCP_HTTP_SESSIONS=true for stateful streamable-HTTP sessions. The client initializes once, sends the returned mcp-session-id header on later requests, receives SSE responses that can carry server-initiated messages, and can end the session with a DELETE. Idle sessions expire after 5 minutes.
The server refuses to start in HTTP mode without MCP_HTTP_BEARER_TOKEN. To run an open endpoint on a trusted network on purpose, set MCP_HTTP_ALLOW_UNAUTHENTICATED=true, and the server logs a warning at startup. Requests without a matching token get a 401, and the token comparison is constant-time.
Every request uses your privileged Unraid API key upstream. The server binds to localhost by default. To expose it further (including to cloud clients such as ChatGPT connectors), put TLS in front with a reverse proxy and setMCP_HTTP_ALLOWED_HOSTS for DNS-rebinding protection. Never expose the endpoint unauthenticated to an untrusted network.
Docker (HTTP transport)
The image runs only the HTTP transport (MCP_TRANSPORT=http, bound to 0.0.0.0:3000 inside the container) and, like the CLI, refuses to start without MCP_HTTP_BEARER_TOKEN:
services:
better-unraid-mcp:
image: ghcr.io/mswdev/better-unraid-mcp:latest
ports: ["127.0.0.1:3000:3000"]
environment:
UNRAID_API_URL: https://tower.local/graphql
UNRAID_API_KEY: ${UNRAID_API_KEY}
MCP_HTTP_BEARER_TOKEN: ${MCP_HTTP_BEARER_TOKEN}
MCP_HTTP_ALLOWED_HOSTS: localhost,mcp.example.com # DNS-rebinding protection
# UNRAID_SSH_HOST / UNRAID_SSH_PASSWORD for host tools; MCP_HTTP_SESSIONS=true for subscriptions/elicitation
restart: unless-stoppedPoint your client at http://<host>:3000/mcp with Authorization: Bearer <token>, and put TLS in front before it leaves the LAN. Every release publishes multi-arch (amd64/arm64) images.
Security
The Unraid API key controls your server. Give it the least privilege you need, keep it only in environment variables or your client's secret store, and never commit it to version control.
Development
git clone https://github.com/mswdev/better-unraid-mcp.git
cd better-unraid-mcp
npm install
npm run build # or: npm run devRun the quality gate before every commit (npm run test:coverage also enforces the coverage threshold that CI checks):
npm run typecheck && npm run build && npm test && npm run lintTo contribute, branch off develop, keep one logical change per commit (conventional commits), and open a draft PR into develop. Never hand-edit the vendored schema (schema/unraid.graphql) or the generated types (src/types/unraid/**); refresh them with npm run schema:update and npm run generate.
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
Official Todoist MCP server. Manage tasks and projects. Hosted, no API key needed.
Sonos MCP server: control your Sonos speakers from any MCP client. Play songs, artists and playlists, set volume, group rooms, move music to another room, switch to TV, spoken announcements and reminders. 27 tools, English and Chinese. Works through the official Sonos cloud, so there is no home bridge to install; sign in with OAuth. Requires the free ZoneFoundry iOS app.
Manage your KeepMySubs subscriptions, spend, renewals, and bills from any MCP client.
MCP server for Gainium — manage trading bots, deals, and balances via AI assistants
Related MCP Servers
- FlicenseNot gradedqualityBmaintenanceEnables AI assistants to manage Unraid OS via Docker, system calls, and file system access for automating array, share, and container operations.-
- AlicenseNot gradedqualityDmaintenanceAn MCP server that gives AI assistants real-time access to your homelab infrastructure. It enables querying node status, managing Docker containers, controlling Proxmox VMs, and inspecting OPNsense firewall state through natural conversation.2MIT
- AlicenseNot gradedqualityDmaintenanceAn MCP server that enables AI assistants like Claude to manage Unraid servers through natural language. Install it from Community Applications and control your homelab from any MCP-compatible AI client.3MIT
- AlicenseNot gradedqualityBmaintenanceMCP server for Home Assistant that lets you control and query your smart home through natural language via MCP clients. Provides tools for entities, devices, services, automations, scripts, history, add-ons, and system info, with read-only access by default and optional configurable write support.1MIT