docs: reconcile sunset of LiteLLM external, mcp-gateway, and LobeChat

- Bifrost replaces LiteLLM at ai.nuclide.systems (CT 104:14003); LiteLLM
  now internal-only backend at :14000
- mcp-gateway (FastAPI/DinD, mcp.nuclide.systems) decommissioned 2026-05-26;
  MCP now served by Bifrost at ai.nuclide.systems/mcp (29 clients, ~760 tools)
- LobeChat decommissioned 2026-05-26; chat.nuclide.systems now Open WebUI
  (CT 104:14002, stack ai/open-webui.yml)
- Update portmap, volumes, services-overview, homelab-architecture, zoraxy,
  mcp-servers, databases, README accordingly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-26 13:35:29 +02:00
parent 550b54085c
commit 6c401f2376
8 changed files with 119 additions and 158 deletions
+2 -2
View File
@@ -22,7 +22,7 @@ Single source of truth for the homelab. Git-tracked since 2026-05-20.
├── services/ ← per-service operational docs (current truth) ├── services/ ← per-service operational docs (current truth)
│ ├── homelab-architecture.md topology + design rationale │ ├── homelab-architecture.md topology + design rationale
│ ├── dev-environment.md Coder + Gitea on CT 111 │ ├── dev-environment.md Coder + Gitea on CT 111
│ ├── mcp-gateway.md MCP gateway on CT 104 │ ├── mcp-gateway.md MCP gateway — DECOMMISSIONED 2026-05-26; see mcp-servers.md for Bifrost
│ ├── comfyui.md │ ├── comfyui.md
│ ├── zoraxy.md reverse proxy │ ├── zoraxy.md reverse proxy
│ ├── adguard-dns.md DNS + rewrites │ ├── adguard-dns.md DNS + rewrites
@@ -83,7 +83,7 @@ See [`/CLAUDE.md`](../CLAUDE.md) for the full doctrine. Highlights:
| Alloy UI | `http://192.168.1.8:12345` | Log agent pipeline inspector | | Alloy UI | `http://192.168.1.8:12345` | Log agent pipeline inspector |
### Public services (`*.nuclide.systems`) ### Public services (`*.nuclide.systems`)
- **AI**: [ai.nuclide.systems](https://ai.nuclide.systems) (LiteLLM) · [chat.nuclide.systems](https://chat.nuclide.systems) (LobeHub) · [mcp.nuclide.systems](https://mcp.nuclide.systems) (MCP Gateway) - **AI**: [ai.nuclide.systems](https://ai.nuclide.systems) (Bifrost — LLM + MCP gateway) · [chat.nuclide.systems](https://chat.nuclide.systems) (Open WebUI)
- **Files**: [nc.nuclide.systems](https://nc.nuclide.systems) (Nextcloud) · [paperless.nuclide.systems](https://paperless.nuclide.systems) · [immich.nuclide.systems](https://immich.nuclide.systems) - **Files**: [nc.nuclide.systems](https://nc.nuclide.systems) (Nextcloud) · [paperless.nuclide.systems](https://paperless.nuclide.systems) · [immich.nuclide.systems](https://immich.nuclide.systems)
- **Dev**: [git.nuclide.systems](https://git.nuclide.systems) (Gitea) · [dev.nuclide.systems](https://dev.nuclide.systems) (Coder) - **Dev**: [git.nuclide.systems](https://git.nuclide.systems) (Gitea) · [dev.nuclide.systems](https://dev.nuclide.systems) (Coder)
- **Home**: [ha.nuclide.systems](https://ha.nuclide.systems) (Home Assistant) · [hoarder.nuclide.systems](https://hoarder.nuclide.systems) (Karakeep) · [memos.nuclide.systems](https://memos.nuclide.systems) - **Home**: [ha.nuclide.systems](https://ha.nuclide.systems) (Home Assistant) · [hoarder.nuclide.systems](https://hoarder.nuclide.systems) (Karakeep) · [memos.nuclide.systems](https://memos.nuclide.systems)
+10 -10
View File
@@ -106,10 +106,11 @@ All arr-stack services run behind `vpn_gluetun` container network.
| Port | Service | Container | Public URL | Notes | | Port | Service | Container | Public URL | Notes |
|---|---|---|---|---| |---|---|---|---|---|
| [14000](http://192.168.1.40:14000) | LiteLLM | `litellm` | [ai.nuclide.systems](https://ai.nuclide.systems) | LLM proxy gateway | | [14000](http://192.168.1.40:14000) | LiteLLM | `litellm` | — | LLM proxy gateway — **internal only** (no Zoraxy route); Bifrost proxies to it at `http://litellm:4000` |
| [14001](http://192.168.1.40:14001) | LobeHub | `lobehub` | [chat.nuclide.systems](https://chat.nuclide.systems) | Chat UI | | ~~14001~~ | ~~LobeHub~~ | ~~`lobehub`~~ | — | **DECOMMISSIONED 2026-05-26** — compose renamed `.DECOMMISSIONED-lobehub-2026-05-26.yml`; replaced by Open WebUI |
| [14002](http://192.168.1.40:14002) | Qdrant | `qdrant_scientific` | — | Vector DB, internal only | | [14002](http://192.168.1.40:14002) | Open WebUI | `open-webui` | [chat.nuclide.systems](https://chat.nuclide.systems) | Chat UI; stack `ai/open-webui.yml`; uses Qdrant + TEI for RAG |
| [8080](http://192.168.1.40:8080) | MCP Gateway | `mcp-gateway` | [mcp.nuclide.systems](https://mcp.nuclide.systems) | Pocket ID gated; spawns MCP servers on `ai-internal` | | [14003](http://192.168.1.40:14003) | Bifrost | `bifrost` | [ai.nuclide.systems](https://ai.nuclide.systems) | LLM gateway + MCP at `/mcp`; auth via `sk-bf-` VKs; stack `ai/bifrost/` |
| ~~8080~~ | ~~MCP Gateway~~ | ~~`mcp-gateway`~~ | — | **DECOMMISSIONED 2026-05-26** — compose renamed `.DECOMMISSIONED-2026-05-26`; MCP now at `https://ai.nuclide.systems/mcp` (Bifrost) |
| [18002](http://192.168.1.40:18002) | ComfyUI | `comfyui` | — | LAN only (Intel Arc iGPU, FLUX.1-schnell GGUF) | | [18002](http://192.168.1.40:18002) | ComfyUI | `comfyui` | — | LAN only (Intel Arc iGPU, FLUX.1-schnell GGUF) |
| [18003](http://192.168.1.40:18003) | ComfyUI MCP | `comfyui-mcp` | — | FastMCP; reachable via gateway at `mcp.nuclide.systems/comfyui/mcp` | | [18003](http://192.168.1.40:18003) | ComfyUI MCP | `comfyui-mcp` | — | FastMCP; reachable via gateway at `mcp.nuclide.systems/comfyui/mcp` |
| [18005](http://192.168.1.40:18005) | Docling MCP | `docling-mcp` | — | SAIA Docling PDF→Markdown; reachable via gateway | | [18005](http://192.168.1.40:18005) | Docling MCP | `docling-mcp` | — | SAIA Docling PDF→Markdown; reachable via gateway |
@@ -248,9 +249,8 @@ Zoraxy routes to these external backends:
| Domain | Backend (NUC `192.168.1.40`) | Port | | Domain | Backend (NUC `192.168.1.40`) | Port |
|---|---|---| |---|---|---|
| [ai.nuclide.systems](https://ai.nuclide.systems) | litellm | 14000 | | [ai.nuclide.systems](https://ai.nuclide.systems) | bifrost | 14003 |
| [chat.nuclide.systems](https://chat.nuclide.systems) | lobehub | 14001 | | [chat.nuclide.systems](https://chat.nuclide.systems) | open-webui | 14002 |
| [mcp.nuclide.systems](https://mcp.nuclide.systems) | mcp-gateway | 8080 |
| [arcane.nuclide.systems](https://arcane.nuclide.systems) | arcane on CT 109 | **192.168.1.8**:10002 | | [arcane.nuclide.systems](https://arcane.nuclide.systems) | arcane on CT 109 | **192.168.1.8**:10002 |
| [gotify.nuclide.systems](https://gotify.nuclide.systems) | gotify | 10003 | | [gotify.nuclide.systems](https://gotify.nuclide.systems) | gotify | 10003 |
| [vault.nuclide.systems](https://vault.nuclide.systems) | vaultwarden | 11001 | | [vault.nuclide.systems](https://vault.nuclide.systems) | vaultwarden | 11001 |
@@ -264,7 +264,7 @@ Zoraxy routes to these external backends:
| [dozzle.nuclide.systems](https://dozzle.nuclide.systems) | dozzle | 10001 | | [dozzle.nuclide.systems](https://dozzle.nuclide.systems) | dozzle | 10001 |
| [s3.nuclide.systems](https://s3.nuclide.systems) | garage | 10004 | | [s3.nuclide.systems](https://s3.nuclide.systems) | garage | 10004 |
**Not publicly proxied** (LAN / localhost only): pgadmin, paperless, paperless-ai, comfyui, comfyui-mcp, rdtclient, prowlarr, shelfarr, qdrant. **Not publicly proxied** (LAN / localhost only): litellm (internal only — no Zoraxy route), pgadmin, paperless, paperless-ai, comfyui, comfyui-mcp, rdtclient, prowlarr, shelfarr, qdrant.
--- ---
@@ -278,8 +278,8 @@ Zoraxy routes to these external backends:
| Client ID | Name | Redirect URIs | | Client ID | Name | Redirect URIs |
|---|---|---| |---|---|---|
| `e73bb7b9` | litellm | (empty = accept all) — used by LiteLLM UI + MCP Gateway | | `e73bb7b9` | litellm | (empty = accept all) — used by LiteLLM UI (internal only); Bifrost auth uses `sk-bf-` VKs |
| `26f3c26b` | lobehub | `https://chat.nuclide.systems/api/auth/callback/generic-oidc` | | ~~`26f3c26b`~~ | ~~lobehub~~ | **DECOMMISSIONED 2026-05-26** — LobeChat removed; Open WebUI OIDC not yet wired |
| `81cf4ed0` | arcane | `https://arcane.nuclide.systems/auth/oidc/callback` | | `81cf4ed0` | arcane | `https://arcane.nuclide.systems/auth/oidc/callback` |
| `33135ad4` | n8n | `https://n8n.nuclide.systems/auth/oidc/callback` | | `33135ad4` | n8n | `https://n8n.nuclide.systems/auth/oidc/callback` |
| `9c91c18b` | immich | `https://immich.nuclide.systems/auth/login` + mobile | | `9c91c18b` | immich | `https://immich.nuclide.systems/auth/login` + mobile |
+10 -7
View File
@@ -147,23 +147,25 @@ All behind gluetun VPN.
|---|---|---|---| |---|---|---|---|
| **bind** | **`/opt/stacks/ai/postgres_data`** | **`/var/lib/postgresql/data`** | ⏳ Plan: `ai/litellm-db` | | **bind** | **`/opt/stacks/ai/postgres_data`** | **`/var/lib/postgresql/data`** | ⏳ Plan: `ai/litellm-db` |
### LobeHub — `lobehub` ### ~~LobeHub~~DECOMMISSIONED 2026-05-26
LobeChat compose renamed `.DECOMMISSIONED-lobehub-2026-05-26.yml`. Volumes below are orphaned — clean up after confirming no data needed.
| Type | Source | Container | UNAS | | Type | Source | Container | UNAS |
|---|---|---|---| |---|---|---|---|
| bind | `/opt/stacks/ai/lobehub/data` | `/var/lib/postgresql/data` | ⏳ Plan: `ai/lobehub-db` | | bind | `/opt/stacks/ai/lobehub/data` | `/var/lib/postgresql/data` | 🗑️ orphaned — decommissioned |
### LobeHub Redis — `lobe-redis` ### ~~LobeHub Redis~~DECOMMISSIONED 2026-05-26
| Type | Source | Container | UNAS | | Type | Source | Container | UNAS |
|---|---|---|---| |---|---|---|---|
| volume | `nuc-ai-core_redis_data` | `/data` | (ephemeral, stay) | | volume | `nuc-ai-core_redis_data` | `/data` | 🗑️ orphaned — decommissioned |
### LobeHub RustFS — `lobe-rustfs` ### ~~LobeHub RustFS~~DECOMMISSIONED 2026-05-26
| Type | Source | Container | UNAS | | Type | Source | Container | UNAS |
|---|---|---|---| |---|---|---|---|
| volume | `nuc-ai-core_rustfs-data` | `/data` | ⏳ Plan: `ai/rustfs` | | volume | `nuc-ai-core_rustfs-data` | `/data` | 🗑️ orphaned — decommissioned |
### SearXNG — `searxng` ### SearXNG — `searxng`
@@ -344,7 +346,8 @@ No DB-specific mounts needed (connects via env vars).
| ✅ Migrated (Phase 1) | 3 | memos, arcane, n8n | | ✅ Migrated (Phase 1) | 3 | memos, arcane, n8n |
| 🔷 Shared infrastructure (local) | 2 | shared-postgres (local volume), garage (local NVMe — moved off UNAS 2026-05-19) | | 🔷 Shared infrastructure (local) | 2 | shared-postgres (local volume), garage (local NVMe — moved off UNAS 2026-05-19) |
| 📋 Own CT, local only | 1 | pocketid (CT 110, no UNAS) | | 📋 Own CT, local only | 1 | pocketid (CT 110, no UNAS) |
| ⏳ Phase 2 planned (PG consolidation) | 5 | immich → shared-postgres, paperless → shared-postgres, daytona → shared-postgres, litellm → shared-postgres, lobehub → shared-postgres | | ⏳ Phase 2 planned (PG consolidation) | 4 | immich → shared-postgres, paperless → shared-postgres, daytona → shared-postgres, litellm → shared-postgres |
| 🗑️ Decommissioned 2026-05-26 | 3 | lobehub-db, lobe-redis, lobe-rustfs (LobeChat removed) |
| ⏳ Phase 3 planned | 1 | arr-stack*(8 mounts) | | ⏳ Phase 3 planned | 1 | arr-stack*(8 mounts) |
| 📋 Keep local | ~5 | homepage, dozzle, litellm-config, searxng-config, saia-image-proxy | | 📋 Keep local | ~5 | homepage, dozzle, litellm-config, searxng-config, saia-image-proxy |
| 🧠 Cache (stay) | ~5 | immich_model-cache, paperless-ngx redis, lobe-redis, searxng-redis, flaresolverr, daytona-runner | | 🧠 Cache (stay) | ~5 | immich_model-cache, paperless-ngx redis, lobe-redis, searxng-redis, flaresolverr, daytona-runner |
+3 -3
View File
@@ -8,9 +8,9 @@ Every service running in the homelab, with its access URL(s) and host. **Externa
| Service | External | Internal | Host | Doc | | Service | External | Internal | Host | Doc |
|---|---|---|---|---| |---|---|---|---|---|
| LobeChat | <https://chat.nuclide.systems> | <http://192.168.1.40:14001> | CT 104 | — | | Bifrost (LLM/MCP gateway) | <https://ai.nuclide.systems> | <http://192.168.1.40:14003> | CT 104 | — |
| LiteLLM (gateway) | <https://ai.nuclide.systems> | <http://192.168.1.40:14000> | CT 104 | [[mcp-gateway]] | | Open WebUI | <https://chat.nuclide.systems> | <http://192.168.1.40:14002> | CT 104 | |
| MCP Gateway | <https://mcp.nuclide.systems> | <http://192.168.1.40:8080> | CT 104 | [[mcp-gateway]], [[mcp-servers]] | | LiteLLM | — | <http://192.168.1.40:14000> (internal only) | CT 104 | — |
| ComfyUI | — | <http://192.168.1.40:18188> | CT 104 | [[comfyui]] | | ComfyUI | — | <http://192.168.1.40:18188> | CT 104 | [[comfyui]] |
| Nexa | — | — | CT 104 | [[nexa]] | | Nexa | — | — | CT 104 | [[nexa]] |
| n8n (automation) | — | <http://192.168.1.40:15678> | CT 104 | — | | n8n (automation) | — | <http://192.168.1.40:15678> | CT 104 | — |
+1 -1
View File
@@ -20,7 +20,7 @@ All application databases live on **CT 113** (`192.168.1.6:5432`) after Phase 2
| DB | Container | Reason | | DB | Container | Reason |
|----|-----------|--------| |----|-----------|--------|
| `lobechat` | `lobe-postgres` (paradedb) on CT 104 | Requires `pg_search` extension for `USING bm25` indexes | | `lobechat` | `lobe-postgres` (paradedb) on CT 104 | **LobeChat decommissioned 2026-05-26** — DB retained pending cleanup; no active service |
| `immich` | `immich_postgres` on CT 104 | Version-pinned by Immich AIO | | `immich` | `immich_postgres` on CT 104 | Version-pinned by Immich AIO |
| `nextcloud` | Nextcloud AIO on CT 105 | AIO manages its own postgres | | `nextcloud` | Nextcloud AIO on CT 105 | AIO manages its own postgres |
+44 -67
View File
@@ -136,9 +136,10 @@ across ~23 compose stacks. Principle: **self-host everything**, OIDC SSO,
(see n8n note under Operational rules). (see n8n note under Operational rules).
- **Auth** — **PocketID** (`id.nuclide.systems`, OIDC, SQLite) is the - **Auth** — **PocketID** (`id.nuclide.systems`, OIDC, SQLite) is the
**universal SSO/IdP for the entire ecosystem** — effectively every service **universal SSO/IdP for the entire ecosystem** — effectively every service
authenticates via PocketID OIDC (LiteLLM, LobeChat, MCP gateway, Nextcloud, authenticates via PocketID OIDC (LiteLLM, Nextcloud, Coder, Gitea,
Coder, Gitea, Vaultwarden, etc.). Single sign-on everywhere; one identity Vaultwarden, etc.). Single sign-on everywhere; one identity source to
source to secure/audit. Vaultwarden remains the lone gap as of 2026-05-20. secure/audit. Vaultwarden remains the lone gap as of 2026-05-20.
Open WebUI OIDC not yet wired (as of 2026-05-26).
## Docker networks ## Docker networks
`ai-internal` (AI/MCP plane) · `shared_backend` (cross-stack DB/S3) · `ai-internal` (AI/MCP plane) · `shared_backend` (cross-stack DB/S3) ·
@@ -147,59 +148,37 @@ plus per-stack: `arr-stack_default`,
The MCP gateway bridges `ai-internal` + `shared_backend`. The MCP gateway bridges `ai-internal` + `shared_backend`.
## AI / Agent platform (the core, `/opt/stacks/ai`) ## AI / Agent platform (the core, `/opt/stacks/ai`)
- **LiteLLM** (`ai.nuclide.systems`, :14000) — model gateway. ~28 curated - **Bifrost** (`ai.nuclide.systems`, :14003) — unified LLM gateway + MCP host.
models (provider allowlist), SAIA-terminal **failovers** + `num_retries`, Stack `ai/bifrost/`. Auth via `sk-bf-` VKs. LLM inference at `/v1`; MCP at
Redis completion cache, Gemini €10/30d `provider_budget_config`. Config: `/mcp` (29 clients, ~760 tools as of 2026-05-26). Proxies LLM requests to
`ai/litellm-config/config.yaml` (+ DB overlay `LiteLLM_Config`). LiteLLM internally.
- **LiteLLM** (:14000, **internal only** — no Zoraxy route) — model gateway,
backend for Bifrost. ~28 curated models (provider allowlist), SAIA-terminal
**failovers** + `num_retries`, Redis completion cache, Gemini €10/30d
`provider_budget_config`. Config: `ai/litellm-config/config.yaml` (+ DB
overlay `LiteLLM_Config`). Reachable as `http://litellm:4000` inside Docker.
- **Open WebUI** (`chat.nuclide.systems`, :14002) — chat UI. Stack
`ai/open-webui.yml`. Uses Qdrant + TEI for RAG. OIDC via Pocket-ID (not
yet wired as of 2026-05-26).
- **syncstack** (`ai/syncstack.py`, cron `/etc/cron.d/syncstack` 15 min) — - **syncstack** (`ai/syncstack.py`, cron `/etc/cron.d/syncstack` 15 min) —
**model syncer/optimizer ONLY** (curation/allowlist → DB, `OPENAI_MODEL_LIST` **model syncer/optimizer ONLY** (curation/allowlist → DB, model-health → ntfy).
→ `.env`, recreate lobe, model-health → ntfy). One-shot container. One-shot container.
- **mcp-gateway / Agent Operator** (`mcp.nuclide.systems`, :8080) — **all - ~~**mcp-gateway**~~ — **DECOMMISSIONED 2026-05-26.** Was FastAPI/DinD on
things MCP**. DinD-spawns MCP servers on `ai-internal`, OAuth-gated streaming `:8080` at `mcp.nuclide.systems`. Compose renamed `.DECOMMISSIONED-2026-05-26`.
reverse proxy `/<server>/mcp` + `/group/<g>/mcp`, multi-group, health-watcher, MCP is now served by Bifrost at `https://ai.nuclide.systems/mcp`.
per-server tools/list cache. **Deep health-check (2026-05-19):** beyond - **MCP servers** (Bifrost-managed, formerly gateway-managed): time, home-assistant,
shallow liveness, the watcher drives a real MCP session (`initialize` → kroki, coder, fetch, sequential-thinking, gotify, memos, docling, markitdown,
`tools/list` → optional `health_probe_tool` no-side-effect call) against crawl4ai, context7, wikipedia, papersearch, comfyui, bluesky, obsidian,
**every** server incl. spawned ones, recording `ok|degraded|down` in immich, n8n, nextcloud, paperless, unifi, upload-artifact, gitea, proxmox,
`/api/servers`. Usage-aware: a server used within 5 min isn't probed shepard, git, gitlab, youtube-transcript, searxng (30 servers). 29 clients,
(traffic = health); idle servers probed every 15 min; probe self-excludes ~760 tools. See [`services/mcp-servers.md`](mcp-servers.md).
via `X-Health-Probe`. Deep failures are status-only (no restart loops);
shallow-liveness auto-restart stays static-only. First run caught the
invisible class: `memos` degraded (search_memo → DNS `Errno -2`, the
ai-internal isolation bug), plus `context7`/`crawl4ai`/`markitdown` down
and `nextcloud` probe false-positive (probe lacks per-user NC creds —
candidate for `health_check:false`). **Semantic tool retrieval**: groups with >25
aggregated tools expose just `find_tools`/`call_tool` meta-tools (LiteLLM
embedding index, cosine top-k, two-phase schema promotion) instead of
flooding clients with hundreds of schemas. Group members are proxied via the
gateway's own path (`_mcp_gw`) so `exact_upstream` servers (home-assistant,
n8n) aggregate correctly. **MCP→LobeChat registration** (migrated here
from syncstack), and the **Agent Operator**: cron+event agents
(`/api/agents/{name}/run` webhook), LLM↔MCP executor, **Agent Creator**
(AI-drafts agent specs; overridable meta-prompt), prompt export. Config:
`mcp-gateway/config.json` (servers), `agents.json` + `prompts/` (agents).
- **MCP servers** (gateway-managed): time, home-assistant (exact_upstream to
`.60` ha-mcp), kroki (self-hosted: kroki+mermaid+excalidraw companions),
**coder** (replaced daytona 2026-05-20), fetch, sequential-thinking, ntfy, memos,
docling, markitdown, crawl4ai, context7, wikipedia, papersearch, comfyui,
bluesky (brianellin, rate-limit pending). Groups incl. `shepard-mcp`.
Gaps to close (community MCPs exist): gitea, paperless, karakeep, vaultwarden,
proxmox-ve, audiobookshelf. See [`services/mcp-gateway.md`](mcp-gateway.md).
- **Coder** (`dev.nuclide.systems`, CT 111) — replaced Daytona as the sandbox / - **Coder** (`dev.nuclide.systems`, CT 111) — replaced Daytona as the sandbox /
dev-environment runtime. Templates: `python-uv` (persistent, GPU passthrough, dev-environment runtime. Templates: `python-uv` (persistent, GPU passthrough,
baked LiteLLM env + Claude Code), `mcp-sandbox` (ephemeral, sci stack baked LiteLLM env + Claude Code), `mcp-sandbox` (ephemeral, sci stack
pre-baked). See [`services/dev-environment.md`](dev-environment.md). pre-baked). See [`services/dev-environment.md`](dev-environment.md).
- **LobeChat** (`chat.nuclide.systems`, :14001) — chat UI; MCP plugins + - ~~**LobeChat**~~ — **DECOMMISSIONED 2026-05-26.** Was at `chat.nuclide.systems`
agents in `lobechat` DB (lobe-postgres). Agents scriptable via (:14001). Compose renamed `.DECOMMISSIONED-lobehub-2026-05-26.yml`. Replaced
`scripts/lobe_agent.py`. Native QStash scheduler NOT functional here → by Open WebUI.
scheduling lives in the gateway Agent Operator. **Auth = Better Auth**
(not NextAuth) SSO via PocketID (`generic-oidc`, client `26f3c26b`, PKCE
S256). The `state_not_found` callback bug was fixed by setting
`AUTH_TRUSTED_ORIGINS=https://chat.nuclide.systems`; verified 2026-05-19
(sign-in yields a correct PocketID authorize URL; callback now validates
with `oAuth_code_missing`, not `state_not_found`). Definitive proof =
one real browser login. NB: `/oidc/auth` is LobeChat-*as*-OIDC-provider
(desktop/mobile), distinct from this SSO-client path.
- **ComfyUI** (img gen, Intel Arc iGPU), **Kroki**, **searxng** (self-hosted - **ComfyUI** (img gen, Intel Arc iGPU), **Kroki**, **searxng** (self-hosted
meta-search). meta-search).
@@ -227,8 +206,7 @@ The MCP gateway bridges `ai-internal` + `shared_backend`.
**pgloader data-only of ALL tables** into the app-built schema (exclude **pgloader data-only of ALL tables** into the app-built schema (exclude
only the app's own migration-tracking table), app role temp-SUPERUSER for only the app's own migration-tracking table), app role temp-SUPERUSER for
the load (FK/trigger disable) then reverted. the load (FK/trigger disable) then reverted.
- **lobe-postgres** (pg17/ParadeDB) — LobeChat. **lobe-redis** — LiteLLM cache - **lobe-postgres** (pg17/ParadeDB) — LobeChat (decommissioned 2026-05-26; DB retained pending cleanup). **lobe-redis** — LiteLLM cache (LobeChat decommissioned). **Garage S3** (`garage:3900`, ext `s3.nuclide.systems` /
+ LobeChat. **Garage S3** (`garage:3900`, ext `s3.nuclide.systems` /
`:10004`) — lobe-files, memos, **WAL-G PG backups**. **Qdrant** (vector, `:10004`) — lobe-files, memos, **WAL-G PG backups**. **Qdrant** (vector,
on UNAS) — unused yet (future RAG/mem0). pgAdmin (internal). on UNAS) — unused yet (future RAG/mem0). pgAdmin (internal).
- **Backups**: WAL-G v3 → Garage for all 3 PG instances (shared-postgres, - **Backups**: WAL-G v3 → Garage for all 3 PG instances (shared-postgres,
@@ -299,7 +277,7 @@ Nextcloud (LXC .41), **Paperless-ngx** (+paperless-ai, tika/gotenberg),
**Daytona OIDC adapter** (Keycloak→PocketID PKCE proxy for the VS Code ext). **Daytona OIDC adapter** (Keycloak→PocketID PKCE proxy for the VS Code ext).
## Operational rules / conventions ## Operational rules / conventions
- **Separation**: `syncstack` = models; `mcp-gateway` = all MCP/agents. - **Separation**: `syncstack` = model curation; `bifrost` = MCP + LLM gateway (mcp-gateway decommissioned 2026-05-26).
- **Self-host first**: external/cloud only when no self-hosted form exists. - **Self-host first**: external/cloud only when no self-hosted form exists.
- **Pinned NTP source standard** — all network gear/infra should point at - **Pinned NTP source standard** — all network gear/infra should point at
the *same fixed-IP, DNS-free* NTP sources (devices like the D-Link can't the *same fixed-IP, DNS-free* NTP sources (devices like the D-Link can't
@@ -328,8 +306,7 @@ Nextcloud (LXC .41), **Paperless-ngx** (+paperless-ai, tika/gotenberg),
timed out`) and was **migrated to `shared-postgres`** (DB on local ZFS; timed out`) and was **migrated to `shared-postgres`** (DB on local ZFS;
data dir moved to local `/opt/stacks/n8n/data`; old NFS `database.sqlite` data dir moved to local `/opt/stacks/n8n/data`; old NFS `database.sqlite`
kept as rollback). Audit other SQLite stacks for NFS-backed data dirs. kept as rollback). Audit other SQLite stacks for NFS-backed data dirs.
- Naming debt: "mcp-gateway"/"syncstack" have outgrown their names — rename - Naming debt: "syncstack" has outgrown its name — rename once the agent-platform identity firms up. mcp-gateway renamed/decommissioned 2026-05-26.
once the agent-platform identity firms up.
## Open / roadmap ## Open / roadmap
mem0 vs Qdrant for agent memory (deferred); Agent teams/orchestration + mem0 vs Qdrant for agent memory (deferred); Agent teams/orchestration +
@@ -338,8 +315,8 @@ expose Agent Operator as MCP; S3/Immich/n8n/Paperless/Proxmox MCP servers
197 tools, Network App API key, `http` transport; local API fully working). 197 tools, Network App API key, `http` transport; local API fully working).
**Tier-1 SQLite-off-NFS: COMPLETE** — all services off NFS for DB/metadata. **Tier-1 SQLite-off-NFS: COMPLETE** — all services off NFS for DB/metadata.
Note: Traccar watch protocol port 15001 is already forwarded at the UDM level — Note: Traccar watch protocol port 15001 is already forwarded at the UDM level —
no Zoraxy stream proxy needed. Plus: disable LobeChat external features (keep no Zoraxy stream proxy needed. Plus: env → secret vault. Wire Open WebUI OIDC
`plugins`!); env → secret vault. via Pocket-ID once Bifrost auth is settled.
**Management-plane TLS (planned):** issue/trust proper certs for admin-UI **Management-plane TLS (planned):** issue/trust proper certs for admin-UI
auth on the **Proxmox** host and the **D-Link DGS-1210** (currently HTTP-only auth on the **Proxmox** host and the **D-Link DGS-1210** (currently HTTP-only
@@ -426,31 +403,31 @@ flowchart LR
zx --> gitea[Gitea · CT 111] zx --> gitea[Gitea · CT 111]
zx --> nc2[Nextcloud · CT 105] zx --> nc2[Nextcloud · CT 105]
zx --> immich[Immich · CT 104] zx --> immich[Immich · CT 104]
zx --> lobe[LobeChat · CT 104] zx --> owui[Open WebUI · CT 104]
zx --> n8n[n8n · CT 104] zx --> n8n[n8n · CT 104]
zx --> mcp[MCP gateway · CT 104] zx --> bifrost[Bifrost · CT 104]
zx --> vw[Vaultwarden · CT 104] zx --> vw[Vaultwarden · CT 104]
coder --> pid[(Pocket-ID<br/>CT 110)] coder --> pid[(Pocket-ID<br/>CT 110)]
gitea --> pid gitea --> pid
nc2 --> pid nc2 --> pid
immich --> pid immich --> pid
lobe --> pid owui -.->|OIDC not yet wired| pid
n8n --> pid n8n --> pid
mcp --> pid bifrost -.->|VK auth, not OIDC| pid
vw -.->|via Tinyauth<br/>when CT 109 lands| pid vw -.->|via Tinyauth<br/>when CT 109 lands| pid
classDef pending stroke-dasharray:4 4,color:#888 classDef pending stroke-dasharray:4 4,color:#888
class vw pending class vw pending
``` ```
### MCP plane — gateway control, child workers ### MCP plane — Bifrost host, child workers
The MCP gateway on CT 104 is the OIDC-gated front; ~23 child MCP servers run on the same docker network (`ai-internal`). When CT 109 "ops" is built, the gateway moves to CT 109 and reaches CT 104's docker daemon via a socket-proxy; the children stay put. Bifrost on CT 104 is the MCP host; ~30 child MCP servers run on the same docker network (`ai-internal`). The old mcp-gateway FastAPI/DinD container was decommissioned 2026-05-26.
```mermaid ```mermaid
flowchart LR flowchart LR
client[["Claude Code / Cursor / LobeChat"]] client[["Claude Code / Cursor / Open WebUI"]]
gw["MCP gateway<br/>(CT 104 → CT 109 ops when 109 lands)<br/>mcp.nuclide.systems"] gw["Bifrost<br/>(CT 104)<br/>ai.nuclide.systems/mcp"]
client -- Bearer / OIDC --> gw client -- Bearer VK --> gw
subgraph "CT 104 · ai-internal docker net" subgraph "CT 104 · ai-internal docker net"
direction TB direction TB
coderm[coder-mcp] coderm[coder-mcp]
+45 -65
View File
@@ -1,9 +1,9 @@
# MCP Servers — nuclide.systems # MCP Servers — nuclide.systems
Complete reference for all 30 MCP servers managed by the gateway at `https://mcp.nuclide.systems`. Complete reference for all 30 MCP servers. MCP is now served by **Bifrost** at `https://ai.nuclide.systems/mcp`.
**Last verified: 2026-05-23.** **Last verified: 2026-05-23. Gateway migrated to Bifrost: 2026-05-26.**
> Architecture doc: [`mcp-gateway.md`](mcp-gateway.md) · Config file: `/opt/stacks/ai/mcp-gateway/config.json` on CT 104 · Secrets: `/opt/stacks/ai/.env` > The old mcp-gateway (FastAPI/DinD, `mcp.nuclide.systems`) was **decommissioned 2026-05-26** — compose renamed `.DECOMMISSIONED-2026-05-26`. Config file was at `/opt/stacks/ai/mcp-gateway/config.json` on CT 104 · Secrets: `/opt/stacks/ai/.env`
--- ---
@@ -11,40 +11,38 @@ Complete reference for all 30 MCP servers managed by the gateway at `https://mcp
| # | Server | Group | Kind | Gateway URL | Status | | # | Server | Group | Kind | Gateway URL | Status |
|---|---|---|---|---|---| |---|---|---|---|---|---|
| 1 | `context7` | dev | catalog | `https://mcp.nuclide.systems/context7/mcp` | ✓ | | 1 | `context7` | dev | catalog | `https://ai.nuclide.systems/mcp/context7/mcp` | ✓ |
| 2 | `fetch` | dev | spawn | `https://mcp.nuclide.systems/fetch/mcp` | ✓ | | 2 | `fetch` | dev | spawn | `https://ai.nuclide.systems/mcp/fetch/mcp` | ✓ |
| 3 | `git` | dev | catalog | `https://mcp.nuclide.systems/git/mcp` | ✓ | | 3 | `git` | dev | catalog | `https://ai.nuclide.systems/mcp/git/mcp` | ✓ |
| 4 | `gitlab` | dev | catalog | `https://mcp.nuclide.systems/gitlab/mcp` | ✓ | | 4 | `gitlab` | dev | catalog | `https://ai.nuclide.systems/mcp/gitlab/mcp` | ✓ |
| 5 | `kroki` | dev | static | `https://mcp.nuclide.systems/kroki/mcp` | ✓ | | 5 | `kroki` | dev | static | `https://ai.nuclide.systems/mcp/kroki/mcp` | ✓ |
| 6 | `markitdown` | dev | catalog | `https://mcp.nuclide.systems/markitdown/mcp` | ✓ | | 6 | `markitdown` | dev | catalog | `https://ai.nuclide.systems/mcp/markitdown/mcp` | ✓ |
| 7 | `sequential-thinking` | dev | catalog | `https://mcp.nuclide.systems/sequential-thinking/mcp` | ✓ | | 7 | `sequential-thinking` | dev | catalog | `https://ai.nuclide.systems/mcp/sequential-thinking/mcp` | ✓ |
| 8 | `time` | dev | spawn | `https://mcp.nuclide.systems/time/mcp` | ✓ | | 8 | `time` | dev | spawn | `https://ai.nuclide.systems/mcp/time/mcp` | ✓ |
| 9 | `docling` | dev | static | `https://mcp.nuclide.systems/docling/mcp` | ✓ | | 9 | `docling` | dev | static | `https://ai.nuclide.systems/mcp/docling/mcp` | ✓ |
| 10 | `coder` | dev | static | `https://mcp.nuclide.systems/coder/mcp` | ✓ | | 10 | `coder` | dev | static | `https://ai.nuclide.systems/mcp/coder/mcp` | ✓ |
| 11 | `gitea` | dev | static | `https://mcp.nuclide.systems/gitea/mcp` | ✓ | | 11 | `gitea` | dev | static | `https://ai.nuclide.systems/mcp/gitea/mcp` | ✓ |
| 12 | `proxmox` | dev | spawn | `https://mcp.nuclide.systems/proxmox/mcp` | ✓ | | 12 | `proxmox` | dev | spawn | `https://ai.nuclide.systems/mcp/proxmox/mcp` | ✓ |
| 13 | `shepard` | dev | static | `https://mcp.nuclide.systems/shepard/mcp` | ✓ | | 13 | `shepard` | dev | static | `https://ai.nuclide.systems/mcp/shepard/mcp` | ✓ |
| 14 | `crawl4ai` | research | spawn | `https://mcp.nuclide.systems/crawl4ai/mcp` | ✓ | | 14 | `crawl4ai` | research | spawn | `https://ai.nuclide.systems/mcp/crawl4ai/mcp` | ✓ |
| 15 | `paper-search` | research | catalog | `https://mcp.nuclide.systems/paper-search/mcp` | ✓ | | 15 | `paper-search` | research | catalog | `https://ai.nuclide.systems/mcp/paper-search/mcp` | ✓ |
| 16 | `searxng` | research | spawn | `https://mcp.nuclide.systems/searxng/mcp` | ✓ | | 16 | `searxng` | research | spawn | `https://ai.nuclide.systems/mcp/searxng/mcp` | ✓ |
| 17 | `wikipedia-mcp` | research | catalog | `https://mcp.nuclide.systems/wikipedia-mcp/mcp` | ✓ | | 17 | `wikipedia-mcp` | research | catalog | `https://ai.nuclide.systems/mcp/wikipedia-mcp/mcp` | ✓ |
| 18 | `youtube-transcript` | research | catalog | `https://mcp.nuclide.systems/youtube-transcript/mcp` | ✓ | | 18 | `youtube-transcript` | research | catalog | `https://ai.nuclide.systems/mcp/youtube-transcript/mcp` | ✓ |
| 19 | `bluesky` | personal | static | `https://mcp.nuclide.systems/bluesky/mcp` | ✓ | | 19 | `bluesky` | personal | static | `https://ai.nuclide.systems/mcp/bluesky/mcp` | ✓ |
| 20 | `obsidian` | personal | spawn | `https://mcp.nuclide.systems/obsidian/mcp` | ✓ | | 20 | `obsidian` | personal | spawn | `https://ai.nuclide.systems/mcp/obsidian/mcp` | ✓ |
| 21 | `gotify` | personal | spawn | `https://mcp.nuclide.systems/gotify/mcp` | ✓ | | 21 | `gotify` | personal | spawn | `https://ai.nuclide.systems/mcp/gotify/mcp` | ✓ |
| 22 | `home-assistant` | personal | static | `https://mcp.nuclide.systems/home-assistant/mcp` | ✓ | | 22 | `home-assistant` | personal | static | `https://ai.nuclide.systems/mcp/home-assistant/mcp` | ✓ |
| 23 | `immich` | personal | spawn | `https://mcp.nuclide.systems/immich/mcp` | ✓ | | 23 | `immich` | personal | spawn | `https://ai.nuclide.systems/mcp/immich/mcp` | ✓ |
| 24 | `memos` | personal | spawn | `https://mcp.nuclide.systems/memos/mcp` | ✓ | | 24 | `memos` | personal | spawn | `https://ai.nuclide.systems/mcp/memos/mcp` | ✓ |
| 25 | `n8n` | personal | static | `https://mcp.nuclide.systems/n8n/mcp` | ✓ | | 25 | `n8n` | personal | static | `https://ai.nuclide.systems/mcp/n8n/mcp` | ✓ |
| 26 | `nextcloud` | personal | spawn | `https://mcp.nuclide.systems/nextcloud/mcp` | ✓ | | 26 | `nextcloud` | personal | spawn | `https://ai.nuclide.systems/mcp/nextcloud/mcp` | ✓ |
| 27 | `paperless` | personal | static | `https://mcp.nuclide.systems/paperless/mcp` | ✓ | | 27 | `paperless` | personal | static | `https://ai.nuclide.systems/mcp/paperless/mcp` | ✓ |
| 28 | `unifi` | personal | spawn | `https://mcp.nuclide.systems/unifi/mcp` | ✓ | | 28 | `unifi` | personal | spawn | `https://ai.nuclide.systems/mcp/unifi/mcp` | ✓ |
| 29 | `comfyui` | image | static | `https://mcp.nuclide.systems/comfyui/mcp` | ✓ | | 29 | `comfyui` | image | static | `https://ai.nuclide.systems/mcp/comfyui/mcp` | ✓ |
| 30 | `upload-artifact` | storage | static | `https://mcp.nuclide.systems/upload-artifact/mcp` | ✓ | | 30 | `upload-artifact` | storage | static | `https://ai.nuclide.systems/mcp/upload-artifact/mcp` | ✓ |
**Auth**: all gateway URLs require `Authorization: Bearer <gateway-token>`. Get a config bundle at `https://mcp.nuclide.systems/mcp-config?format=claude`. **Auth**: all Bifrost MCP URLs require `Authorization: Bearer sk-bf-<key>`. MCP endpoint: `https://ai.nuclide.systems/mcp`.
**Gateway API key** (for `/api/*` management calls): `JxxCqKw32XoN4LOHunDikS6u1RpS7R5ythzaqADPuIA`
--- ---
@@ -523,13 +521,15 @@ Complete reference for all 30 MCP servers managed by the gateway at `https://mcp
### Auto (recommended) ### Auto (recommended)
> **Note**: URLs below use the new Bifrost endpoint. Old `mcp.nuclide.systems` routes are decommissioned.
``` ```
GET https://mcp.nuclide.systems/mcp-config?format=claude # Claude Code / Claude Desktop GET https://ai.nuclide.systems/mcp-config?format=claude # Claude Code / Claude Desktop
GET https://mcp.nuclide.systems/mcp-config?format=cursor # Cursor GET https://ai.nuclide.systems/mcp-config?format=cursor # Cursor
GET https://mcp.nuclide.systems/mcp-config?format=raw # raw token + URLs GET https://ai.nuclide.systems/mcp-config?format=raw # raw token + URLs
``` ```
Requires Pocket-ID session. Downloads a pre-built config with fresh long-lived token. Merge `mcpServers` block into `~/.claude/settings.json`. Auth: `Authorization: Bearer sk-bf-<key>`. Merge `mcpServers` block into `~/.claude/settings.json`.
### Manual (Claude Code) ### Manual (Claude Code)
@@ -538,9 +538,9 @@ Requires Pocket-ID session. Downloads a pre-built config with fresh long-lived t
"mcpServers": { "mcpServers": {
"<name>": { "<name>": {
"type": "http", "type": "http",
"url": "https://mcp.nuclide.systems/<name>/mcp", "url": "https://ai.nuclide.systems/mcp/<name>/mcp",
"headers": { "headers": {
"Authorization": "Bearer JxxCqKw32XoN4LOHunDikS6u1RpS7R5ythzaqADPuIA" "Authorization": "Bearer sk-bf-<key>"
} }
} }
} }
@@ -551,32 +551,12 @@ Requires Pocket-ID session. Downloads a pre-built config with fresh long-lived t
## Gateway management API ## Gateway management API
All calls require `Authorization: Bearer JxxCqKw32XoN4LOHunDikS6u1RpS7R5ythzaqADPuIA`. Bifrost management API (auth: `sk-bf-<key>`).
```bash ```bash
BASE=https://mcp.nuclide.systems BASE=https://ai.nuclide.systems
TOKEN=JxxCqKw32XoN4LOHunDikS6u1RpS7R5ythzaqADPuIA
H="Authorization: Bearer $TOKEN"
# List all servers + status # List all servers + status
curl -H "$H" $BASE/api/servers curl -H "Authorization: Bearer sk-bf-..." $BASE/api/servers
# Start / stop a server
curl -X POST -H "$H" $BASE/api/servers/memos/start
curl -X POST -H "$H" $BASE/api/servers/memos/stop
# Create new server (persists to config.json)
curl -X POST -H "$H" -H "Content-Type: application/json" \
-d '{"name":"myserver","static":true,"upstream":"http://host:port","group":"custom"}' \
$BASE/api/servers
# Delete server (stops container + removes from config.json)
curl -X DELETE -H "$H" $BASE/api/servers/myserver
# Patch server config
curl -X PATCH -H "$H" -H "Content-Type: application/json" \
-d '{"enabled":false}' \
$BASE/api/servers/myserver
# Health check # Health check
curl $BASE/health curl $BASE/health
+4 -3
View File
@@ -4,7 +4,7 @@
## Current route table ## Current route table
Audited 2026-05-23. All 22 public routes have: Audited 2026-05-23; updated 2026-05-26 (mcp.nuclide.systems removed, ai/chat backends swapped). 21 active public routes have:
- `EnableAutoHTTPS: true` — Zoraxy requests LE certs for `*.nuclide.systems` - `EnableAutoHTTPS: true` — Zoraxy requests LE certs for `*.nuclide.systems`
- `EnableWebsocketCustomHeaders: true` — preserves WS upgrade headers through the proxy - `EnableWebsocketCustomHeaders: true` — preserves WS upgrade headers through the proxy
- `DisableHopByHopHeaderRemoval: true` — keeps hop-by-hop headers intact for upstream - `DisableHopByHopHeaderRemoval: true` — keeps hop-by-hop headers intact for upstream
@@ -24,7 +24,7 @@ Audited 2026-05-23. All 22 public routes have:
| hoarder.nuclide.systems | 192.168.1.40:17001 | — | Karakeep bookmarks | | hoarder.nuclide.systems | 192.168.1.40:17001 | — | Karakeep bookmarks |
| id.nuclide.systems | 192.168.1.5:11000 | — | Pocket-ID OIDC (CT 110) | | id.nuclide.systems | 192.168.1.5:11000 | — | Pocket-ID OIDC (CT 110) |
| immich.nuclide.systems | 192.168.1.40:12000 | ✓ | Immich photos | | immich.nuclide.systems | 192.168.1.40:12000 | ✓ | Immich photos |
| mcp.nuclide.systems | 192.168.1.40:8080 | | MCP gateway | | ~~mcp.nuclide.systems~~ | ~~192.168.1.40:8080~~ | | **DECOMMISSIONED 2026-05-26** — mcp-gateway removed; MCP now at `https://ai.nuclide.systems/mcp` (Bifrost) |
| memos.nuclide.systems | 192.168.1.40:17000 | — | Memos notes | | memos.nuclide.systems | 192.168.1.40:17000 | — | Memos notes |
| n8n.nuclide.systems | 192.168.1.40:16000 | ✓ | n8n workflows | | n8n.nuclide.systems | 192.168.1.40:16000 | ✓ | n8n workflows |
| nc.nuclide.systems | 192.168.1.41:11000 | ✓ | Nextcloud AIO (CT 105) | | nc.nuclide.systems | 192.168.1.41:11000 | ✓ | Nextcloud AIO (CT 105) |
@@ -95,9 +95,10 @@ ssh root@192.168.1.4 'cp /tmp/zoraxy-backup-2026-05-21/<domain>.config /opt/zora
`.DECOMMISSIONED-*` files in `/opt/zoraxy/conf/proxy/` are ignored by Zoraxy. Current: `.DECOMMISSIONED-*` files in `/opt/zoraxy/conf/proxy/` are ignored by Zoraxy. Current:
- `daytona.nuclide.systems.config.DECOMMISSIONED-2026-05-20` - `daytona.nuclide.systems.config.DECOMMISSIONED-2026-05-20`
- `id.daytona.nuclide.systems.config.DECOMMISSIONED-2026-05-20` - `id.daytona.nuclide.systems.config.DECOMMISSIONED-2026-05-20`
- `mcp.nuclide.systems.config` — removed 2026-05-26 (mcp-gateway decommissioned; MCP now via Bifrost at `ai.nuclide.systems/mcp`)
## Auth posture ## Auth posture
No routes have `ForwardAuthURL` set (no Tinyauth/auth middleware). Pocket-ID (`id.nuclide.systems`) is the OIDC IdP; apps that require auth implement it themselves (LobeHub, Coder, Gitea, Nextcloud). Public-facing routes like `ha.nuclide.systems` and `ocpp.nuclide.systems` have no proxy-level auth — upstream apps handle it. No routes have `ForwardAuthURL` set (no Tinyauth/auth middleware). Pocket-ID (`id.nuclide.systems`) is the OIDC IdP; apps that require auth implement it themselves (Open WebUI, Coder, Gitea, Nextcloud). Public-facing routes like `ha.nuclide.systems` and `ocpp.nuclide.systems` have no proxy-level auth — upstream apps handle it.
**Pending**: Tinyauth or similar on unauthenticated-but-sensitive routes (arcane, gotify). Planned for CT 109 deployment. **Pending**: Tinyauth or similar on unauthenticated-but-sensitive routes (arcane, gotify). Planned for CT 109 deployment.