[Cline-MCP] homelab_docs-Tool gebaut – Hänger beim Streamen von Secrets (Windows ssh.exe) #101

Closed
opened 2026-06-13 08:52:26 +00:00 by orbitalo · 1 comment
Owner

Kontext

Im Rahmen von #97 (Cline als Cursor-Ersatz) wurde beschlossen: CT 999 muss primärer Anlaufpunkt für Homelab-Wissen sein (statt raten). Dafür wurde ein homelab_docs-MCP-Tool gebaut, das die CT-999-Doku (/root/docs) durchsucht/liest – damit Cline/DeepSeek erst nachschlägt statt zu halluzinieren.

Was fertig ist

  • MCP-Server liegt auf dem KI-Server: C:\dev\homelab\homelab_docs_mcp\server.py
  • Tools: search_docs(query), read_doc(path), list_docs(subdir)
  • Datenquelle: passwortloser SSH KI-Server → pve-hetzner (root@100.88.230.59) → pct exec 999/root/docs (Markdown)
  • Robust gebaut: subprocess mit Arg-Listen, shlex.quote, Pfad-Traversal-Schutz (kein ..), ssh -n + stdin=DEVNULL
  • Glob-Falle gefixt: kein --include=*.md / -name '*.md' mehr durch die Remote-Shell (Quoting überlebt Windows-ssh nicht) → .md-Filter jetzt clientseitig in Python
  • Noch NICHT in cline_mcp_settings.json registriert (wegen offenem Blocker unten)

Funktioniert

  • read_doc auf normale Dateien: schnell (z. B. index.md, 26 KB → 1,2s)
  • SSH-Pfad KI→Hetzner→CT999: ok

BLOCKER

Jeder Befehl, der Inhalt aus credentials.md über Windows-ssh.exe + Python-subprocess zurückstreamt, hängt 30s im Timeout – egal ob cat, head -1, grep (mit Treffer) oder base64.

Eingrenzung (alle Tests vom KI-Server-Python aus)

Test Ergebnis
cat index.md (kein Secret) 1,2s OK
grep xyznomatch credentials.md (liest, kein Output) 1,2s OK
cat credentials.md TIMEOUT
head -1 credentials.md (nur Titelzeile) TIMEOUT
base64 credentials.md TIMEOUT
gleicher Inhalt, neutraler Name (zzz_tmp.md) TIMEOUT

Ausgeschlossen

  • Dateiname (Kopie mit neutralem Namen hängt ebenso)
  • „Böse Bytes" (Datei ist sauberes UTF-8; base64 wäre reines ASCII)
  • Dateigröße (credentials.md = 7,6 KB < index.md = 26 KB, das funktioniert)
  • stdin-Hänger (ssh -n + stdin=DEVNULL ändern nichts)
  • SSH-Quoting (direkte Hetzner-Shell führt dieselben Befehle in 1,5–4s aus)

Beste Hypothese

Ein Windows-seitiger Content-Scanner (Defender / DLP / Endpoint-Security) auf dem KI-Server hängt sich in die ssh.exe-Pipe ein, sobald durchfließende Daten wie Passwörter/API-Keys aussehen. Reines Lesen ohne Output und Nicht-Secret-Dateien passieren ungestört. Erklärt auch, warum search_docs('openrouter') hängt (Treffer stammt aus credentials.md).

Nächste Schritte

  1. Beweis: Defender/Endpoint-Security testweise pausieren, cat credentials.md vom KI-Python erneut → wenn dann schnell, ist die Ursache bestätigt.
  2. Falls bestätigt: Tool soll nie Roh-Secrets streamen – Treffer/Zeilen aus credentials.md serverseitig maskieren (nur Zeilennr. + Key-Name, Wert ***).
  3. Danach homelab_docs in cline_mcp_settings.json registrieren und in .clinerules verankern: „bei Pfaden/Configs/Zugangsdaten IMMER zuerst homelab_docs fragen".

Betroffene Systeme

KI-Server (Windows, Cline), pve-hetzner, CT 999 (cluster-docu)

## Kontext Im Rahmen von #97 (Cline als Cursor-Ersatz) wurde beschlossen: **CT 999 muss primärer Anlaufpunkt für Homelab-Wissen sein** (statt raten). Dafür wurde ein `homelab_docs`-MCP-Tool gebaut, das die CT-999-Doku (`/root/docs`) durchsucht/liest – damit Cline/DeepSeek erst nachschlägt statt zu halluzinieren. ## Was fertig ist - MCP-Server liegt auf dem KI-Server: `C:\dev\homelab\homelab_docs_mcp\server.py` - Tools: `search_docs(query)`, `read_doc(path)`, `list_docs(subdir)` - Datenquelle: passwortloser SSH KI-Server → pve-hetzner (`root@100.88.230.59`) → `pct exec 999` → `/root/docs` (Markdown) - Robust gebaut: `subprocess` mit Arg-Listen, `shlex.quote`, Pfad-Traversal-Schutz (kein `..`), `ssh -n` + `stdin=DEVNULL` - **Glob-Falle gefixt**: kein `--include=*.md` / `-name '*.md'` mehr durch die Remote-Shell (Quoting überlebt Windows-ssh nicht) → `.md`-Filter jetzt clientseitig in Python - Noch NICHT in `cline_mcp_settings.json` registriert (wegen offenem Blocker unten) ## Funktioniert - `read_doc` auf normale Dateien: schnell (z. B. `index.md`, 26 KB → 1,2s) - SSH-Pfad KI→Hetzner→CT999: ok ## BLOCKER **Jeder Befehl, der Inhalt aus `credentials.md` über Windows-`ssh.exe` + Python-`subprocess` zurückstreamt, hängt 30s im Timeout** – egal ob `cat`, `head -1`, `grep` (mit Treffer) oder `base64`. ### Eingrenzung (alle Tests vom KI-Server-Python aus) | Test | Ergebnis | |---|---| | `cat index.md` (kein Secret) | 1,2s OK | | `grep xyznomatch credentials.md` (liest, **kein Output**) | 1,2s OK | | `cat credentials.md` | TIMEOUT | | `head -1 credentials.md` (nur Titelzeile) | TIMEOUT | | `base64 credentials.md` | TIMEOUT | | gleicher Inhalt, **neutraler Name** (`zzz_tmp.md`) | TIMEOUT | ### Ausgeschlossen - Dateiname (Kopie mit neutralem Namen hängt ebenso) - „Böse Bytes" (Datei ist sauberes UTF-8; base64 wäre reines ASCII) - Dateigröße (credentials.md = 7,6 KB < index.md = 26 KB, das funktioniert) - stdin-Hänger (`ssh -n` + `stdin=DEVNULL` ändern nichts) - SSH-Quoting (direkte Hetzner-Shell führt dieselben Befehle in 1,5–4s aus) ### Beste Hypothese Ein **Windows-seitiger Content-Scanner (Defender / DLP / Endpoint-Security)** auf dem KI-Server hängt sich in die `ssh.exe`-Pipe ein, sobald durchfließende Daten wie Passwörter/API-Keys aussehen. Reines Lesen ohne Output und Nicht-Secret-Dateien passieren ungestört. Erklärt auch, warum `search_docs('openrouter')` hängt (Treffer stammt aus `credentials.md`). ## Nächste Schritte 1. Beweis: Defender/Endpoint-Security testweise pausieren, `cat credentials.md` vom KI-Python erneut → wenn dann schnell, ist die Ursache bestätigt. 2. Falls bestätigt: Tool soll **nie Roh-Secrets streamen** – Treffer/Zeilen aus `credentials.md` serverseitig maskieren (nur Zeilennr. + Key-Name, Wert `***`). 3. Danach `homelab_docs` in `cline_mcp_settings.json` registrieren und in `.clinerules` verankern: „bei Pfaden/Configs/Zugangsdaten IMMER zuerst homelab_docs fragen". ## Betroffene Systeme KI-Server (Windows, Cline), pve-hetzner, CT 999 (cluster-docu)
Author
Owner

Gelöst

Blocker analysiert und behoben, end-to-end über den echten MCP-Weg verifiziert.

Zwei unabhängige Root Causes

  1. Windows Defender inspiziert die ssh.exe-stdout-Pipe und blockiert secret-artigen Inhalt am Stream-Ende. Beweis: cat credentials.md → ~7680/7687 Bytes kommen an, dann kein EOF (30s Timeout); Umleitung in eine Datei statt Pipe → 1,2s. Nicht der Dateiname, sondern der Inhalt (neutraler-Name-Kopie hängt, credential-Name-mit-harmlosem-Inhalt läuft). Auch secret-dichte greps (openrouter) betroffen. Einziges AV: Windows Defender (RealTimeProtection/NIS/BehaviorMonitor).
  2. ssh.exe startet gar nicht aus dem MCP-stdio-Subprozess (rc 255, null Output, auch mit -vvv/full-path/CREATE_NO_WINDOW/cmd), während cmd /c ver im selben Kontext funktioniert → fehlende Console-/Terminal-Handles. Zusätzlich nutzte Cline ein python ohne die nötigen Pakete.

Finale Lösung

  • MCP-Server auf paramiko umgestellt (reiner stdio-JSON-RPC + paramiko, kein fastmcp/ssh.exe mehr). paramiko liest über einen Socket statt über die ssh.exe-Pipe → beide Root Causes erledigt (kein Console-Problem, keine Defender-Pipe-Inspektion). Damit ist auch der frühere 20%-Rest (search auf secret-dichte Begriffe) weg.
  • Key: C:\Users\wutti\.ssh\id_ed25519root@100.88.230.59pct exec 999 -- ...
  • In cline_mcp_settings.json registriert mit vollem Python-Pfad (...Python310\python.exe) und alwaysAllow für search_docs/read_doc/list_docs.
  • In .clinerules verankert (REGEL 1b): bei Pfaden/Configs/Zugangsdaten zuerst homelab_docs fragen statt zu raten; credentials.md nicht per direktem SSH catten.

Verifikation (echter MCP-stdio-Weg, wie Cline)

  • list_docs() → 79 Doku-Dateien, 1,2s
  • read_doc('credentials.md') → 7677 Zeichen, 1,1s (Ur-Blocker)
  • read_doc('container/ct-116-…') → 36343 Zeichen, 1,2s
  • search_docs('openrouter') → 4330 Zeichen, 1,1s (vorher 30s-Hänger)

Cline schlägt jetzt zuverlässig in CT 999 nach statt zu halluzinieren.

Betroffene Systeme

KI-Server (Windows, Cline), pve-hetzner, CT 999 (cluster-docu)

## Gelöst ✅ Blocker analysiert und behoben, end-to-end über den echten MCP-Weg verifiziert. ### Zwei unabhängige Root Causes 1. **Windows Defender inspiziert die `ssh.exe`-stdout-Pipe** und blockiert secret-artigen Inhalt am Stream-Ende. Beweis: `cat credentials.md` → ~7680/7687 Bytes kommen an, dann kein EOF (30s Timeout); Umleitung in eine Datei statt Pipe → 1,2s. Nicht der Dateiname, sondern der Inhalt (neutraler-Name-Kopie hängt, credential-Name-mit-harmlosem-Inhalt läuft). Auch secret-dichte greps (`openrouter`) betroffen. Einziges AV: Windows Defender (RealTimeProtection/NIS/BehaviorMonitor). 2. **`ssh.exe` startet gar nicht aus dem MCP-stdio-Subprozess** (rc 255, null Output, auch mit `-vvv`/full-path/`CREATE_NO_WINDOW`/`cmd`), während `cmd /c ver` im selben Kontext funktioniert → fehlende Console-/Terminal-Handles. Zusätzlich nutzte Cline ein `python` ohne die nötigen Pakete. ### Finale Lösung - MCP-Server auf **paramiko** umgestellt (reiner stdio-JSON-RPC + paramiko, kein fastmcp/ssh.exe mehr). paramiko liest über einen **Socket** statt über die `ssh.exe`-Pipe → **beide** Root Causes erledigt (kein Console-Problem, keine Defender-Pipe-Inspektion). Damit ist auch der frühere 20%-Rest (search auf secret-dichte Begriffe) weg. - Key: `C:\Users\wutti\.ssh\id_ed25519` → `root@100.88.230.59` → `pct exec 999 -- ...` - In `cline_mcp_settings.json` registriert mit **vollem Python-Pfad** (`...Python310\python.exe`) und `alwaysAllow` für `search_docs`/`read_doc`/`list_docs`. - In `.clinerules` verankert (REGEL 1b): bei Pfaden/Configs/Zugangsdaten zuerst `homelab_docs` fragen statt zu raten; `credentials.md` nicht per direktem SSH catten. ### Verifikation (echter MCP-stdio-Weg, wie Cline) - `list_docs()` → 79 Doku-Dateien, 1,2s - `read_doc('credentials.md')` → 7677 Zeichen, 1,1s (Ur-Blocker) - `read_doc('container/ct-116-…')` → 36343 Zeichen, 1,2s - `search_docs('openrouter')` → 4330 Zeichen, 1,1s (vorher 30s-Hänger) Cline schlägt jetzt zuverlässig in CT 999 nach statt zu halluzinieren. ## Betroffene Systeme KI-Server (Windows, Cline), pve-hetzner, CT 999 (cluster-docu)
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: orbitalo/homelab-brain#101
No description provided.