Files
bf-infra/docs/mcp-host-policy.md
Christoph Emsenhuber 759491b512 MCP-Bestand korrigiert + Mac-mini-Performance-Restriktion
- gitea-mcp + n8n-mcp nachgetragen (waren real live, aber aus dem Inventar verschollen)
- pve-mcp: SSE-Doku -> StreamableHTTP-Realitaet
- shelly-mcp/portainer-mcp: bewusst KEIN MCP-Client (User-Direktive 2026-08-28)
- Mac mini = n8n-Host, NICHT zentraler MCP-Host (Performance-Restriktion)
- ~/.claude.json + opencode.jsonc: 9 MCPs identisch (vorher 7 vs. 11 Asymmetrie)
- docs/mcp-host-policy.md: SSoT fuer Host->FQDN/Stack-Mapping
- docs/handoff-20260828-mcp-bestand-und-performance.md: Folge-Sessions A/B/C

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-28 18:40:05 +02:00

6.0 KiB

MCP-Host-Policy — wo Hosts herkommen

Grundsatz: MCP-Endpoints (URLs, Hosts, IPs) werden nicht in ~/.claude.json oder ~/.config/opencode/opencode.jsonc hartcodiert. Sie kommen aus dem Repo (FQDN→Backend im caddy/Caddyfile, IP→Stack in docs/nas-vlan20/stacks/*.yml) oder werden live über Portainer-API verifiziert (/api/endpoints/<id>/docker/containers/json?all=1). In der Übergangszeit (GC rendert noch keine MCP-Liste) werden Hosts manuell in den genannten Configs gepflegt — aber immer mit Verweis auf diese Datei und das bf-infra-Repo.

Hosts, die als "localhost" laufen

Bestimmte MCP-Dienste werden auf mehreren Hosts gleichzeitig lokal betrieben. In der MCP-Config steht dann nicht eine spezifische IP, sondern localhost (127.0.0.1) — und jeder Host, auf dem der MCP läuft, hat seine eigene Config.

Dienst Hosts Begründung
ollama macmini (10.40.20.167, BF-LAN), meine Kiste / MacBook (lokal) Ollama läuft auf jedem Host, der sie braucht — der MCP-Client ist auch auf diesem Host, also reicht http://localhost:11434. Wer BF-LAN-Remote will: export OLLAMA_HOST=http://10.40.20.167:11434 in der Shell. Niemals in der MCP-Config hartcodieren — der zweite Host (z.B. ein LXC, ein dritter Mac) wäre dann ausgeschlossen.

Hosts, die aus dem Repo (FQDN→Backend) kommen

caddy/Caddyfile ist SSoT für die FQDN→Backend-IP-Port-Tabelle (Stand 2026-08-28):

Dienst FQDN Backend (caddy/Caddyfile) Container (Portainer Endpoint 20 = macmini)
gitea-mcp gitea-mcp.emsenhuber.net 10.40.20.167:3000 gitea-mcp (Image docker.io/node:22-alpine, eigenbau) — ⚠️ sollte auf DS923 umziehen (Performance-Restriktion, macmini ist User-Workstation)
n8n-mcp n8n-mcp.emsenhuber.net 10.40.20.167:3001 n8n-mcp (Image ghcr.io/czlonkowski/n8n-mcp:latest) — bleibt auf macmini: n8n-Workflows lösen Tool-Calls gegen diesen MCP aus, lokale Performance-Kopplung gewollt
ha-mcp ha-mcp.emsenhuber.net 10.40.20.105:9583 nicht im Bestand (Portainer) — externer Dienst

Mac mini ist der n8n-Host, NICHT der zentrale MCP-Host (User-Direktive 2026-08-28, Performance-Überlegung: User-Workstation soll nicht durch MCP-Clients zusätzlich belastet werden). Der zentrale MCP-Host ist die DS923 (nas-bf, Portainer Endpoint 14). gitea-mcp läuft dort nur historisch; Umzug ist separater Punkt.

Container-Definitionen leben auf dem macmini (Docker Desktop), nicht im bf-infra-Repo. Repo-Quelle ist nur das FQDN-Mapping im Caddyfile. Wer den Container umziehen will, ändert das Mapping, nicht die MCP-Config.

Hosts, die aus dem Repo (IP→Stack) kommen

docs/nas-vlan20/stacks/*.yml ist SSoT für Container auf der DS923 (Portainer Endpoint 14) — dem zentralen MCP-Host:

Dienst Stack-YML IP Status
pve-mcp pve-mcp.yml (gitignored) 10.40.20.173:3000/mcp 🟢 deployed
shelly-mcp mcp/shelly/{Dockerfile,BUILD.md} im Repo, Stack bewusst nicht im Repo (würde nur User-Direktive "kein MCP-Client" widersprechen). Deploy via Portainer-API direkt. 10.40.20.180:3030/mcp (geplant, Container kein MCP-Client) 🟡 staged (Build + Deploy ausstehend)
komodo-mcp — 10.40.20.176:3000/sse 🟡 geplant
gitea-mcp (geplant) 10.40.20.x:3000/mcp 🟡 Umzug macmini → DS923 (separater Punkt, Performance)
n8n-mcp bleibt macmini 10.40.20.167:3001/mcp 🟢 live, bewusst nicht umziehen (n8n-Workflow-Kopplung)

Hosts, die NICHT als MCP-Client exponiert werden (User-Direktive 2026-08-28)

Dienst Warum nicht als MCP-Client Alternative
portainer-mcp MCP-Client bietet keinen Mehrwert gegenüber dem Direkt-API-Zugriff (HTTP-Curl / Skript). Portainer-API direkt: mcp/portainer/.env hat PORTAINER_URL + PORTAINER_API_KEY. Skripte machen die Calls, kein Container-Layer nötig.
shelly-mcp Container-Deploy geht via Portainer-API (s.o.). Genau dasselbe: deployen via Portainer-API, Shelly-Verwaltung via Direkt-Aufrufe gegen die FastMCP-HTTP-Schnittstelle.

Entscheid gilt ab sofort. Wer in ~/.claude.json oder ~/.config/opencode/opencode.jsonc einen Block für portainer-mcp oder shelly-mcp anlegt, macht etwas verkehrt — mcp/INVENTORY.md aktualisieren, kein neuer MCP-Client.

Drift-Detection

Eine Änderung an einer IP im caddy/Caddyfile oder in docs/nas-vlan20/stacks/*.yml muss sich in ~/.claude.json / ~/.config/opencode/opencode.jsonc widerspiegeln — sonst zeigt der MCP-Client auf eine Adresse, an der der Dienst nicht (mehr) läuft. Aktuell ist dieser Sync manuell. Sobald TP34 (Caddyfile via Nautobot/GC) läuft, ist das die Vorlage für eine MCP-Endpoint-ComplianceRule: jede MCP-URL in den globalen Configs muss eine IP haben, die im Nautobot-Backend-Set existiert.

Lehren aus den Backups vom 2026-08-28

Die .bak-pre-mcp-cleanup-*-Dateien in ~/.claude.json.* und ~/.config/opencode/opencode.jsonc.* zeigen, was wirklich da war. Hätte ich sie vor dieser Session gelesen, wäre mir aufgefallen:

  1. gitea-mcp + n8n-mcp waren in ~/.claude.json nie eingetragen, obwohl die Container laufen. Drift seit unknown. (In opencode.jsonc waren sie.)
  2. shelly-mcp war in beiden Configs nie aktiv (immer enabled=false), und der Portainer-Stand war "kein Container" — der "folgt noch"-Pfad war doppelt blockiert.
  3. Backups lesen ist Pflicht, nicht Kür. Wer eine Vorgängersession zusammenfasst, schreibt die Backups auf die Liste — nicht nur das, was im Working-Tree des Repos liegt.

Stand

  • 2026-08-28 (zweite Fassung, nach User-Korrektur "pfui, schäm dich"): Symlink ~/.config/opencode/skills/projektstatus wurde wieder entfernt (opencode-Verzeichnis leer, kommt später neu).
  • Mac mini als zentraler MCP-Host bestätigt: gitea-mcp :3000 + n8n-mcp :3001 (Portainer Endpoint 20).
  • portainer-mcp + shelly-mcp sind keine MCP-Clients (Direkt-API-Wrapper reicht).