Repository avatar
Developer Tools
v0.1.1
active

better-unraid-mcp

io.github.mswdev/better-unraid-mcp

Monitor and manage an Unraid server from any MCP client: array, Docker, VMs, ZFS, logs, and UPS.

Documentation

Better Unraid MCP

Monitor and manage your Unraid server in plain English, from any MCP client.

npm version CI Coverage License: MIT Node.js 20+

MCP protocol 2026-07-28 MCP Registry Docker Claude Desktop bundle

Features · Quick start · Tools · MCP features · Configuration · HTTP transport · Security · Development

A Claude Code session: asking why the array is degraded, getting a health rollup, and a gated container restart

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 command
  • Work 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 .plg plugin installs, mover control, reboot and shutdown
  • Watch 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_query and a confirm-gated graphql_mutation while 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.

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 --create

[!IMPORTANT] The 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 Code
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@latest
Claude Desktop

Add 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
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@latest

Or 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" }
Gemini CLI

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.

OptionDetails
Claude Desktop, one clickDownload better-unraid-mcp-<version>.mcpb from the latest release and open it. Claude Desktop asks for the URL and API key.
Claude Code plugin marketplaceclaude plugin marketplace add mswdev/better-unraid-mcp, then claude plugin install better-unraid@better-unraid-mcp. The plugin reads UNRAID_API_URL and UNRAID_API_KEY from your environment.
Docker (remote HTTP transport)ghcr.io/mswdev/better-unraid-mcp. See Docker.
MCP RegistryListed as io.github.mswdev/better-unraid-mcp for clients that browse the registry.

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 doctor

It 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: OK

4. 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.

CategoryTools
System and storage14
Array control3
Docker9
Virtual machines4
Notifications8
Observability4
Plugins4
ZFS (SSH)4
Host configuration (SSH)7
Backup (SSH)1
User Scripts (SSH)2
API keys2
UPS1
Host shell (optional, needs SSH)2
Raw GraphQL (advanced)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

14 tools
ToolTypeDescription
system_inforead-onlyOS, kernel, uptime, hostname, and CPU summary.
array_statusread-onlyArray state, capacity, current parity-check status, and per-disk health.
parity_historyread-onlyRecent parity checks (date, status, errors, speed).
disk_listread-onlyPhysical disks with model, size, SMART status, temperature, and partitions.
disk_smart_reportread-onlyFull smartctl attribute report for one disk (SSH).
disk_spinmutationSpins a disk up or down (SSH; confirm): array slots through emhttpd so the state stays consistent, unassigned /dev/sdX through sdspin (ATA only).
share_listread-onlyUser shares with usage; filter by name.
mover_statusread-onlyWhether the mover (cache-to-array migration) is running, plus its schedule.
system_healthread-onlyOne severity-scored health rollup (OK / WARNING / CRITICAL) across array, capacity, disks and temperatures, parity, notifications, UPS, and pending container updates. Start here.
connection_doctorread-onlySelf-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 npx better-unraid-mcp doctor.
gpu_metricsread-onlyGPU 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.
process_listread-onlyThe host's busiest processes by CPU or memory (SSH).
mover_actiondestructiveStarts or stops the mover over SSH (requires confirm: true). Stopping can leave partial files on the destination.
system_powerdestructiveReboots or shuts down the whole server over SSH. Requires confirm: true and acknowledge_risk: true.

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.

3 tools
ToolTypeDescription
array_actiondestructiveStarts or stops the array. Stopping takes every share, container, and VM offline, so stop also requires acknowledge_risk: true.
array_disk_actiondestructiveAdds 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 confirm + acknowledge_risk.
parity_checkdestructiveStarts (optionally correcting), pauses, resumes, or cancels a parity check.

Docker

9 tools
ToolTypeDescription
docker_container_listread-onlyContainers with state, image, and update availability; filter by name.
docker_container_logsread-onlyRecent log lines for a container, with tail and time-based paging.
docker_network_listread-onlyDocker networks (driver, scope, IPv6/internal/attachable).
docker_port_conflictsread-onlyContainer and LAN port conflicts.
docker_statsread-onlyPer-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 docker stats over SSH (see Host shell); the response says which source it used.
docker_container_actiondestructiveStart, stop, pause, unpause, or restart a container (restart uses the API's native restart mutation, API 4.37+).
docker_container_removedestructivePermanently deletes a container (irreversible) and optionally its image. Needs Unraid 7.3+.
docker_container_updatedestructivePulls the latest image and recreates containers, by id or all with updates. Needs Unraid 7.3+.
docker_autostart_setdestructiveSets which containers start on boot without losing the existing boot order. Needs Unraid 7.3+.

Virtual machines

4 tools
ToolTypeDescription
vm_listread-onlyVirtual machines with run state; filter by name.
vm_actiondestructiveStart, stop, pause, resume, forceStop, reboot, or reset a VM by name or id. forceStop and reset are ungraceful and also require acknowledge_risk: true.
vm_snapshot_listread-onlyLists a VM's libvirt snapshots through virsh (SSH; the GraphQL API doesn't expose them).
vm_snapshot_createdestructiveCreates an EXTERNAL disk snapshot through virsh, the same way Unraid 7 does. Requires confirm + acknowledge_risk. Revert and delete stay in the Unraid UI on purpose.

Notifications

8 tools
ToolTypeDescription
notification_overviewread-onlyUnread and archived counts broken down by importance.
notification_listread-onlyNotifications by type (unread or archive) with paging; the source of truth for ids.
notification_alertsread-onlyDeduplicated unread warnings and alerts: the "needs attention now" view.
notification_archivemutationArchives or unarchives notifications (reversible, no confirmation needed). The API swallows per-id failures, so verify with notification_list.
notification_unreadmutationMarks one notification as unread again (reversible, no confirmation needed).
notification_createmutationCreates a notification (no confirmation needed).
notification_recalculatemutationRe-syncs cached overview counts from disk (no confirmation needed).
notification_deletedestructivePermanently deletes notifications (irreversible).

Observability

4 tools
ToolTypeDescription
log_listread-onlyThe server's log files with size and last-modified time.
log_readread-onlyTails or windows a log file (default 100 lines, max 2000), with paging hints.
system_metricsread-onlyPoint-in-time CPU load, memory pressure, per-interface network rates, and server time. Temperature data is opt-in.
metrics_historyread-onlyRecent CPU, memory, and network history from the opt-in in-memory recorder (MCP_METRICS_HISTORY=true): 30-second min/avg/max buckets for up to 24 hours, with gaps reported as gaps. When recording is off, it says how to turn it on.

Plugins

4 tools
ToolTypeDescription
plugin_listread-onlyInstalled API plugins and OS .plg plugins.
plugin_adddestructiveInstalls API plugins by npm package name, then restarts the Unraid API. npm install on your server runs package lifecycle scripts, so only install packages you trust.
plugin_removedestructiveUninstalls API plugins by npm package name, then restarts the Unraid API.
plugin_install_plgdestructiveInstalls a native Unraid OS plugin from a .plg URL. A .plg runs arbitrary code as root, so this requires confirm + acknowledge_risk. Only install from sources you trust.

ZFS (SSH)

ZFS ships with Unraid 6.12+. These tools say so plainly when no pools exist.

4 tools
ToolTypeDescription
zfs_statusread-onlyPool health and capacity, plus ARC memory usage.
zfs_dataset_listread-onlyDatasets with used and available space and mountpoints; optional pool filter.
zfs_snapshot_listread-onlySnapshots with size and creation time; optional dataset filter.
zfs_snapshot_actiondestructiveCreate, destroy, or roll back a snapshot. Rollback discards everything after the snapshot, so this requires confirm + acknowledge_risk.

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.

7 tools
ToolTypeDescription
service_listread-onlyRunning, stopped, or not-installed state of samba, nfs, sshd, docker, libvirt, and tailscale.
service_actiondestructiverestart, start, or stop one of those services, then check its status. stop needs allow_stop: true, and stopping docker or libvirt is refused (use array_action). Requires confirm + acknowledge_risk.
unassigned_listread-onlyDisks outside the array, pools, and flash, with partitions, filesystems, and mount points.
unassigned_actiondestructiveMounts or unmounts an unassigned partition through the Unassigned Devices plugin (rc.unassigned) and checks the result with lsblk. Refuses when the plugin isn't installed. Requires confirm + acknowledge_risk.
share_createdestructiveCreates 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 .cfg. Requires confirm + acknowledge_risk.
share_editdestructiveChanges that same subset of settings on an existing share, leaves the other settings alone, and checks the result by reading it back. Requires confirm + acknowledge_risk.
share_deletedestructiveDeletes an EMPTY share's configuration. It never deletes files and refuses while the share holds data. Requires confirm + acknowledge_risk.

Backup (SSH)

1 tool
ToolTypeDescription
flash_backupdestructiveArchives the flash (USB boot) device into a user share as /mnt/user/<share>/flash-backups/flash-backup-<scope>-<timestamp>.tar.gz: /boot/config by default, or the whole flash with full: true. Each archive is checked with tar -tzf, and keep: N prunes older archives and lists what it removed. The archive contains your license key, API keys, and passwords, so it stays on your array. Requires confirm + acknowledge_risk.

User Scripts (SSH)

2 tools
ToolTypeDescription
user_script_listread-onlyLists scripts managed by the User Scripts plugin.
user_script_rundestructiveRuns one user script with the plugin's noexec-safe runner. A user script is arbitrary root code, so this requires confirm + acknowledge_risk.

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.

2 tools
ToolTypeDescription
apikey_listread-onlyLists configured API keys (name, roles, permissions, created). Key values are never selected or returned.
apikey_managedestructiveCreates, updates, adds or removes roles on, or deletes API keys. Requires confirm + acknowledge_risk. The key value is shown exactly once, at creation. Deleting the key this MCP server uses locks it out.

UPS

1 tool
ToolTypeDescription
ups_statusread-onlyLive UPS telemetry from apcupsd: status (ONLINE, ONBATT, LOWBATT, ...), battery charge and runtime, and power load. When apcaccess has nothing to report, it says "no live UPS data" instead of erroring or inventing a healthy reading. That includes NUT-managed servers, which the Unraid API can't see.

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.

2 tools
ToolTypeDescription
file_readread-onlyTails any absolute file path on the host (default 200 lines, max 2000). An optional pattern greps on the server first, so searching huge logs stays cheap.
shell_execdestructiveRuns an arbitrary command as the SSH user (typically root). Every call requires confirm: true. Output is capped, and timeouts are enforced (default 30 s, max 120 s).

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.

2 tools
ToolTypeDescription
graphql_queryread-onlyRuns 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; dry_run: true validates without sending.
graphql_mutationdestructiveRuns an arbitrary GraphQL mutation. Requires confirm: true on every call, plus acknowledge_risk: true when it selects a known-dangerous field (setState, forceStop, reset, configureUps). Verify results with a follow-up read. Validated against the vendored schema before the confirm gate; dry_run: true validates without sending and needs no confirm.

[!NOTE] 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 please open 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.

FeatureDetails
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 confirm and acknowledge_risk arguments still work everywhere and are the only option on stateless HTTP. Declining the prompt changes nothing on the server.
Resourcesunraid://schema (the vendored GraphQL SDL this package was built against), unraid://health (the system-health rollup as JSON), unraid://doctor (the connection self-test as JSON), and unraid://live/history (the last hour of recorded CPU, memory, and network history when MCP_METRICS_HISTORY=true, or a hint on how to turn it on).
Live resourcesSubscribe to unraid://live/parity, unraid://live/docker-stats, unraid://live/metrics, unraid://live/ups, unraid://live/array, and unraid://live/notifications for updates pushed over the Unraid API's WebSocket, or to unraid://logs/{path} to follow a log file.
PromptsFour guided workflows: triage-array-problem, find-resource-hog, safe-container-update (takes an optional container argument), and health-report.
Structured outputsystem_health, system_metrics, array_status, and docker_container_list declare an outputSchema and return structuredContent alongside the human-readable text in both response formats.
Complete annotationsEvery tool declares readOnlyHint, destructiveHint, idempotentHint, and openWorldHint, and a registry test enforces it.

Configuration

VariableRequiredDefaultDescription
UNRAID_API_URLyesFull Unraid GraphQL endpoint, including /graphql.
UNRAID_API_KEYyesAPI key from Quick start step 1.
MCP_TRANSPORTnostdiostdio (local clients) or http (remote clients).
MCP_HTTP_PORTno3000Port for the http transport.
MCP_HTTP_HOSTno127.0.0.1Bind address for the http transport.
MCP_HTTP_ALLOWED_HOSTSnoComma-separated Host allow-list; turns on DNS-rebinding protection.
UNRAID_ALLOW_SELF_SIGNEDnofalseSet true only for a self-signed TLS certificate on the LAN.
MCP_READ_ONLYnofalseSet true to register only the read-only tools.
MCP_METRICS_HISTORYnofalseSet true to record CPU, memory, and network history in memory (30-second min/avg/max buckets, 24 hours, cleared on restart) for metrics_history and unraid://live/history. Keeps one WebSocket open to the server.
MCP_HTTP_BEARER_TOKENhttpRequired for the http transport: clients must send Authorization: Bearer <token>.
MCP_HTTP_ALLOW_UNAUTHENTICATEDnofalseExplicit opt-in to run the http transport with no auth (trusted networks only).
LOG_LEVELnoinfofatal, error, warn, info, debug, trace, or silent.
UNRAID_SSH_HOSTnoTurns on every tool marked SSH above, plus the SSH fallback for docker_stats. Requires a password or key path.
UNRAID_SSH_PORTno22SSH port.
UNRAID_SSH_USERnorootSSH user. Unraid administration is normally done as root.
UNRAID_SSH_PASSWORDnoSSH password. Prefer UNRAID_SSH_KEY_PATH where you can.
UNRAID_SSH_KEY_PATHnoPath to an SSH private key file (readable by the MCP server process).
UNRAID_SSH_IDLE_SECONDSno90Idle seconds before the persistent SSH connection closes (it reconnects when next needed).
MCP_HTTP_SESSIONSnofalseSet true for stateful HTTP sessions (SSE responses), which carry server-initiated messages: progress notifications, elicitation prompts, and live-resource updates.

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@latest

The 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.

[!WARNING] 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 set MCP_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-stopped

Point 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 dev

Run 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 lint

To 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

MIT

NPM
better-unraid-mcp
Install Command
npm install better-unraid-mcp