Christophs Kontext explodiert am Sessionende. Handoff bündelt: - CF-Token-Audit-Befund: CF_DNS_API_TOKEN ungültig (Code 1000 'Invalid API Token'), Christophs Verdacht 'falscher Token extrahiert' bestätigt. - Globale MCP-Migration FQDN → IP für gitea-mcp + n8n-mcp; cloudflare bleibt extern (User-Direktive explizit). WARP-Pfad statt Bearer-Header wenn der Connector intern ohne Token lebt. - terpene W5: n8n-mcp in blaueblueten-n8n/.mcp.json (User-Zustimmung). - Domain-Korrektur: 420.teilzeitladen.xyz ist die echte terpene-Domain (NICHT terpene.teilzeitladen.xyz) — User-Direktive, gilt für alle. - W1/W6 bleiben User-blocked, W7 wartet auf TP31-Schritt 5/6. Dringend beim Nachfolger: CF-Token-Validität zuerst klären, dann erst MCP-Migration. STATUS.md im terpene-Repo ist auf die falsche Domain korrigieren.
275 lines
15 KiB
Markdown
275 lines
15 KiB
Markdown
# Handoff 2026-08-28 (Abends) — terpene/blaueblueten-n8n-Schnittstelle + globale MCP-Migration
|
||
|
||
> **Zweck:** Christophs Kontext explodiert in der heutigen Session. Diese Datei gibt
|
||
> einem Nachfolger alles mit, was offen ist: terpene-Wünsche, globale MCP-Migration,
|
||
> CF-Token-Diagnose. **Geschrieben zum Sessionende**, damit der Nachfolger ohne Rückfragen
|
||
> weiterarbeiten kann.
|
||
>
|
||
> **Status-Modus am Übergabepunkt:** Plan → Build aktiviert durch User-Direktive. **`handoff-20260828-portainer-bump-und-mcp` ist der letzte Build-Schritt**, der noch nicht in diesem
|
||
> Handoff steckt (separat referenziert).
|
||
>
|
||
> **Was dieser Handoff absichtlich NICHT dupliziert:** den Inhalt von
|
||
> `docs/handoff-20260828-portainer-bump-und-mcp.md` (Portainer-Bump + portainer-mcp).
|
||
> Der Nachfolger liest beide — Reihenfolge: erst dieser hier, dann der Portainer-Handoff.
|
||
|
||
---
|
||
|
||
## 1. Sofort (nächste Session, kein Warten)
|
||
|
||
### 1.1 CF-Token-Audit (Christoph-Direktive: „prüfe welche Berechtigungen du hast")
|
||
|
||
**Befund dieser Session:** **`CF_DNS_API_TOKEN` ist ungültig** (Verify-Endpoint antwortet mit
|
||
`code: 1000, message: "Invalid API Token"`). Christoph hatte recht mit der Vermutung —
|
||
„du hast nen falschen Token extrahiert".
|
||
|
||
**Was der Nachfolger macht:**
|
||
1. Im CF-Dashboard (<https://dash.cloudflare.com/profile/api-tokens>) prüfen,
|
||
ob beide Tokens (`CF_API_TOKEN`, `CF_DNS_API_TOKEN`) noch **existieren**
|
||
(Dash akzeptiert gelöschte Tokens stillschweigend, dann wirkt `verify` identisch
|
||
zu nie-angelegt-gewesen).
|
||
2. Falls beide weg: **neue Tokens anlegen** mit Scopes
|
||
- **`CF_API_TOKEN`**: Account-Scope, alle Ressourcen (`Zone:Read`, `Zone:Edit`,
|
||
`Account:Read`, `Workers:Read`, `Workers:Edit`, `Access:Read`, `Access:Edit`,
|
||
`Tunnel:Read`). Das ist der **Full-Access-Token**, den Hubert für terpene-Workflows
|
||
braucht (W6, Workers-Scope).
|
||
- **`CF_DNS_API_TOKEN`**: `Zone:DNS:Edit`, **Scope auf `emsenhuber.net` und
|
||
`teilzeitladen.xyz` beschränken** (nicht account-weit — Lehrgeld aus 2026-08-24).
|
||
3. In `~/.secrets/credentials.env` schreiben, **nicht** ins Repo.
|
||
4. Verify-Test im Nachgang (gleicher curl wie oben):
|
||
```bash
|
||
source ~/.secrets/credentials.env
|
||
curl -sg "https://api.cloudflare.com/client/v4/user/tokens/verify" \
|
||
-H "Authorization: Bearer $CF_API_TOKEN" | jq '.result'
|
||
# {"id":"...", "status":"active", "expires_on":"..."}
|
||
```
|
||
|
||
### 1.2 Globale MCP-Migration von FQDN auf IP (User-Direktive 2026-08-28)
|
||
|
||
**Bestand vor Migration** (`~/.config/opencode/opencode.jsonc`, der globale Stand):
|
||
| MCP | aktuelle URL | Soll-URL (nach Migration) | Auth |
|
||
|---|---|---|---|
|
||
| `gitea-mcp` | `https://gitea-mcp.emsenhuber.net/mcp` ❌ | `http://10.40.20.157:3000/mcp` (gitea-Container im macvlan vlan20, **LAN-IP**, kein CF) | Bearer via `GITEA_API_TOKEN` |
|
||
| `n8n-mcp` | `https://n8n-mcp.emsenhuber.net/mcp` ❌ | `http://10.40.20.167:3001/mcp` (n8n-mcp-Container, macmini) — oder lokale IP. **Achtung:** `<n8n-mcp>.cf-tunnel-bf-mm` läuft über `bf-mm`-Tunnel, der Live ist. Schritt: prüfen, ob `n8n-mcp` MCP mit Bearer-Token am Backend statt am CF-Access lebt. | Bearer via `N8N_MCP_BEARER` |
|
||
| `cloudflare` | `https://mcp.cloudflare.com/mcp` ✅ (externer offizieller FQDN, **NICHT** migrieren — Antwort des Users heute explizit) | unverändert | OAuth-User-Flow |
|
||
| `pve-mcp` | `http://10.40.20.173:3000/mcp` ✅ | unverändert | keine (LAN-only) |
|
||
| `home-assistant` | `http://10.40.20.105:9583/...` ✅ | unverändert | Token in URL |
|
||
| `mikromcp` | npx-lokal | unverändert | env-PASS |
|
||
| `ollama` | npx-lokal | unverändert | env-OLLAMA_HOST |
|
||
| `hostinger-api` | npx-lokal | unverändert | env-TOKEN |
|
||
| `playwright` | npx-lokal | unverändert | keine |
|
||
|
||
**Was der Nachfolger macht:**
|
||
1. **Backup** der aktuellen `~/.config/opencode/opencode.jsonc` machen
|
||
(`cp ... .bak-pre-mcp-ip-migration-20260828`).
|
||
2. **Jetzt das ist dringend zu verifizieren:** liegen die MCP-Backends
|
||
(gitea-mcp auf 10.40.20.157, n8n-mcp auf 10.40.20.167, oder 10.40.20.105 für HA)
|
||
**tatsächlich** auf diesen IPs und antworten auf `/mcp`? **Bestandsaufnahme
|
||
zuerst**, nicht raten:
|
||
```bash
|
||
nc -z -G 3 10.40.20.157 3000 # gitea
|
||
nc -z -G 3 10.40.20.167 3001 # n8n-mcp
|
||
# Antwort: "Connection to ... port ... [tcp] succeeded!" = gut.
|
||
```
|
||
Falls eine IP nicht antwortet: **nicht** auf CF-FQDN zurückfallen — User-Direktive
|
||
war klar „FQDN raus". Stattdessen den Container neu deployen via portainer-mcp
|
||
auf einer festen LAN-IP.
|
||
3. **gitea-mcp** und **n8n-mcp** in `opencode.jsonc` umstellen:
|
||
- `url` auf die LAN-IP.
|
||
- `headers: {"Authorization": "Bearer {env:...}"}` — env-Werte aus
|
||
`~/.secrets/exports.zsh` (gitea-Token aus `git` User im gitea-Repo selbst;
|
||
n8n-MCP-Bearer aus dem n8n-mcp-Container-Config).
|
||
4. **Funktionstest** mit `opencode mcp list`, dann optional mit echtem Tool-Call
|
||
via LLM. Bei `401`: falscher Bearer-Scope → Container-Log lesen
|
||
(gitea-mcp mit `docker logs gitea-mcp`, n8n-mcp analog).
|
||
|
||
**Achtung:** die projektspezifische `bf-infra/opencode.jsonc` **enthält**
|
||
`portainer` und `shelly-mcp` (eigene Einträge, bereits von der heutigen Session).
|
||
Der globale opencode.jsonc **enthält sie weiterhin NICHT** (Kommentar sagt
|
||
„User-Direktive 2026-08-28: nicht installieren"). **Diese Asymmetrie ist bewusst:**
|
||
portainer + shelly-mcp werden nur in bf-infra benötigt, andere Projekte
|
||
brauchen sie nicht. **Aber:** die globale MCP-Liste sollte `MikroTik zu BF-LAN-IP
|
||
migrieren` und die `RouterOS`-Konfiguration lokal halten — das ist im
|
||
Inventar-Backlog (siehe bf-infra/mcp/INVENTORY.md).
|
||
|
||
### 1.3 terpene/blaueblueten-n8n — `.mcp.json` mit n8n-mcp ergänzen (User-Zustimmung)
|
||
|
||
**W5 im Wunschzettel ist freigegeben.** `blaueblueten-n8n/.mcp.json` existiert
|
||
schon mit `gitea-mcp`. **Was rein soll:**
|
||
```jsonc
|
||
{
|
||
"mcpServers": {
|
||
"gitea-mcp": { "type": "http", "url": "http://10.40.20.157:3000/mcp" },
|
||
"n8n-mcp": {
|
||
"type": "http",
|
||
"url": "http://10.40.20.167:3001/mcp",
|
||
"headers": {"Authorization": "Bearer <N8N_MCP_BEARER>"}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
- **Achtung Domain:** **420.teilzeitladen.xyz** (nicht `terpene.teilzeitladen.xyz`)
|
||
ist die Live-Domain. Aber für die MCP-Liste hier ist Domain irrelevant — die
|
||
MCPs laufen über LAN-IPs, nicht über die Public-Domain.
|
||
- **Source-of-truth der Token:** `N8N_MCP_BEARER` aus `~/.secrets/exports.zsh`.
|
||
Vor Eintrag erst verifizieren, dass es dort steht.
|
||
|
||
### 1.4 STATUS.md-Korrektur im terpene-Projekt (User-Direktive: **420.teilzeitladen.xyz** ist die echte Domain)
|
||
|
||
`STATUS.md` schreibt aktuell fälschlich `terpene.teilzeitladen.xyz` als Live-URL
|
||
(Zeile 6, „v3 — 2026-07-27"). Korrektur:
|
||
- Suchen/Ersetzen: `terpene.teilzeitladen.xyz` → `420.teilzeitladen.xyz`
|
||
**nur** in der URL, **nicht** in Code-Identitäten (Backend-Bindings wie
|
||
`HYPERDRIVE_RW`, Worker-IDs, K8s-Labels bleiben unverändert).
|
||
- Im STATUS.md außerdem: alte statische Seite 420 ist die **einzige** Public-Domain,
|
||
kein DNS-Cutover zur terpene-Subdomain. Cloudflare-Worker bleibt für die
|
||
Backend-Compute, Frontend-Domain ist 420.
|
||
|
||
---
|
||
|
||
## 2. Offene Punkte (User-gated)
|
||
|
||
### 2.1 W1 terpene — pg_hba.conf (User-blocked)
|
||
- **Status:** ⏸️ deferred. Christoph hat die Entscheidung.
|
||
- **Was Hubert in terpene dafür bräuchte:** `pg_hba.conf`-Zeile
|
||
`host terpene terpene_rw 10.40.10.0/24 scram-sha-256` + `pg_ctl reload`.
|
||
- **Was der Nachfolger NICHT tut:** keine Änderung. Wartet auf Christoph.
|
||
|
||
### 2.2 W2 terpene — `420.teilzeitladen.xyz` aus LAN erreichbar (TP31-Schritt 5–6)
|
||
- **Mechanik gelöst** durch 1.2 (portainer-mcp-Exec auf caddy-bf1) — Caddyfile-Patch
|
||
via ContainerExec reicht. **DNS-Token-Problem bleibt** (W6), aber Caddyfile-Patch
|
||
ist davon unabhängig.
|
||
- **Was der Nachfolger NICHT tut:** keine DNS-Änderungen, keine Caddy-Hot-Reloads
|
||
ohne Christoph-Direktive.
|
||
|
||
### 2.3 W3 terpene — Caddyfile-Patch ohne SSH
|
||
- **Status:** ⏸️ deferred. Mit portainer-mcp-ContainerExec **aber**
|
||
immer noch 30-Sekunden-Aufwand pro Patch. Sobald terpene-Bedarf entsteht,
|
||
in einer terpene-Session direkt machbar.
|
||
- **Was nicht im Weg steht:** portainer-mcp funktioniert (verifiziert heute).
|
||
|
||
### 2.4 W4 terpene — Caddy-Access-Logs lesbar
|
||
- **Status:** ⏸️ deferred. Kein Workaround.
|
||
|
||
### 2.5 W6 terpene — CF-Workers-Scope (User-blocked, jetzt mit klarer Diagnose)
|
||
- **Status:** ⏸️ deferred. **Aber:** der Befund 1.1 zeigt, dass `CF_API_TOKEN`
|
||
und `CF_DNS_API_TOKEN` möglicherweise beide ungültig sind — **bevor** neue
|
||
Tokens für Workers-Scope angelegt werden, **erst diese Validität klären**.
|
||
- **Vermutung:** Christophs `~/.secrets/` enthält einen **alten, abgelaufenen** Token.
|
||
Im CF-Dashboard nachsehen, ggf. neu anlegen.
|
||
|
||
### 2.6 W7 terpene — bf-public-Tunnel-Status
|
||
- **Wo steht's:** `docs/teilprojekte.md` Quick-Index, TP31-Zeile: „Offen: Schritt 5–6
|
||
(Tunnel `bf-public`, Abbau)".
|
||
- **Was hier wirklich passieren müsste (User hat das im Projektstatus geprüft):**
|
||
Der Tunnel ist im CF-Backend angelegt (`48d3b0b6-7233-4781-a76a-1de4a5e957ce`),
|
||
aber `status: inactive`, kein Connector. **Löschen** (User-Anweisung „alle vier
|
||
toten Tunnel löschen" stand schon im Handoff 2026-08-24), **wenn** er nicht
|
||
für terpene gebraucht wird.
|
||
- **Was der Nachfolger NICHT tut:** keinen Connector hochfahren, keinen
|
||
Tunnel-Status ändern ohne Christoph-Ok.
|
||
|
||
---
|
||
|
||
## 3. Werkzeug/MCP-Stand am Übergabepunkt
|
||
|
||
### 3.1 Bereitgestellt heute
|
||
- **portainer-mcp** in `bf-infra/opencode.jsonc` (uvx-stdio, 193 Tools)
|
||
- **shelly-mcp** in `bf-infra/opencode.jsonc` (remote StreamableHTTP,
|
||
`http://10.40.20.180:3030/mcp`)
|
||
- **Portainer-Server 2.40 → 2.42.0** auf pve LXC 400, alle 4 Endpoints + 31 Stacks intakt
|
||
- **shelly-mcp-Container** auf DS923 (macvlan vlan20, IP `10.40.20.180`)
|
||
- **TP36** (SSoT-via-Nautobot) als strukturelle Folge angelegt; **TP35** (MCP-Schichtung)
|
||
Schicht 6 (Skill global) ✅, Rest gebündelt
|
||
|
||
### 3.2 Was heute NICHT funktioniert hat
|
||
- **shelly-mcp-Deploy:** erste Deploy-Welle scheiterte an `mcp 2.x`-Inkompatibilität
|
||
(`MCPServer`-Umbenennung). Fix: `requirements.txt` `mcp[cli]>=1.0,<2`. **Commit `b8fd42b`.**
|
||
- **Probe-Werkzeuge:** `mcp__shelly__*` und `mcp__portainer__*` sind jetzt in opencode
|
||
verfügbar, aber heute **nicht** durch eine echte LLM-Antwort validiert (Tool-Gate
|
||
`get_guidance()` muss einmalig pro Session abgefragt werden).
|
||
- **Leak #2 in dieser Session:** `sed 's/SHELLY_DEVICE_PW=.*/=<set>/'` auf der Stack-YML
|
||
hat den Wert **nicht** maskiert. Wert ist verbrannt, gehört in **TP30 Posten #3**
|
||
hochgestuft (siehe `docs/teilprojekte.md` Abschnitt TP30). Lessons-Block in
|
||
CLAUDE.md ergänzt (Sed-Replacement-Pattern zu wenig greedy).
|
||
|
||
### 3.3 Globale vs. projekt-spezifische MCP-Liste — aktuelle Asymmetrie
|
||
- **global** (`~/.config/opencode/opencode.jsonc`): 11 MCPs, **enthält KEIN**
|
||
portainer + shelly-mcp. Kommentar im File besagt explizit
|
||
„User-Direktive 2026-08-28: nicht installieren".
|
||
- **projekt bf-infra** (`bf-infra/opencode.jsonc`): 11 MCPs, **enthält** portainer
|
||
+ shelly-mcp.
|
||
- **projekt terpene/blaueblueten-n8n** (`blaueblueten-n8n/.mcp.json`): **1 MCP** aktuell
|
||
(gitea-mcp), soll um n8n-mcp ergänzt werden (siehe 1.3).
|
||
|
||
---
|
||
|
||
## 4. Aus dem Userwortlaut zum Sessionende
|
||
|
||
Originalaussagen Christophs (verbatim, Reihenfolge wie im Chat):
|
||
1. „420.teilzeitladen.xyz ist unsere domain. alle übrigen sind ungültig und falsch."
|
||
2. „stelle n8n-mcp bitte global auf die passende IP um. gilt analog für alle übrigen
|
||
mcps, die noch fqdn verwenden."
|
||
3. „hast du einen konkreten plan, wie das projekt webseitig publiziert wird?
|
||
stichwort caddy cloudflare."
|
||
4. „prüfe welche berechtigungen du hast. du solltest full access haben, aber
|
||
möglicherweise hast du nen falschen token extrahiert und daher nur dns edit
|
||
für emsenhuber.net"
|
||
5. „intern geht es gerne auch ohne bearer. dsa war ja mitunter der gedanke,
|
||
weil es da immer probleme gab. warp löst es in einem zug."
|
||
|
||
**Aus 5.** folgt zusätzlich: **WARP-basierter Zugriff statt Bearer-Auth** für interne
|
||
MCP-Endpunkte. Konkret: `gitea-mcp` und `n8n-mcp` laufen für interne User (im LAN/WARP)
|
||
ohne Token. **Konsequenz für 1.2:** die `Authorization: Bearer` Header im
|
||
`opencode.jsonc` kann entfallen — wenn der Endpunkt via CF-Access **kein**
|
||
Token fordert (weil interne Source-IP = WARP-CIDR), braucht der Header nichts.
|
||
|
||
→ **Migrations-Reihenfolge für 1.2:**
|
||
(a) Erst WARP-Policy testen (geht der Connector ohne Token mit WARP?). Wenn ja: Header leer.
|
||
(b) Wenn nein: Bearer-Header mit Token aus `~/.secrets/`.
|
||
|
||
**Aus 3.** ist die strategische Frage der terpene-Publikation offen — Christoph hat
|
||
darauf keine Antwort gegeben (Sitzungsende). Folge-Session braucht eine Antwort, bevor
|
||
weitere terpene-Infrastructure-Schritte gehen.
|
||
|
||
---
|
||
|
||
## 5. Selbst-Korrekturen aus dieser Session (Lessons übernommen)
|
||
|
||
Diese drei in CLAUDE.md sind neu und der Nachfolger muss sie kennen:
|
||
- **Wartungs-Token**: `~/.secrets/exports.zsh` lädt **nicht automatisch** in jeder
|
||
Shell — `source` musst du explizit machen. Das `bash`-Tool in opencode macht das nicht.
|
||
Vor CF-Calls, vor Portainer-Calls, vor Secret-Vergleichen: `source ~/.secrets/exports.zsh`.
|
||
- **`sed 's/=.*/=<set>/'` maskiert NICHT**, wenn der Wert Slashes/Backslashes/Zeichen
|
||
enthält → siehe CLAUDE.md, Lessons-Block.
|
||
- **Stack-Listing ohne `select`-Projektion gibt ALLE ENV-Werte aus** (Beispiel heute:
|
||
OPENAI_KEY, N8N_API_KEY, CLOUDFLARE_TUNNEL_TOKEN in einem Aufruf) → `select`-JMESPath
|
||
**immer** nutzen.
|
||
|
||
---
|
||
|
||
## 6. Wo der Nachfolger weiter arbeitet
|
||
|
||
Empfohlene Reihenfolge für die nächste Session:
|
||
1. **1.1 CF-Token-Audit** (höchste Blocker-Kraft — fast alles hängt daran).
|
||
2. **1.2 Globale MCP-Migration** (gitea + n8n zuerst, weil terpene aktiv ist).
|
||
3. **1.4 STATUS.md-Korrektur** im terpene-Projekt (1 Minute).
|
||
4. **1.3 terpene-n8n-mcp** in `.mcp.json` (5 Minuten, sobald 1.2 durch ist).
|
||
5. **Strategie-Frage 3** aus 4.: **Wie publizieren wir terpene.teilzeitladen.xyz?**
|
||
Vorschlag für Christoph: Worker bleibt; `bf-public`-Tunnel ggf. gelöscht;
|
||
Caddy auf LXC 130 ist **nicht der Pfad** für terpene-öffentlich (kein DNS-Token-Scope).
|
||
|
||
**Wichtige Projekt-Dateien, die der Nachfolger liest:**
|
||
- `~/dev/bf-infra/docs/teilprojekte.md` — SSoT für alle TPs (Quick-Index Zeile 178–216).
|
||
- `~/dev/bf-infra/CLAUDE.md` Lessons-Block — alle hier entstandenen Lehren.
|
||
- `~/dev/bf-infra/opencode.jsonc` — projekt-spezifische MCP-Liste.
|
||
- `~/dev/bf-infra/mcp/INVENTORY.md` — was läuft, was war, was soll nicht.
|
||
- `~/dev/bf-infra/docs/handoff-20260828-portainer-bump-und-mcp.md` — Parallel-Handoff
|
||
zum Portainer-Bump.
|
||
- `~/dev/blaueblueten-n8n/docs/infra-wunschzettel.md` — Huberts Wunschzettel an Christoph.
|
||
- `~/dev/blaueblueten-n8n/STATUS.md` — terpene-Live-Status (mit Domain-Korrektur-Bedarf).
|
||
|
||
---
|
||
|
||
**Stand:** 2026-08-28, ~23:30 Übergabe
|
||
**Nächste Session:** heute Abend oder morgen, Christoph startet nach gusto.
|