Unraid Code Mode
БесплатноНе проверенA code-mode MCP server for the Unraid 7.2+ GraphQL API that exposes search and execute tools, allowing LLM agents to introspect and call any GraphQL field via s
Описание
A code-mode MCP server for the Unraid 7.2+ GraphQL API that exposes search and execute tools, allowing LLM agents to introspect and call any GraphQL field via sandboxed JavaScript.
README
CI License: MIT Status: beta Version: v0.1.0-beta.3
A code-mode MCP server for the Unraid 7.2+ GraphQL API. Exposes two MCP tools — search and execute — that let an LLM agent introspect and call any Unraid GraphQL field by writing JavaScript that runs inside a sandboxed QuickJS WASM context.
Built as the GraphQL-flavoured sibling of unifi-code-mode-mcp and fortimanager-code-mode-mcp. Same architecture, same sandbox model, adapted to GraphQL introspection instead of OpenAPI.
Project status
This is a public beta. Install from source. Not on npm yet.
The server boots, both tools work, and the test suite is green (56/56 unit + integration tests across spec loader, dispatcher, sandbox, HTTP client, multi-tenant context, and server transports). A standalone
npm run test:sandboxscript exercises the QuickJS sync + Promise-callback host bridge with 25 sequential awaits, a 10-wayPromise.all, mixed sequential/parallel patterns, and error propagation — these are the patterns LLMs actually emit, and they are the regression bar for the bridge.Verified live against a single real Unraid 7.2 box (the maintainer's homelab) via
scripts/mcp-call.mjsdriving the stdio transport directly:info,array,shares,vms,docker, andonlinereads succeed; the VMSHUTOFF → RUNNING → SHUTOFFcycle viavmStart/vmStopmutations succeeds; sequential awaits andPromise.allboth work end-to-end with real GraphQL latency; and the bundled SDL fallback path (introspection disabled) returns a human-readable diagnostic with a remediation hint instead of an opaqueHTTP 400. The bundled SDL is pinned to a tagged unraid/api release (currentlyv4.33.0, nomain-drift) and the introspection-disabled fallback is exercised by unit tests.End-to-end LLM-mediated invocation is verified through two clients against the same Unraid 7.2 box:
Client Model Status Transcript cursor-agentv2026.05.05Claude Sonnet 4.6 ( claude-4.6-sonnet-medium)VERIFIED — 3 prompts including a full live info/array/shares/vms/docker/onlineoverview rendered to a Markdown table; error-path prompt handled correctly without invented recoveryout/verification/cursor-agent-sonnet-mcp-call.txt opencodev1.14.30DeepSeek v4 Flash via opencode-go/deepseek-v4-flashVERIFIED on schema-only path; live execute hit a mid-test upstream CSRF flip — schema smoke (102 ops) green; the live overview produced valid Promise.alltyped-query code on the first try and the model handled the upstreamInvalid CSRF token / 401gracefully (explained, suggested re-auth, did not flail)out/verification/opencode-deepseek-mcp-call.txt See examples/unraid-expert-agent/ for the persona (AGENTS.md), a vetted set of sample prompts, and cross-platform install snippets.
NOT verified by us (and where help is welcome): every agent / IDE client beyond cursor-agent CLI and opencode — Cursor IDE chat panel, Claude Code, Claude Desktop, VS Code + Copilot, Codex CLI, Continue, Cline, Aider, Zed, MCP Inspector (CLI + UI); the Streamable HTTP transport in multi-tenant mode; the Cloudflare Workers entry (scaffolded but not deployed); any non-VM mutation (Docker container start/stop, share/disk operations, parity ops); any Unraid box other than the maintainer's. We need testers — please file verification reports and bug reports with whatever you find. See CONTRIBUTING.md for the rules.
Why "code mode"?
The default MCP pattern is one tool per API operation. A typical Unraid 7.2 schema has ~57 queries and ~45 mutations across 240+ types — registering all of those as discrete MCP tools blows past every commercial agent's tool-list cap.
Code mode flips that: instead of a hundred tools, you get two. The LLM uses search to figure out what to call (no network), then writes a tiny JS snippet for execute that talks to the live API. See Cloudflare's code mode post for the full pattern, or the architecture doc for the per-module breakdown.
Highlights
- Two tools.
searchis read-only;executeruns sandboxed JS that calls real Unraid GraphQL. - Typed convenience calls.
unraid.local.query.<fieldName>({ args, fields })andunraid.local.mutation.<fieldName>({ args, fields })synthesise the GraphQL document for you using introspected arg types. - Raw escape hatch.
unraid.local.graphql({ query, variables })posts any document;unraid.local.request({ method, path, body })covers the rare non-GraphQL endpoints. - Single- and multi-user modes. Single-user via env vars (stdio), multi-user via
X-Unraid-Api-KeyHTTP headers. - Per-tenant TLS. Custom CA bundles or
insecuremode survive into a per-request undici dispatcher. - Bundled SDL fallback. Server can boot without an Unraid server — it parses the latest committed
src/spec/local-fallback.graphqlsosearchis immediately useful. - Cloudflare Workers entry. A scaffold using
@cloudflare/codemodeships incf-worker/. See cf-worker/README.md.
Quick start
git clone https://github.com/jmpijll/unraid-code-mode-mcp
cd unraid-code-mode-mcp
npm install --legacy-peer-deps
cp .env.example .env
# edit .env — set UNRAID_BASE_URL + UNRAID_API_KEY
npm run dev
Wire it into your MCP client. For Cursor, add to .cursor/mcp.json:
{
"mcpServers": {
"unraid": {
"command": "node",
"args": ["/absolute/path/to/unraid-code-mode-mcp/dist/index.js"]
}
}
}
(Run npm run build first if you point at dist/. Or use npx tsx against src/index.ts for live development.)
Creating an Unraid API key
The API key is what authenticates the MCP server's calls to your Unraid box. Two ways to mint one:
Option A — Web UI. Go to Settings → Management Access → API Keys and create a key with the ADMIN role (or scope it down to whatever you actually want the agent to do). Copy the value into UNRAID_API_KEY.
Option B — CLI on the Unraid box. SSH in and run:
unraid-api apikey --create --name "mcp" --roles ADMIN --json
The JSON output contains a key field; that's UNRAID_API_KEY.
UNRAID_BASE_URL should be the URL you'd visit in a browser to reach the web UI (no path, no trailing slash) — e.g. https://tower.local or https://192.168.1.10.
TLS on Unraid
Unraid 7.2+ usually serves over HTTPS using a self-signed *.unraid.net certificate fronted by the LAN proxy. The MCP server has three options:
- Recommended: install the Unraid root CA on the host, or fetch it and pass
UNRAID_CA_CERT_PATH=/path/to/ca.pem. - Lab use:
UNRAID_INSECURE=trueskips verification. Logged on every request. - Multi-tenant: clients can supply
X-Unraid-Ca-Certand/orX-Unraid-Insecure: trueper request.
See docs/security.md for the full picture.
Sample interactions
Discover the schema:
// search tool
searchOperations('docker', 10).map(function (op) { return op.name + ' (' + op.kind + ')'; });
// search tool — drill into a single op
getOperation('info');
Run a query (verified live on Unraid 7.2):
// execute tool
const info = await unraid.local.query.info({
fields: ['os { distro release kernel uptime }', 'cpu { manufacturer brand cores threads }'].join(' '),
});
return info;
Read multiple things — sequential await and Promise.all both work:
// execute tool — sequential awaits (fine; full canonical async)
const info = await unraid.local.query.info({ fields: 'os { distro }' });
const arr = await unraid.local.query.array({ fields: 'state' });
const shares = await unraid.local.query.shares({ fields: 'name free used size' });
return { info, arr, shares };
// execute tool — parallel batch (faster when calls are independent)
const [info, arr, shares, online] = await Promise.all([
unraid.local.graphql({ query: 'query { info { os { distro release kernel } cpu { brand cores threads } } }' }),
unraid.local.graphql({ query: 'query { array { state } }' }),
unraid.local.graphql({ query: 'query { shares { name free used size } }' }),
unraid.local.graphql({ query: 'query { online }' }),
]);
return { info, arr, shares, online };
Run a mutation:
// execute tool
return await unraid.local.mutation.archiveAll({});
Fall back to raw GraphQL:
// execute tool
const data = await unraid.local.graphql({
query: 'query { array { state capacity { kilobytes { free total } } } }',
});
return data;
Documentation
- Usage guide — the search/execute API in detail.
- Architecture — per-module breakdown, request lifecycle.
- Multi-tenant deployment — HTTP transport + headers.
- Deployment — Node / Docker / Cloudflare.
- Security — sandbox properties, TLS, Unraid 7.2 CSRF behaviour, threat model.
- Cursor coupling guide —
.cursor/mcp.jsonshapes,cursor-agentquirks, smoke commands. - opencode coupling guide —
opencode.jsonshape, permissions, headless verification. - Verification transcripts — sanitized records of every live end-to-end run we have.
Verifying your install
npm run build
npm test # 65 unit + integration tests
npm run test:sandbox # QuickJS host-bridge stress (no Unraid box needed)
npm run smoke:inspector # MCP Inspector CLI smoke against built dist (no Unraid box needed)
If smoke:inspector prints OK: both 'search' and 'execute' tools exposed by dist/index.js, your build is wire-compatible with any MCP client. The sandbox stress doubles as the regression bar for the Promise-callback host bridge.
Multi-user / multi-tenant
Run with MCP_TRANSPORT=http and without env credentials. The MCP HTTP transport listens on POST /mcp + GET /health, and every request must carry:
X-Unraid-Api-KeyX-Unraid-Base-UrlX-Unraid-Insecure(optional,trueto skip TLS verification)X-Unraid-Ca-Cert(optional, PEM-encoded CA bundle)
Origin allowlist defaults to localhost; tune via MCP_HTTP_ALLOWED_ORIGINS. See docs/multi-tenant.md.
Verification status
What we have directly verified so far:
| Layer | How | Result |
|---|---|---|
| Unit tests | Vitest, 56 specs across spec loader, dispatcher, sandbox, HTTP client, multi-tenant context, and server transports | ✅ all green |
| Integration tests | In-process node:http GraphQL mock + InMemoryTransport against createMcpServer; covers sequential awaits, Promise.all, mixed query/mutation/raw GraphQL, error propagation, and the per-execute call budget |
✅ green |
| QuickJS host-bridge stress | npm run test:sandbox — 25 sequential awaits, 10-way Promise.all, mixed patterns, rejection propagation through await |
✅ green; this is the regression bar after the asyncify → sync + Promise-callback rewrite |
| SDL fallback (introspection disabled) | Server boots without an Unraid box, parses bundled src/spec/local-fallback.graphql (pinned to unraid/[email protected]), search is immediately usable; runtime fallback path also exercised by unit tests against a mock that returns INTROSPECTION_DISABLED |
✅ green; the INTROSPECTION_DISABLED error returns a human-readable diagnostic with a remediation hint (unraid-api developer --sandbox true) instead of HTTP 400 |
| Live read sweep on a real Unraid 7.2 box | scripts/mcp-call.mjs driving stdio transport against the maintainer's homelab: info, array, shares, vms, docker, online |
✅ all queries returned real data; sequential awaits and Promise.all both worked end-to-end with real GraphQL latency |
| Live mutation round-trip on the same box | VM SHUTOFF → RUNNING → SHUTOFF cycle via vmStart / vmStop mutations, with state polled via vms.domain.state between transitions |
✅ full cycle completed; error propagation verified by attempting vmStart on an already-running VM (returns Failed to set VM state: Invalid state transition from RUNNING to RUNNING cleanly through await) |
| Linter + formatter + typecheck | npm run lint / npm run format:check / npm run typecheck |
✅ clean |
What is not yet verified (and where help is welcome):
- Any agent / IDE client. All live verification so far has been through
scripts/mcp-call.mjsdriving the stdio transport directly. Cursor (chat panel), Claude Code, Claude Desktop, VS Code + Copilot, Codex CLI, Continue, Cline, opencode, Aider, Zed, the MCP Inspector (CLI and UI) — all wired but NOT verified by us. End-to-end LLM-mediated invocation is the most useful thing testers can report on. - Streamable HTTP transport in multi-tenant mode. The transport is wired and unit-tested; a real multi-tenant deployment behind a reverse proxy with header-based credentials is not.
- Cloudflare Workers entry.
cf-worker/is scaffolded against@cloudflare/codemodebut the WebRequest/Response↔ MCP SDK Node-stream adapter is not implemented, and the Worker is not deployed anywhere. Tracked in cf-worker/README.md. - Mutations beyond VM start/stop. Docker container
start/stop, parity checkstart/cancel, share / disk operations, user / API-key management, and the full mutation surface are wired through the typed dispatcher but not live-verified. Probing them blindly against live hardware is unsafe; we want testers with redundant homelabs. - Unraid Connect cloud surface.
unraid.connect.*is reserved inTenantContextand not yet implemented. The current server only talks to a controller you can reach over the LAN. - Real Unraid boxes other than the maintainer's homelab. A single Unraid 7.2 box is not enough to generalise resilience claims — different array configs, plugin sets, network topologies, and Unraid versions will all surface different edge cases.
- Long-running soak / stability under sustained load.
Roadmap
Done in v0.1.0-beta.2 and v0.1.0-beta.3:
- ✅ Expose the sandbox wall-clock deadline as
UNRAID_EXECUTE_TIMEOUT_MS(1 s – 10 min, default 30 s). Useful for slow-booting VMs and for very largePromise.allbatches against a controller under load. (beta.2) - ✅ CSRF-aware error decoration — when an Unraid box returns
extensions.code: UNAUTHENTICATED+Invalid CSRF token, the MCP server adds a remediation hint pointing at API key re-mint, the curl sanity check, and the box-side log path. See docs/security.md. (beta.2) - ✅ MCP
serverInfo.versionreads frompackage.jsonat runtime — no more hand-stamped version drift between releases. (beta.2) - ✅ End-to-end LLM-mediated invocation verification through
cursor-agent(Claude Sonnet 4.6) andopencode(DeepSeek v4 Flash). See the verification matrix above. (beta.2) - ✅ Auto-bump bundled SDL pin —
.github/workflows/update-spec.ymlruns weekly, detects new unraid/api releases, regeneratessrc/spec/local-fallback.graphql, and opens a PR with a release-notes link for human review. (beta.3) - ✅
npm run smoke:inspector— local mirror of the CI MCP Inspector smoke. Boots the builtdist/index.jsserver, requeststools/list, asserts both tools are exposed. CI now uses the same script. (beta.3)
Still open (rough order, highest-leverage first):
- More LLM clients verified — Claude Code CLI, Claude Desktop, MCP Inspector UI (CLI smoke is in CI), VS Code + Copilot. Roadmap item, gating for
1.0.0. - Streamable HTTP multi-tenant deployment verified against a real reverse proxy with rotating per-tenant credentials.
- Mutation verification matrix beyond VM start/stop — Docker container lifecycle, parity checks, share/disk ops — once we have testers with redundant hardware.
unraid.connect.*namespace for the Unraid Connect cloud API. Reserved inTenantContexttoday, not yet implemented.- Cloudflare Workers transport adapter (the bridge from Web
Request/Responseto the MCP SDK's NodeIncomingMessage/ServerResponse). Tracked in cf-worker/README.md. - NPM publish — reserved for
1.0.0. The package is"private": trueuntil then.
Contributing
See CONTRIBUTING.md. Use Conventional Commits (feat:, fix:, chore:, docs:, test:, ci:).
License
MIT — see LICENSE.
Установка Unraid Code Mode
У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.
▸ github.com/jmpijll/unraid-code-mode-mcpFAQ
Unraid Code Mode MCP бесплатный?
Да, Unraid Code Mode MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для Unraid Code Mode?
Нет, Unraid Code Mode работает без API-ключей и переменных окружения.
Unraid Code Mode — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить Unraid Code Mode в Claude Desktop, Claude Code или Cursor?
Открой Unraid Code Mode на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
GitHub
PRs, issues, code search, CI status
автор: GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
автор: mcpdotdirectCompare Unraid Code Mode with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории development
