11 KiB
Unraid Install Guide — totalmcp
Step-by-step walkthrough for deploying the totalmcp gateway on Unraid using the Docker Add Container GUI. Targets Unraid 6.12+ / 7.0+.
After installing, totalmcp is reachable at:
- LAN:
http://10.2.0.35:8811 - Health:
http://10.2.0.35:8811/health(no auth) - MCP endpoint:
http://10.2.0.35:8811/mcp(Bearer token required) - Public proxy (optional, after NPM entry):
https://mcp.alwisp.comonce the existinggitea-mcpproxy is repointed
0. Prerequisites
Gitea Container Registry login
The image lives in your private Gitea registry, so the Unraid host needs credentials.
- Open the Unraid web UI → Console (top right) or SSH into the box.
- Run:
docker login git.alwisp.com - Enter your Gitea username and a personal access token (with
read:packagesscope). Credentials are saved to/root/.docker/config.json.
Confirm br0 and pick the IP
br0should already exist (every other ALPHA container uses it).- Reserve
10.2.0.35for totalmcp (next free above codedump @.34). - If
.35is taken when you go to assign it, pick the next free IP and updatePLAN.md+SERVICES.mdto match.
Pre-create the appdata directory
mkdir -p /mnt/user/appdata/totalmcp/data
mkdir -p /mnt/user/appdata/totalmcp/logs
chown -R 99:100 /mnt/user/appdata/totalmcp
(99:100 = nobody:users, the standard Unraid container ownership.)
1. Add Container — top-level fields
Docker tab → Add Container
| Field | Value |
|---|---|
| Name | totalmcp |
| Overview | Unified MCP gateway for ALPHA — exposes every backend service to Claude Code, Codex, Antigravity |
| Repository | git.alwisp.com/jason/totalmcp:latest |
| Docker Hub URL | (leave blank — private registry) |
| Icon URL | (optional — set later) |
| WebUI | http://[IP]:[PORT:8811]/health |
| Extra Parameters | --pids-limit=2048 |
| Post Arguments | (leave blank) |
| Network Type | Custom: br0 |
| Use IPv4 only | ☑ checked |
| Fixed IP address (optional) | 10.2.0.35 |
| Privileged | ☐ unchecked |
| Console shell command | Shell |
| Auto update / Restart Policy | unless-stopped |
Why
br0instead ofbridge? br0 gives the gateway its own LAN IP so agents on workstations connect directly without going through Unraid's port-mapped 10.2.0.2:8811. Matches the rest of the ALPHA service catalog.
2. Port mappings
Click Add another Path, Port, Variable, Label or Device → Port.
| Container Port | Host Port | Connection Type | Description |
|---|---|---|---|
8811 |
8811 |
TCP |
MCP gateway (HTTP + SSE) |
With
br0and a fixed IP, the host-port column is mostly cosmetic — the container has its own IP. Listed for completeness.
3. Path mappings
Click Add Path for each row.
Required
| Container Path | Host Path | Access Mode | Description |
|---|---|---|---|
/app/data |
/mnt/user/appdata/totalmcp/data |
Read/Write |
SQLite event log + plugin runtime data |
/app/logs |
/mnt/user/appdata/totalmcp/logs |
Read/Write |
Structured JSON logs (Phase 5) |
Required if docker plugin is enabled (Phase 2)
| Container Path | Host Path | Access Mode | Description |
|---|---|---|---|
/var/run/docker.sock |
/var/run/docker.sock |
Read/Write |
Docker socket — needed for start/stop/restart |
Read-only is enough for
docker_list_containers/get_logs/get_stats, butstart/stop/restartrequire RW.
Required if codex-mrp plugin is enabled (Phase 3)
| Container Path | Host Path | Access Mode | Description |
|---|---|---|---|
/app/codex/db.sqlite |
/mnt/user/appdata/codex/db.sqlite |
Read/Write |
CODEX SQLite database |
Plugin reads in WAL mode so concurrent reads with CODEX itself are safe. Writes (
codex_create_work_order) bypass CODEX validation — use the CODEX UI for routine work-order creation.
4. Environment variables
Click Add Variable for each row. Group by phase — only add variables for plugins you're enabling now.
Core (always required)
| Variable | Value | Description |
|---|---|---|
NODE_ENV |
production |
|
PORT |
8811 |
Must match the port mapping above |
LOG_LEVEL |
info |
debug / info / warn / error |
GATEWAY_VERSION |
0.1.0 |
|
PLUGINS_DIR |
./dist/plugins |
(default — only override for advanced setups) |
ENABLED_PLUGINS |
gitea,unraid,docker,openclaw,unifi,codex-mrp,streamvault,rackmapper |
Comma-separated. Trim to only the plugins you've configured. |
AGENT_TOKENS |
claude-code:TOKEN1,antigravity:TOKEN2,codex:TOKEN3 |
Generate with openssl rand -hex 32. Save the same tokens in your agent configs. |
Phase 1 — Gitea + Unraid
| Variable | Value | Required for plugin |
|---|---|---|
GITEA_HOST |
https://git.alwisp.com |
gitea |
GITEA_TOKEN |
(Gitea PAT with repo + issue + admin scopes) | gitea |
UNRAID_HOST |
http://10.2.0.2 |
unraid |
UNRAID_API_KEY |
(generated via unraid-api start on the host) |
unraid |
Phase 2 — Docker + OpenClaw
| Variable | Value | Required for plugin |
|---|---|---|
OPENCLAW_HOST |
http://10.2.0.26:18789 |
openclaw (NOVA) |
The
dockerplugin needs no env vars — it uses the mounted socket.
Phase 3 — Service Connectors
| Variable | Value | Required for plugin |
|---|---|---|
UNIFI_HOST |
https://<your-unifi-controller> |
unifi |
UNIFI_API_KEY |
(UniFi Access → Settings → Security → API tokens) | unifi |
UNIFI_SITE_ID |
(your site UUID, optional) | unifi |
CODEX_DB_PATH |
/app/codex/db.sqlite |
codex-mrp (must match the path mapping above) |
STREAMVAULT_HOST |
http://streamvault:3100 |
streamvault (skip until StreamVault is deployed) |
STREAMVAULT_TOKEN |
(if StreamVault requires auth) | streamvault (optional) |
RACKMAPPER_HOST |
http://10.2.0.23 |
rackmapper |
RACKMAPPER_TOKEN |
(if RackMapper requires auth) | rackmapper (optional) |
Phase 6 — Deferred
| Variable | Value | Required for plugin |
|---|---|---|
CHRONICLE_HOST |
(after deploy) | chronicle (deferred) |
CHRONICLE_TOKEN |
(after deploy) | chronicle (deferred) |
OBSIDIAN_REST_HOST |
http://10.2.0.2:27123 |
obsidian (deferred) |
OBSIDIAN_API_KEY |
(Obsidian Local REST API plugin) | obsidian (deferred) |
Phase 7+ (defer until Phase 7 ships)
The full set is documented in .env.example — NPM_*, UISP_*, TRANSMISSION_*, SYNCTHING_*, PLEX_*, NYAA_*, HA_*, INVOICENINJA_*, FABDASH_*, CPAS_*, WFH_*, BREEDR_*, CODEDUMP_*, UITRACKER_*, STEPVIEW_*, QRKNIT_*, MEMER_*, ALWISP_WEB_*. Add only when those plugin phases land.
5. Apply & verify
- Click Apply at the bottom of the Add Container form.
- Unraid pulls the image from
git.alwisp.com/jason/totalmcp:latestand starts the container. - Watch the Docker tab — totalmcp should show started within 5–10 seconds.
Liveness check
From the Unraid console (or any LAN host):
curl http://10.2.0.35:8811/health
Expected:
{
"status": "ok",
"version": "0.1.0",
"plugins": 8,
"enabled": ["gitea","unraid","docker","openclaw","unifi","codex-mrp","streamvault","rackmapper"]
}
Plugin diagnostics
curl -H "Authorization: Bearer <CLAUDE_CODE_TOKEN>" http://10.2.0.35:8811/plugins
You'll see a per-plugin breakdown with tool counts. If a plugin is missing, check the container logs:
docker logs totalmcp | grep -E "plugin_(loaded|connect_failed|invalid)"
Connect Claude Code
claude mcp add --scope user --transport http totalmcp http://10.2.0.35:8811/mcp \
-H "Authorization: Bearer <CLAUDE_CODE_TOKEN>"
Then run /mcp inside Claude Code — the totalmcp tools should appear in the catalog.
6. Updates
Manual (one-time)
- Docker tab → totalmcp → click the icon → Force Update.
- Unraid pulls
git.alwisp.com/jason/totalmcp:latestand restarts the container in place. - Re-verify via
curl /health.
Automated (Phase 4 — Gitea Actions CI)
Once the CI pipeline lands, every push to main rebuilds the image. To pick up updates without manual intervention:
- Set Unraid's update polling to a short interval (Settings → Docker → "Check for updates every"), or
- Hit the Docker tab → Check for Updates button when ready.
7. Troubleshooting
/health returns 500 or container crash-loops
Check the logs:
docker logs totalmcp
Common causes:
Invalid environment configuration—AGENT_TOKENSmalformed orPORTnot a number. Fix the Variable in the Unraid GUI and the container will auto-restart.Cannot find module ...— image was built without one of the new deps (e.g.,dockerodeorbetter-sqlite3). Force-update to pull the latest image.
docker plugin: docker_connect_failed
Confirm the path mapping is /var/run/docker.sock → /var/run/docker.sock with Read/Write access mode.
codex-mrp plugin: codex_mrp_connect_failed
- Check that
/mnt/user/appdata/codex/db.sqliteexists on the host. - Confirm the path mapping is
/app/codex/db.sqlite(file path, not directory). - Confirm
CODEX_DB_PATH=/app/codex/db.sqlitematches.
unraid plugin: unraid_connect_failed
- Run
unraid-api statuson the host to confirm the API plugin is running. - Confirm
UNRAID_API_KEYmatches the key fromunraid-api key.
Authentication 401s from Claude Code
- Token mismatch — the
AGENT_TOKENSvalue in Unraid must contain the same token Claude Code is sending. - Format reminder:
agentName:token,agentName2:token2(no spaces, comma-separated).
Port collision on 8811
If something else on 10.2.0.35 (or your chosen IP) already binds 8811, change PORT and the port mapping to 8812 (or whichever) and update agent configs accordingly. The PLAN.md default is 8811.
8. Reference: minimal viable install
If you just want the gateway running with only the Gitea plugin to start:
| Setting | Value |
|---|---|
| Repository | git.alwisp.com/jason/totalmcp:latest |
| Network / IP | br0 / 10.2.0.35 |
| Port | 8811:8811 TCP |
| Path | /app/data → /mnt/user/appdata/totalmcp/data (RW) |
Variable NODE_ENV |
production |
Variable PORT |
8811 |
Variable AGENT_TOKENS |
claude-code:<your-token> |
Variable ENABLED_PLUGINS |
gitea |
Variable GITEA_HOST |
https://git.alwisp.com |
Variable GITEA_TOKEN |
(your PAT) |
Apply, verify with curl /health, then expand by adding more variables and updating ENABLED_PLUGINS as each phase comes online.