This commit is contained in:
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(npm --version)",
|
||||||
|
"Bash(npm install *)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,294 @@
|
|||||||
|
# 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.com` once the existing `gitea-mcp` proxy is repointed
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. Prerequisites
|
||||||
|
|
||||||
|
### Gitea Container Registry login
|
||||||
|
|
||||||
|
The image lives in your private Gitea registry, so the Unraid host needs credentials.
|
||||||
|
|
||||||
|
1. Open the Unraid web UI → **Console** (top right) or SSH into the box.
|
||||||
|
2. Run:
|
||||||
|
```bash
|
||||||
|
docker login git.alwisp.com
|
||||||
|
```
|
||||||
|
3. Enter your Gitea username and a personal access token (with `read:packages` scope). Credentials are saved to `/root/.docker/config.json`.
|
||||||
|
|
||||||
|
### Confirm `br0` and pick the IP
|
||||||
|
|
||||||
|
- `br0` should already exist (every other ALPHA container uses it).
|
||||||
|
- Reserve **`10.2.0.35`** for totalmcp (next free above codedump @ `.34`).
|
||||||
|
- If `.35` is taken when you go to assign it, pick the next free IP and update `PLAN.md` + `SERVICES.md` to match.
|
||||||
|
|
||||||
|
### Pre-create the appdata directory
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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 `br0` instead of `bridge`?** 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 `br0` and 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`, but `start`/`stop`/`restart` require 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 `docker` plugin 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](.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
|
||||||
|
|
||||||
|
1. Click **Apply** at the bottom of the Add Container form.
|
||||||
|
2. Unraid pulls the image from `git.alwisp.com/jason/totalmcp:latest` and starts the container.
|
||||||
|
3. Watch the **Docker tab** — totalmcp should show **started** within 5–10 seconds.
|
||||||
|
|
||||||
|
### Liveness check
|
||||||
|
|
||||||
|
From the Unraid console (or any LAN host):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://10.2.0.35:8811/health
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "ok",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"plugins": 8,
|
||||||
|
"enabled": ["gitea","unraid","docker","openclaw","unifi","codex-mrp","streamvault","rackmapper"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Plugin diagnostics
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker logs totalmcp | grep -E "plugin_(loaded|connect_failed|invalid)"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Connect Claude Code
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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)
|
||||||
|
|
||||||
|
1. Docker tab → **totalmcp** → click the icon → **Force Update**.
|
||||||
|
2. Unraid pulls `git.alwisp.com/jason/totalmcp:latest` and restarts the container in place.
|
||||||
|
3. 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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker logs totalmcp
|
||||||
|
```
|
||||||
|
|
||||||
|
Common causes:
|
||||||
|
- **`Invalid environment configuration`** — `AGENT_TOKENS` malformed or `PORT` not 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., `dockerode` or `better-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.sqlite` exists on the host.
|
||||||
|
- Confirm the path mapping is `/app/codex/db.sqlite` (file path, not directory).
|
||||||
|
- Confirm `CODEX_DB_PATH=/app/codex/db.sqlite` matches.
|
||||||
|
|
||||||
|
### `unraid` plugin: `unraid_connect_failed`
|
||||||
|
|
||||||
|
- Run `unraid-api status` on the host to confirm the API plugin is running.
|
||||||
|
- Confirm `UNRAID_API_KEY` matches the key from `unraid-api key`.
|
||||||
|
|
||||||
|
### Authentication 401s from Claude Code
|
||||||
|
|
||||||
|
- Token mismatch — the `AGENT_TOKENS` value 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.
|
||||||
@@ -214,11 +214,15 @@ export interface MCPTool {
|
|||||||
| Network | `br0` |
|
| Network | `br0` |
|
||||||
| IP | `10.2.0.35` (next available static; `gitea-mcp` already owns `10.2.0.16:8081` and remains undisturbed during transition) |
|
| IP | `10.2.0.35` (next available static; `gitea-mcp` already owns `10.2.0.16:8081` and remains undisturbed during transition) |
|
||||||
| Port | `8811:8811` |
|
| Port | `8811:8811` |
|
||||||
| Appdata | `/mnt/user/appdata/totalmcp → /app/data` |
|
| Appdata | `/mnt/user/appdata/totalmcp/data → /app/data` |
|
||||||
| Env File | `/mnt/user/appdata/totalmcp/.env` |
|
| Logs | `/mnt/user/appdata/totalmcp/logs → /app/logs` |
|
||||||
| Docker Socket | `/var/run/docker.sock → /var/run/docker.sock` |
|
| Docker Socket | `/var/run/docker.sock → /var/run/docker.sock` (RW, required for Phase 2 docker plugin) |
|
||||||
|
| CODEX DB | `/mnt/user/appdata/codex/db.sqlite → /app/codex/db.sqlite` (Phase 3 codex-mrp plugin) |
|
||||||
|
| Variables | Set per-plugin env vars in the Unraid GUI (see `INSTALL-UNRAID.md`) |
|
||||||
| Restart Policy | `unless-stopped` |
|
| Restart Policy | `unless-stopped` |
|
||||||
| Pids Limit | `2048` |
|
| Pids Limit | `2048` (via Extra Parameters: `--pids-limit=2048`) |
|
||||||
|
|
||||||
|
> **Full GUI walkthrough:** [`INSTALL-UNRAID.md`](INSTALL-UNRAID.md) — every field, env var, and verification step.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -31,13 +31,17 @@ npm run build # tsc → dist/
|
|||||||
npm start # node dist/server.js
|
npm start # node dist/server.js
|
||||||
```
|
```
|
||||||
|
|
||||||
## Docker
|
## Docker (local dev)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose up --build -d
|
docker compose up --build -d
|
||||||
docker compose logs -f totalmcp
|
docker compose logs -f totalmcp
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Unraid deployment
|
||||||
|
|
||||||
|
Step-by-step GUI walkthrough — paths, variables, ports, network — lives in [`INSTALL-UNRAID.md`](INSTALL-UNRAID.md). Covers the full deploy at `10.2.0.35:8811` plus a minimal "Gitea-plugin-only" starter config.
|
||||||
|
|
||||||
## Endpoints
|
## Endpoints
|
||||||
|
|
||||||
| Method | Path | Auth | Purpose |
|
| Method | Path | Auth | Purpose |
|
||||||
|
|||||||
Generated
+2898
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user