How to: OpenClaw an einen GTS Business Brain anbinden

Dieses How-to verbindet einen OpenClaw-Agent (z.B. ein Slack-/Discord-Bot) mit einem Ground Truth System Business Brain, sodass der Agent die Brain-Tools (lesen, schreiben, suchen, committen) aus einem Chat-Channel nutzen kann.

Ergebnis: Ein User schreibt im Slack-Channel "Leg ein Projekt-Brain für Kunde XY an", der Agent ruft via MCP brain_write auf dem Ziel-Server, schreibt eine schema-validierte Markdown-Datei, committed atomar in git, und meldet den Commit-Hash zurück.


Voraussetzungen

Auf dem Agent-Host (der Server auf dem OpenClaw läuft, wir nennen ihn im Folgenden AGENT_HOST):

  • OpenClaw installiert und openclaw-gateway.service aktiv
  • Root-SSH-Zugang
  • node, ssh, ssh-keygen vorhanden

Auf dem Brain-Host (der Server auf dem der GTS Business Brain läuft, im Folgenden BRAIN_HOST):

  • GTS deployed (siehe DEPLOYMENT.md)
  • Instance mit type: business unter <BRAIN_INSTANCE_DIR>/.gts/config.yaml
  • /packages/mcp/dist/server.js liegt und ist executable (wird vom Repo-Build mitgeliefert)
  • Root-SSH-Zugang für den einmaligen Key-Import

Vom Operator-Laptop (wo du das How-to ausführst): SSH-Aliase oder direkt root@ip zu beiden Hosts konfiguriert.


Überblick

┌───────────────────┐              ┌───────────────────────┐
│  AGENT_HOST       │              │   BRAIN_HOST          │
│                   │   SSH        │                       │
│  openclaw-gateway │────────────▶ │  node packages/mcp    │
│        │          │   (MCP via   │       /dist/server.js │
│   Slack/Discord   │    stdio)    │        │              │
│        │          │              │   writeBrain → git    │
│        ▼          │              │                       │
│   User im Channel │              │   <BRAIN_INSTANCE_DIR>│
└───────────────────┘              └───────────────────────┘

Der OpenClaw-Gateway spawnt bei jedem Tool-Call einen SSH-Prozess zu BRAIN_HOST, der dort den MCP-Server-Node-Prozess startet. Die Kommunikation läuft über stdio. Das Key-Paar ist dediziert für diese Verbindung.


Schritt 1 — SSH-Key-Paar auf dem Agent-Host erzeugen

Auf AGENT_HOST:

ssh-keygen -t ed25519 -f ~/.ssh/agent_to_brain -N "" -C "openclaw@$(hostname)"
  • -N "" = keine Passphrase (systemd-Service muss ohne Interaktion SSH-en)
  • Der Comment dokumentiert Herkunft für später

Public-Key zeigen (brauchst du im nächsten Schritt):

cat ~/.ssh/agent_to_brain.pub

Schritt 2 — Public-Key auf dem Brain-Host autorisieren

Auf BRAIN_HOST (z.B. von deinem Laptop per SSH):

# Public-Key aus Schritt 1 anhängen
echo "ssh-ed25519 AAAAC3... openclaw@agent-host" >> /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys

Schritt 3 — SSH-Config auf dem Agent-Host

Auf AGENT_HOST:

cat >> ~/.ssh/config <<'EOF'

Host brain-host
  HostName <brain-host-ip-or-domain>
  User root
  IdentityFile ~/.ssh/agent_to_brain
  IdentitiesOnly yes
  StrictHostKeyChecking no
  UserKnownHostsFile ~/.ssh/known_hosts
  # Pool für schnelle Folge-Calls (ControlMaster)
  ControlMaster auto
  ControlPath ~/.ssh/cm-%r@%h:%p
  ControlPersist 10m
EOF
chmod 600 ~/.ssh/config

ControlMaster + ControlPersist 10m sind wichtig: ohne Multiplex kostet jeder Tool-Call ~500ms für den SSH-Handshake; mit Pool bleibt die Verbindung offen und Folgecalls sind quasi instant.

Testen:

ssh brain-host 'echo ok from $(hostname); node --version; ls /opt/gts-business/packages/mcp/dist/server.js'

Erwartete Ausgabe: ok from <brain-host-hostname>, node-Version, und der Pfad zum MCP-Server-Binary.

Schritt 4 — MCP-Eintrag in OpenClaw registrieren

Auf AGENT_HOST:

openclaw mcp set kuble-business '{
  "command": "ssh",
  "args": [
    "brain-host",
    "GTS_INSTANCE_DIR=/opt/gts-business/data/instance GTS_MCP_ACTOR_EMAIL=hermes@kuble.com GTS_MCP_ACTOR_NAME=hermes GTS_MCP_READONLY_CATEGORIES=slow node /opt/gts-business/packages/mcp/dist/server.js"
  ]
}'

Was die Env-Variablen tun:

Variable Zweck
GTS_INSTANCE_DIR Welches Instance-Verzeichnis der MCP-Server bedient (muss .gts/config.yaml enthalten)
GTS_MCP_ACTOR_EMAIL Git-Commit-Autor-Email, so dass History klar ausweist "das war Hermes, nicht Gustavo"
GTS_MCP_ACTOR_NAME Git-Commit-Autor-Name (selber Zweck)
GTS_MCP_READONLY_CATEGORIES Comma-separierte Liste von Kategorien die der Agent nicht schreiben darf. slow ist hier gut: fundamentale Firmenwerte, Prozesse — nur Menschen sollten das bearbeiten

Verifizieren:

openclaw mcp list                       # sollte "kuble-business" zeigen
openclaw mcp show kuble-business        # zeigt das JSON zurück

Schritt 5 — OpenClaw-Gateway neustarten

systemctl --user restart openclaw-gateway.service
sleep 2
systemctl --user is-active openclaw-gateway.service    # → "active"

Schritt 6 — Smoke-Test

(a) MCP-Handshake direkt über SSH prüfen (geht ohne OpenClaw im Weg):

echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"probe","version":"0"}}}' \
  | ssh brain-host "GTS_INSTANCE_DIR=/opt/gts-business/data/instance GTS_MCP_READONLY_CATEGORIES=slow node /opt/gts-business/packages/mcp/dist/server.js"

Erwartete Ausgabe (erste Zeile ist stderr, zweite ist das JSON):

[gts-mcp] connected. instance=kuble (business) dir=... readonly=[slow]
{"result":{"protocolVersion":"2024-11-05","capabilities":{"tools":{"listChanged":true}},"serverInfo":{"name":"gts-mcp","version":"0.3.0"},"instructions":"Ground Truth System — ... WRITE POLICY: ... readonly: slow ..."}}

Wenn du readonly=[slow] in stderr + WRITE POLICY im instructions siehst — Setup ist korrekt.

(b) Über den Bot im Chat-Channel testen:

Schreibe im Slack-/Discord-Channel in dem der Agent zuhört:

Liste alle Brains dieser Instanz

Der Agent sollte brain_list aufrufen und eine Liste zurückgeben.

Erstelle ein Projekt-Brain kuble.projekt.demo mit Titel "Demo Projekt", Status "active" und leerem Body

Der Agent sollte brain_write aufrufen und einen Commit-Hash melden.

Ändere kuble.slow.werte auf XYZ

Der Agent sollte ablehnen mit der Policy-Message ("Writes to category 'slow' are forbidden ... edit via the web UI").


Verfügbare Tools

Nach erfolgreichem Setup sieht der Agent sieben Tools:

Tool Scope Zweck
brain_list read Brains filtern (Kategorie, Tag, Limit)
brain_read read Vollständiges Brain lesen
brain_search read Substring-Suche in id/title/tags/body
brain_write write* Create oder Update, schema-validiert, git-commit
brain_capture write* Quick-capture in Inbox
brain_history read Git-History pro Brain
instance_info read Metadata + welche Kategorien readonly sind

* write-Tools werden pro Kategorie gegated via GTS_MCP_READONLY_CATEGORIES.


Mehrere Brains anbinden

Du kannst beliebig viele MCP-Server registrieren. Z.B. zusätzlich das Personal Brain einer Person:

openclaw mcp set gustavo-personal '{
  "command": "ssh",
  "args": [
    "gustavo-brain",
    "GTS_INSTANCE_DIR=/var/lib/gts-personal GTS_MCP_READONLY_CATEGORIES=private node /opt/gts-personal/packages/mcp/dist/server.js"
  ]
}'
systemctl --user restart openclaw-gateway.service

Im Chat kann der Agent dann beide Tool-Sets parallel nutzen (pro MCP-Server ein Namespace).


Entfernen / Rotieren

MCP-Eintrag entfernen:

openclaw mcp unset kuble-business
systemctl --user restart openclaw-gateway.service

Key rotieren (sicherheitshygiene alle 90d):

# Auf AGENT_HOST: neuen Key generieren
ssh-keygen -t ed25519 -f ~/.ssh/agent_to_brain.new -N "" -C "openclaw@$(hostname)"

# Public-Key auf BRAIN_HOST zu authorized_keys zufügen (alter Key noch drin)
cat ~/.ssh/agent_to_brain.new.pub | ssh brain-host 'cat >> ~/.ssh/authorized_keys'

# Lokale SSH-Config auf neuen Key umstellen
sed -i 's|agent_to_brain$|agent_to_brain.new|' ~/.ssh/config

# Testen ob's geht
ssh brain-host 'echo new key ok'

# Alten Key aus authorized_keys auf BRAIN_HOST entfernen (per Editor)
# Alten Key lokal löschen
rm ~/.ssh/agent_to_brain ~/.ssh/agent_to_brain.pub
mv ~/.ssh/agent_to_brain.new ~/.ssh/agent_to_brain
mv ~/.ssh/agent_to_brain.new.pub ~/.ssh/agent_to_brain.pub

Troubleshooting

"Permission denied (publickey)" beim SSH-Test

  • Public-Key nicht in /root/.ssh/authorized_keys auf BRAIN_HOST
  • oder ~/.ssh/authorized_keys Permissions falsch — chmod 600
  • oder SSH-Config verweist auf falschen IdentityFile

Agent macht Tool-Call aber Antwort timed out

  • SSH-Verbindung lang-latent? ControlMaster in SSH-Config setzen
  • Nginx/Firewall auf BRAIN_HOST blockt SSH? (sollte nicht — SSH läuft auf Port 22, nicht durch den Proxy)
  • Log auf AGENT_HOST: journalctl --user -u openclaw-gateway -n 100

"OPENROUTER_API_KEY not configured" Fehler im Chat

  • Das ist der Built-in-Assistent-Pfad, nicht der MCP-Pfad. OpenClaw via MCP nutzt seinen eigenen LLM-Provider (z.B. Minimax, konfiguriert in /root/.openclaw/openclaw.json). Der GTS-Assistent auf /assistant nutzt OpenRouter. Unterschiedliche Wege.

Agent schreibt in falsche Kategorie

  • Prüf GTS_MCP_READONLY_CATEGORIES in der MCP-Config: openclaw mcp show kuble-business
  • Muss pro MCP-Spawn gesetzt sein — die Env-Datei /etc/gts-business.env (die vom Next-Server gelesen wird) gilt nicht für einmalige SSH-Invocations!

slow-Writes gehen trotzdem durch

  • GTS_MCP_READONLY_CATEGORIES=slow in der Spawn-Command vergessen.
  • Fix via openclaw mcp set mit vollständigem Env-String neu setzen.

Gateway crasht nach Restart

  • Log checken: journalctl --user -u openclaw-gateway -n 50 --no-pager
  • Häufig: MCP-JSON-Syntax kaputt in /root/.openclaw/openclaw.json — aus openclaw.json.bak restoren: cp /root/.openclaw/openclaw.json.bak /root/.openclaw/openclaw.json

Sicherheitsmodell — was ist gut, was nicht

Gut:

  • Dedizierter SSH-Key pro Verbindung → rotierbar ohne andere zu brechen
  • GTS_MCP_READONLY_CATEGORIES sperrt Kern-Brains (Werte, Prozesse) vor Agent-Writes — Menschen-only Bereich bleibt geschützt
  • Jeder Write geht durch @gts/core.writeBrain → Schema-Validation + git Commit; Audit-Trail automatisch da
  • GTS_MCP_ACTOR_EMAIL macht in der git-History sichtbar wer schreibt (Agent vs. Human vs. CI)

Was NICHT im MCP-Layer passiert:

  • Keine Rate-Limits auf Agent-Seite → wenn der Agent in einer Schleife schreibt, hat er freies Feld. Rate-Limit müsste in OpenClaw selbst sein
  • Keine Content-Validation über Schema hinaus → Agent kann ein Brain mit syntaktisch gültigem Inhalt aber „schlechter" Prosa schreiben. Qualität ist Agent-Prompt-Sache
  • SSH-Key liegt in Klartext auf AGENT_HOST → wenn dieser gehackt ist, ist der BRAIN_HOST auch gefährdet (in den Kategorien die nicht readonly sind)

Wenn du's enger willst:

  • Pro Agent eine eigene User-Account auf BRAIN_HOST anlegen (statt root), mit eingeschränkten Filesystem-Permissions
  • SELinux / AppArmor Policy für den MCP-Server-Prozess
  • Separate GTS-Instanz nur für Agent-Writes (die menschliche Produktion läuft parallel, Sync nachts per git-pull)

Für den MVP-Stand ist die aktuelle Setup ausreichend — aber dokumentiert, falls du später tiefer gehen willst.