# Unraidclaw

> AI Agent Gateway for Unraid. Permission-enforcing REST API and MCP server that allows AI agents to manage your server.

- **Type:** MCP server
- **Install:** `agentstack add mcp-emaspa-unraidclaw`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [emaspa](https://agentstack.voostack.com/s/emaspa)
- **Installs:** 0
- **Category:** [Integrations](https://agentstack.voostack.com/c/integrations)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [emaspa](https://github.com/emaspa)
- **Source:** https://github.com/emaspa/unraidclaw

## Install

```sh
agentstack add mcp-emaspa-unraidclaw
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

UnraidClaw

  AI Agent Gateway for Unraid. Permission-enforcing REST API and MCP server that allows AI agents to manage your server.

  
  
  
  

---

UnraidClaw sits between AI agents and your Unraid servers. It provides a REST API, an optional MCP endpoint (off by default) and an `unraidclaw` command-line client, all using the same tools and the same fine-grained permissions. It combines Unraid's GraphQL API with direct system integration (CLI commands for parity checks, reboot/shutdown, and syslog; filesystem operations for share config editing and notification management; network introspection via `ip`) to expose capabilities that no single Unraid API covers. Protected API calls require authentication and the relevant permission. Activity logging excludes the public health probe and successful MCP handshakes.

## Features

- **55 tools** across 13 categories: Health, Docker, Community Applications, Plugins, VMs, Array, Disks, Shares, System, Notifications, Network, Users, Logs
- **30 permission keys** in a resource:action matrix, configurable from the WebGUI
- **HTTPS** with auto-generated self-signed TLS certificate
- **SHA-256 API key** authentication
- **Activity logging** with JSONL format, filter, and search
- **OpenClaw plugin** available on ClawHub and npm (`openclaw plugins install clawhub:unraidclaw --accept-capabilities`)
- **Optional MCP** at `/mcp` for Streamable HTTP clients, off by default, using the same API key and permissions as the REST API
- **Command-line client** built into the plugin and available for other machines from npm (`npm install -g unraidclaw-cli`) or as a release archive. See [CLI](#cli)
- **Single-file server**, no `node_modules` needed on Unraid

## Requirements

- **Unraid 7.0.0+** (Node.js 22 is built-in)

## Installation

### From Community Applications

Search for **UnraidClaw** in the Unraid CA store and click Install.

### Manual install

```bash
# Download and install the plugin
plugin install https://raw.githubusercontent.com/emaspa/unraidclaw/main/packages/unraid-plugin/unraidclaw.plg
```

### Setup

1. Go to **Settings > Management Access** in the Unraid WebGUI, scroll to the API section, and copy your Unraid API key (must have **ADMIN** role)
2. Go to **Settings > UnraidClaw**, paste the Unraid API key into the **Unraid API Key** field
3. Generate an UnraidClaw API key (it's hashed with SHA-256; save it, it won't be shown again)
4. Configure permissions on the **Permissions** tab
5. Set Service to **Enabled** and click Apply

The server starts on port `9876` over HTTPS by default. A self-signed TLS certificate is generated on first start; see [TLS certificate](#tls-certificate) for what it contains and how clients trust it.

### Settings tab

**Settings > UnraidClaw > Settings** holds the service configuration. **Apply** writes `/boot/config/plugins/unraidclaw/unraidclaw.cfg` and restarts the service, or stops it when the service is disabled.

| Row | What it does |
|-----|--------------|
| Enable Service | Starts the gateway (`SERVICE="enable"`) |
| Enable MCP | Serves MCP at `/mcp` on the same port (`MCP_ENABLED="yes"`). Off by default. See [MCP](#mcp) |
| Listen Port | Port for the REST API and MCP, `9876` by default |
| Listen Host | Bind address, `0.0.0.0` by default. An explicit address is also added to the MCP Origin allowlist |
| Unraid WebUI Port | Port of the Unraid WebGUI, used to build the GraphQL URL |
| Unraid API Key | The Unraid API key with the ADMIN role. Leave blank to keep the stored key |
| Max Log Size (bytes) | Activity log rotation threshold, `10485760` bytes (10 MiB) by default |

The **API Key Management** section generates the UnraidClaw API key. The **TLS Certificate** section shows the current certificate's subject, subject alternative names, expiry date and SHA-256 fingerprint, warns when the certificate has no `subjectAltName`, and has a **Regenerate certificate** button. [TLS certificate](#tls-certificate) says what regenerating does and what clients must do afterwards.

## CLI

The `unraidclaw-cli` package provides the `unraidclaw` command, which manages the gateway from a terminal. It uses the same tool definitions and gateway permissions as OpenClaw and MCP, and runs on Unraid and on Linux, macOS and Windows machines with Node.js 22 or newer.

### Install

**On Unraid** there is nothing to install. The plugin puts `unraidclaw` on the `PATH` at `/usr/local/bin/unraidclaw`.

**From npm** on another machine:

```sh
npm install -g unraidclaw-cli
unraidclaw --version
```

Update it with `npm update -g unraidclaw-cli`.

**From the release archive**, for machines without npm: download `unraidclaw-cli-.tar.gz` and its `.sha256` file from the [latest release](https://github.com/emaspa/unraidclaw/releases/latest).

```sh
sha256sum -c unraidclaw-cli-.tar.gz.sha256   # macOS: shasum -a 256 -c
tar -xzf unraidclaw-cli-.tar.gz
sudo ln -s "$PWD/unraidclaw-cli-/unraidclaw" /usr/local/bin/unraidclaw
```

On Windows, add the extracted folder to `PATH` and run `unraidclaw.cmd`. The [CLI guide](packages/cli/README.md#install) also covers building from source.

### Use

```sh
unraidclaw config set-key
unraidclaw docker list
unraidclaw array status --output json
```

On Unraid, it discovers the local gateway and certificate. On another machine, set the gateway URL and trust its certificate first, comparing the fingerprint with the WebGUI before accepting:

```sh
unraidclaw config set url "https://:9876"
unraidclaw trust
unraidclaw config set-key
```

Mutating commands require confirmation or `--yes`, except supported dry runs with `dryRun` set to true. See the [CLI guide](packages/cli/README.md) for credentials, certificate trust, all commands and exit codes.

## API

REST API routes return a consistent envelope (MCP uses JSON-RPC):

```json
{
  "ok": true,
  "data": { ... }
}
```

REST authentication uses the `x-api-key: ` header. `/api/health` is public and has no permission requirement. Unknown paths return 404 without checking the key, and CORS preflight requests return 204.

### Endpoints

| Category | Method | Endpoint | Permission |
|----------|--------|----------|------------|
| **Health** | GET | `/api/health` | none |
| **Docker** | GET | `/api/docker/containers` | `docker:read` |
| | GET | `/api/docker/containers/:id` | `docker:read` |
| | GET | `/api/docker/containers/:id/logs` | `docker:read` |
| | POST | `/api/docker/containers` | `docker:create` |
| | POST | `/api/docker/containers/:id/:action` | `docker:update` |
| | DELETE | `/api/docker/containers/:id` | `docker:delete` |
| **Community Apps** | GET | `/api/ca/search?q=` | `ca:read` |
| | GET | `/api/ca/app/:name` | `ca:read` |
| | POST | `/api/ca/app/:name/install` | `ca:create` |
| | POST | `/api/ca/app/:name/update` | `ca:update` |
| | POST | `/api/ca/app/:name/remove` | `ca:delete` |
| **Plugins** | GET | `/api/plugins` | `plugins:read` |
| | GET | `/api/plugins/:file` | `plugins:read` |
| | POST | `/api/plugins/install` | `plugins:create` |
| | POST | `/api/plugins/:file/check` | `plugins:update` |
| | POST | `/api/plugins/:file/update` | `plugins:update` |
| | POST | `/api/plugins/:file/remove` | `plugins:delete` |
| **VMs** | GET | `/api/vms` | `vms:read` |
| | GET | `/api/vms/:id` | `vms:read` |
| | POST | `/api/vms/:id/:action` | `vms:update` |
| | DELETE | `/api/vms/:id` | `vms:delete` |
| **Array** | GET | `/api/array/status` | `array:read` |
| | GET | `/api/array/parity/status` | `array:read` |
| | POST | `/api/array/start` | `array:update` |
| | POST | `/api/array/stop` | `array:update` |
| | POST | `/api/array/parity/start` | `array:update` |
| | POST | `/api/array/parity/pause` | `array:update` |
| | POST | `/api/array/parity/resume` | `array:update` |
| | POST | `/api/array/parity/cancel` | `array:update` |
| **Disks** | GET | `/api/disks` | `disk:read` |
| | GET | `/api/disks/:id` | `disk:read` |
| **Shares** | GET | `/api/shares` | `share:read` |
| | GET | `/api/shares/:name` | `share:read` |
| | PATCH | `/api/shares/:name` | `share:update` |
| **System** | GET | `/api/system/info` | `info:read` |
| | GET | `/api/system/metrics` | `info:read` |
| | GET | `/api/system/services` | `services:read` |
| | POST | `/api/system/reboot` | `os:update` |
| | POST | `/api/system/shutdown` | `os:update` |
| **Notifications** | GET | `/api/notifications` | `notification:read` |
| | GET | `/api/notifications/overview` | `notification:read` |
| | POST | `/api/notifications` | `notification:create` |
| | POST | `/api/notifications/:id/archive` | `notification:update` |
| | DELETE | `/api/notifications/:id` | `notification:delete` |
| **Network** | GET | `/api/network` | `network:read` |
| **Users** | GET | `/api/users/me` | `me:read` |
| **Logs** | GET | `/api/logs/syslog` | `logs:read` |

### Docker create

`POST /api/docker/containers` accepts:

```json
{
  "image": "vikunja/vikunja:latest",
  "name": "vikunja",
  "ports": ["3456:3456"],
  "volumes": ["/mnt/cache/appdata/vikunja:/app/vikunja/files"],
  "env": ["VIKUNJA_SERVICE_TIMEZONE=Europe/London"],
  "restart": "unless-stopped",
  "network": "bridge",
  "icon": "https://example.com/icon.png",
  "webui": "http://[IP]:[PORT:3456]/"
}
```

Only `image` is required. The container is started immediately and an Unraid dockerMan XML template is created so it appears in the Docker tab.

### Community Applications

The CA endpoints search the public catalog, inspect templates, and install apps. Update and removal use the installed container's saved template, not current catalog defaults.

`GET /api/ca/search?q=plex` matches every query word against names, images, maintainers and descriptions. Add `includePlugins=true` or `includeDeprecated=true` to include entries hidden by default.

`GET /api/ca/app/:name` returns template details, configurable ports, volumes and environment variables, required fields without defaults, and installation blockers. If several templates share a name, the API returns 409 with the candidates. Use `?repo=linuxserver` to select a repository.

#### Installing an app

`POST /api/ca/app/Jellyfin/install` accepts template overrides and an optional container name:

```json
{
  "repo": "linuxserver",
  "name": "jellyfin",
  "overrides": {
    "/config": "/mnt/user/appdata/jellyfin",
    "/data/tvshows": "/mnt/user/media/tv",
    "/data/movies": "/mnt/user/media/movies",
    "PUID": "99"
  },
  "dryRun": true
}
```

Override keys are the field's display name or container-side target. Unknown keys and missing required values return 400. Review the dry-run template and command preview, then set `dryRun` to `false` to install. The app appears on Unraid's Docker tab with its template, icon and WebUI link. The command preview omits some values Unraid adds, including host settings and template labels.

Installation returns 422 for unsupported templates: Extra Parameters, Post Arguments, privileged mode, device passthrough, custom networks, Additional Networks, Tailscale, pinned MAC addresses, legacy configuration, unknown field types, or an incompatible Unraid version. Deprecated, blacklisted and `.plg` entries are also refused. Use the WebGUI for these cases.

Unraid 7.4 templates can set a memory limit and a list of Additional Networks. On 7.4 the limit is written into the saved template and shown in the command preview, so the container is created with it and later updates keep it. Unraid 7.0 through 7.3 do not read the new `` template field, so a template that sets it returns 422 there instead of installing an app whose limit would never apply. The same happens when the server's version cannot be read. An unreadable limit, a nonzero limit below Docker's 6 MB minimum, or a limit above UnraidClaw's exact numeric range returns 422 before anything is written or run. Additional Networks are refused rather than dropped, because Unraid attaches them with a second `docker network connect` step that UnraidClaw does not run.

Host paths are used as written. Supply overrides if you relocated appdata; UnraidClaw does not apply CA's path-rewriting rules. A missing `/mnt` pool or share root returns 400 rather than creating a directory on Unraid's RAM filesystem.

An existing container or `my-.xml` template returns 409 and is not overwritten. A failed install keeps its template so you can inspect it and finish from the Docker tab.

#### Updating and removing an installed app

These endpoints take the **installed container name** from the Docker tab, which may differ from the catalog name:

- `POST /api/ca/app/:name/update`
- `POST /api/ca/app/:name/remove`

Both accept `{"dryRun": true}`. A preview reads the installed configuration but does not pull images or change containers. The container must have a matching saved template and Unraid's `net.unraid.docker.managed=dockerman` label. Concurrent actions against the same container return 409.

Update pulls the current image tag and preserves saved ports, paths, variables and network mode, plus the container's restart policy, pids limit and attached Docker volumes. Running apps return to running; stopped apps remain stopped. If the image has not changed, no replacement is created.

The replacement is created before stopping the old container. UnraidClaw swaps their names, starts the replacement when needed, verifies its state, then removes the old container without deleting its image or volumes. A failed replacement triggers a rollback. If rollback fails, the error identifies the original container for recovery. Container rollback cannot reverse changes an updated app makes to its data.

Updates refuse paused or unstable containers and configurations they cannot reproduce, including unsupported template fields, device access, custom runtime settings and resource limits. Update previews and errors redact values marked `Mask="true"` in the saved template.

Remove deletes only the container. Appdata, Docker volumes, the image and the saved template remain. Use **Add Container** on the Docker tab to recreate it from the saved configuration.

### Plugins

The separate Plugins endpoints manage Unraid `.plg` plugins without CA. List and inspect require `plugins:read`; install requires `plugins:create`; check and update require `plugins:update`; removal requires `plugins:delete`. All four permissions default to off.

Install takes an explicit public HTTPS URL ending in `.plg`. Downloads have size and time limits; private addresses, unsafe URLs and redirects to them are refused. The plugin manager runs the downloaded installer as root, so use sources you trust.

Check and update are separate operations. `POST /api/plugins/:file/check` downloads the published definition and stages it in `/tmp/plugins`. `POST /api/plugins/:file/update` applies that staged version. A check changes the staged files even though it does not install anything. Older, mismatched and unregistered one-shot definitions are refused as updates.

`POST /api/plugins/:file/remove` runs the plugin's own uninstall scripts. Those scripts may delete configuration or data; unlike CA container removal, data preservation is not guaranteed.

Every mutating Plugins endpoint accepts `{"dryRun": true}` to return a plan without downloading, writing or executing scripts. Plugin names accept the `.plg` suffix or omit it. OS plugins are protected. UnraidClaw can list, inspect and check itself, but self-install, self-update and self-removal require the Unraid WebGUI or Unraid's `plugin` command because they stop the API server. The `unraidclaw` CLI uses this API and has the same restriction.

### Docker actions

`POST /api/docker/containers/:id/:action` where action is one of: `start`, `stop`, `restart`, `pause`, `unpause`

### VM actions

`POST /api/vms/:id/:action` where action is one of: `start`, `stop`, `force-stop`, `pause`, `resume`, `reboot`, `reset`

### Share update

`PATCH /api/shares/:name` accepts:

```json
{
  "comment": "My share description",
  "allocator": "highwater",
  "splitLevel": "1",
  "floor": "0"
}

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [emaspa](https://github.com/emaspa)
- **Source:** [emaspa/unraidclaw](https://github.com/emaspa/unraidclaw)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-emaspa-unraidclaw
- Seller: https://agentstack.voostack.com/s/emaspa
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
