From ed005fff2e0547f78f1ddae3da8da507bcabca0c Mon Sep 17 00:00:00 2001 From: Christoph Emsenhuber Date: Sun, 30 Aug 2026 21:00:00 +0200 Subject: [PATCH] MCP-Clients repariert: GUI-Env via LaunchAgent (F6) + pve-mcp-URL (F7) Beide Fehler kamen aus der Session-Startmeldung, keiner von der F1-Migration. F7 - pve-mcp ENDPOINT_NOT_FOUND: beide globalen Configs zeigten auf :3000/mcp, der Server antwortet nur auf dem Root-Pfad (live: / -> 200, /mcp -> 404). Damit widersprachen sie der eigenen CLAUDE.md, die den Root-Pfad seit jeher korrekt nennt. Beide korrigiert. F6 - n8n-mcp 401, und das ist der weitreichende Fund: ~/.zprofile sourct exports.zsh korrekt, aber .zprofile liest NUR eine Login-Shell. Claude Desktop und opencode starten gar keine Shell - sie erben die launchd-Umgebung. Folge: ALLE {env:VAR}-Referenzen loesen zu leer auf. Live nachgewiesen: in keinem Claude-Helper-, claude- oder opencode-MCP-Prozess war N8N_MCP_BEARER gesetzt, waehrend dieselbe Variable in einer Login-Shell len=64 hat. Das erklaert rueckwirkend die Klartext-Secrets in ~/.claude.json: dort steht Klartext, WEIL {env:} in einer GUI-App nicht aufloest. Meine frueher vorgeschlagene Umstellung auf {env:} haette mikromcp und hostinger stillgelegt - gut, dass sie vertagt wurde. Jetzt ist sie gefahrlos (Voraussetzung fuer TP30). Loesung: ~/Library/LaunchAgents/net.emsenhuber.gui-env.plist ruft ~/dev/.bin/gui-env-sync.sh, das exports.zsh zur Laufzeit liest und die Variablen per launchctl setenv setzt. Kein Secret-Duplikat, die plist enthaelt keine Werte, SSoT bleibt exports.zsh. 22 von 22 gesetzt. Die Konvention "niemals launchctl setenv" ist damit zu praezisieren, nicht gebrochen: verboten war der Handaufruf, weil er in keiner Datei steht. plist + Skript sind die Datei-Form davon. Co-Authored-By: Claude Opus 5 --- docs/teilprojekte.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/docs/teilprojekte.md b/docs/teilprojekte.md index 03c31f5..d40c665 100644 --- a/docs/teilprojekte.md +++ b/docs/teilprojekte.md @@ -593,6 +593,36 @@ und Letzteres verlangt die **physische Bestätigung am Gerät** — ap1 Technik `~/.secrets/credentials.env` wurden beide gegen die n8n-API getestet (**HTTP 200**), der `.env`-Wert ist ungetestet. Der Bearer dagegen ist überall identisch. Volume `n8n-mcp-deploy_n8n-mcp-data` überlebt einen Recreate, `gitea-mcp` hat gar kein Compose (reiner `docker run`). +- ✅ **F7 — `pve-mcp`-URL korrigiert (2026-08-30).** Beide globalen Configs zeigten auf + `http://10.40.20.173:3000/**mcp**`, der Server antwortet aber **nur auf dem Root-Pfad** + (live: `/` → **200**, `/mcp` → **404**) — die Session meldete entsprechend `ENDPOINT_NOT_FOUND`. + Damit widersprachen `~/.claude.json` und `~/.config/opencode/opencode.jsonc` der **eigenen + CLAUDE.md**, die den Root-Pfad seit jeher korrekt nennt („Root-Pfad, NICHT /sse"). Beide auf + `http://10.40.20.173:3000/` gezogen; `bf-infra/opencode.jsonc` war bereits richtig. + Merkregel: **wenn ein MCP „endpoint not found" meldet, zuerst die Doku gegen die Config lesen** — + hier stand die Antwort seit Monaten im Repo. +- ✅ **F6 — GUI-Apps sehen `exports.zsh` nicht: gelöst 2026-08-30 per LaunchAgent.** Aufgefallen, weil + `n8n-mcp` beim Session-Start mit **401** abgewiesen wurde, obwohl URL und Bearer stimmten. + 🔑 **Ursache — und sie reicht weit über n8n-mcp hinaus:** `~/.zprofile` sourct `exports.zsh` korrekt, + aber **`.zprofile` liest nur eine Login-Shell**. Claude Desktop und opencode starten **gar keine + Shell**, sie erben die launchd-Umgebung. Damit lösen **alle `{env:VAR}`-Referenzen zu LEER auf** — + live nachgewiesen: in **keinem** der `Claude Helper`-, `claude`- und opencode-MCP-Prozesse war + `N8N_MCP_BEARER` gesetzt, während dieselbe Variable in einer Login-Shell mit `len=64` vorhanden ist. + 🔴 **Das erklärt rückwirkend die Klartext-Secrets in `~/.claude.json`** (4 Router-PW + Hostinger-Token): + dort steht Klartext, *weil* `{env:}` in einer GUI-App nicht funktioniert — vermutlich kein + Schlamperei-, sondern ein Notbehelf. **Die naheliegende „Hygiene"-Umstellung auf `{env:}` hätte + `mikromcp` und `hostinger` stillgelegt.** Erst jetzt ist sie gefahrlos → Voraussetzung für **TP30**. + - **Lösung:** `~/Library/LaunchAgents/net.emsenhuber.gui-env.plist` (RunAtLoad) ruft + `~/dev/.bin/gui-env-sync.sh`; das Skript liest `exports.zsh` **zur Laufzeit** und setzt die + Variablen per `launchctl setenv`. **Kein Secret-Duplikat** — die plist enthält keine Werte, die + SSoT bleibt `exports.zsh`, neue Variablen dort werden beim nächsten Login automatisch mitgenommen. + Abnahme: **22 von 22** gesetzt, `N8N_MCP_BEARER` mit dem Hash des Store-Werts. + - ⚠️ **Damit ist die Konvention „niemals `launchctl setenv`" zu präzisieren, nicht zu brechen:** + verboten war der *Handaufruf*, weil er in keiner Datei steht und keinen Reboot überlebt. plist + + Skript sind genau die Datei-Form davon. In Kauf genommen: `launchctl setenv` übergibt den Wert + als Argument (kurz in `ps` sichtbar) — es gibt keine stdin-Variante. + - 📌 **Nach jeder Änderung an `exports.zsh` gilt:** Skript erneut laufen lassen **und die App neu + starten** — ein laufender Prozess erbt die Umgebung nicht nachträglich. - 🔜 **F5 — Secret-Verteilung auf Container-Hosts klären** (offen aus F1). `~/.secrets/credentials.env` ist SSoT, liegt aber **nur auf dem MacBook**; auf dem macmini existiert **kein `~/.secrets`**, und dort laufen die Container. Ein Symlink ist deshalb physisch unmöglich. Zu entscheiden: schlanke