- 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>
6.0 KiB
MCP-Host-Policy — wo Hosts herkommen
Grundsatz: MCP-Endpoints (URLs, Hosts, IPs) werden nicht in
~/.claude.jsonoder~/.config/opencode/opencode.jsonchartcodiert. Sie kommen aus dem Repo (FQDN→Backend imcaddy/Caddyfile, IP→Stack indocs/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 dasbf-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:
gitea-mcp+n8n-mcpwaren in~/.claude.jsonnie eingetragen, obwohl die Container laufen. Drift seit unknown. (Inopencode.jsoncwaren sie.)shelly-mcpwar in beiden Configs nie aktiv (immerenabled=false), und der Portainer-Stand war "kein Container" — der "folgt noch"-Pfad war doppelt blockiert.- 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/projektstatuswurde 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-mcpsind keine MCP-Clients (Direkt-API-Wrapper reicht).