Files
bf-infra/docs/handoff-20260828-portainer-bump-und-mcp.md
Christoph Emsenhuber 3562e19e47 Portainer 2.40 → 2.42.0 Bump + portainer-mcp projektspezifisch
Portainer-Server (pve LXC 400): 2.40.0 → 2.42.0 via Image-Swap mit Volume-Erhalt.
Pre-Upgrade-Snapshot: docker commit :2.40.0-preupgrade-20260828 (Rollback 7 d
verfügbar) + Settings/Stacks/Endpoints-JSON-Dump (40 KB, 31 Stacks, 4 Endpoints).
Instance-ID + API-Token nach Bump identisch — kein Re-Auth, kein Settings-Verlust.

portainer-mcp: offizielles PyPI-Paket mcp-portainer~=2.42.0 (193 Tools), nur
in bf-infra/opencode.jsonc, via uvx-stdio. Tool-Gate: get_guidance() einmal pro
Session zwingend vor erstem Read. Andere Projekte unberührt.

Korrekturen ggü. Handoff 2026-08-28 README:
- mcp-portainer PyPI bis 2.42.6, Docker-Hub portainer/portainer-ce nur bis 2.42.0
  (unterschiedliche Versionierungspfade).
- mcp/portainer/README.md ist auf 2.42.6 formuliert und sollte nachgezogen werden.

Bestand: mcp/INVENTORY.md portainer-mcp ⛔→🟢 + Header MCP-WARP-Direktive ergänzt.
.mcp.json (war getrackt aus Commit 3426366) entfernt: opencode nutzt opencode.jsonc,
nicht .mcp.json — Claude-Code-Konvention hier irrelevant.
2026-08-28 21:17:52 +02:00

7.2 KiB

Handoff 2026-08-28 — Portainer 2.40 → 2.42.0 Bump + portainer-mcp (uvx, projektebene)

Vorgeschichte: Direktive vom 2026-08-28 (User): "wenn du künftig das ganze containermanagement machst, brauchst du einen MCP für Portainer". Vorgänger-Direktive vom 2026-08-28 selbst (gestern Session): ⛔ NICHT installieren. → revidiert in derselben Diskussion, weil die wiederholten curl-Aufrufe in der Inventur-Session gezeigt haben, dass ein MCP-Layer hier operativ hilft.

Was diese Session geliefert hat

1. Portainer-Server 2.40.0 → 2.42.0 (auf pve LXC 400, Container portainer)

Vorab-Korrektur (war falsch im Handoff 2026-08-28): README schrieb 2.42.6 als Ziel, PyPI hat ein 2.42.6-Wheel, aber Docker-Hub hat nur 2.42.0 als letzten 2.42.x-Tag für portainer/portainer-ce. Bump-Ziel deshalb 2.42.0 statt 2.42.6.

Ablauf:

  1. Pre-Upgrade-Snapshot:
    • docker commit portainer portainer/portainer-ce:2.40.0-preupgrade-20260828 (186 MB)
    • Settings+Endpoints+Stacks-JSON-Dump (40 KB, 31 Stacks, 4 Endpoints)
    • Volume /var/lib/docker/volumes/portainer_data/_data ist persistent, bleibt beim Image-Swap unangetastet.
    • Runflags aus docker inspect ins Runbook übernommen.
  2. docker pull portainer/portainer-ce:2.42.0
  3. docker stop portainer && docker rm portainer && docker run -d mit identischen Flags.
  4. Post-Upgrade-Verifikation:
    • HTTP 200 auf /, TLS self-signed OK
    • api/status → Version: 2.42.0, gleiche InstanceID wie vorher
    • API-Token weiter gültig (api/settings → 200), kein Re-Auth
    • Alle 4 Endpoints + 31 Stacks abrufbar

Sicherheitsabstände für den Bump:

  • Container läuft, alle Endpoints erreichbar (status=1)
  • Edge-Agents auf den 4 Hosts (DS923, macmini, nas-fm, pve) sind eigene Container, Portainer-Container-Restart berührt sie nicht.

2. portainer-mcp — installiert als projektspezifischer uvx-stdio

Quelle: mcp-portainer von PyPI (offiziell, von Portainer, generiert aus OpenAPI-Spec). Wegen "Match minor to minor"-Policy (PyPI/README) war der Bump Pflicht, sonst kein offizieller MCP.

Installation:

  • uvx --from "mcp-portainer~=2.42.0" mcp-portainer — Wheel lokal aufgelöst, 193 Tools
  • bf-infra/.mcp.json (gitignored):
    {
      "mcpServers": {
        "portainer": {
          "command": "uvx",
          "args": ["--from", "mcp-portainer~=2.42.0", "mcp-portainer"],
          "env": {
            "PORTAINER_URL": "https://10.40.20.126:9443",
            "PORTAINER_API_KEY": "${env:PORTAINER_API_KEY}",
            "PORTAINER_TLS_VERIFY": "0"
          }
        }
      }
    }
    
  • Token via ~/.secrets/exports.zsh (PORTAINER_API_KEY) — kein Klartext im Repo
  • PORTAINER_TLS_VERIFY=0 weil self-signed Cert auf pve-LXC
  • Nur projektebene, kein Eintrag in ~/.claude.json oder ~/.config/opencode/opencode.jsonc
  • .mcp.json aus Repo entfernt (git rm --cached) — mcp/INVENTORY.md zeigt das

Tool-Gate: jeder erste Read in einer Session erfordert get_guidance() (vom Server erzwungen). Erst danach funktionieren EndpointList, StackList, StackInspect etc.

3. Abnahme (drei Calls gegen die echte API)

EndpointList mit select-Projektion:
  [ { "Id":2, "Name":"pve", "Type":1, "Status":1 },
    { "Id":14, "Name":"nas-bf (ds923+)", "Type":2, "Status":1 },
    { "Id":20, "Name":"macmini", "Type":2, "Status":1 },
    { "Id":21, "Name":"nas-fm (ds415+)", "Type":2, "Status":1 } ]

StackList (plattformweit, mit select):
  31 Stacks (pve=4, DS923=20, macmini=4, nas-fm=3)

StackInspect(202) mit select:
  { "id":202, "name":"pve-mcp", "endpointId":14, "status":1,
    "entryPoint":"docker-compose.yml", "projectPath":"/data/compose/202" }

MCP ersetzt jetzt: curl "$PORTAINER_URL/api/..." aus Bash. Vorher 4-5 Aufrufe pro Inventur-/Deploy-Schritt; jetzt ein Tool-Call mit select-JMESPath-Projektion.

4. Bestands-Update (mcp/INVENTORY.md)

  • Zeile portainer-mcp: ⛔ → 🟢, mit Stand 2026-08-28, 193 Tools, Tool-Gate vermerkt
  • Header ergänzt: "MCP-Hosts künftig nur WARP/lokal" (User-Direktive)
  • mcp/portainer/README.md: überholt (steht noch auf "Portainer-Bump zuerst" — jetzt erledigt) → TODO für eigene Session: README auf neuen Stand bringen.

Lehren aus dieser Session

Versions-Korrektur

PyPI ≠ Docker-Hub für dieselbe Software. PyPI mcp-portainer hatte 2.42.0-2.42.6 als Wheels (alle 6 Patch-Versionen), aber das Docker-Image portainer/portainer-ce:2.42.x stoppte bei 2.42.0 — vermutlich weil Portainer die Docker-Patch-Serie anders versioniert. Vor jedem Versions-Claim den jeweils anderen Pfad gegenprüfen.

Werkzeug-Namen lernen

list_endpoints war geraten. Tatsächlich heißt das Tool EndpointList (PascalCase), und es braucht zwingend get_guidance() vor dem ersten Read. Bei unbekanntem MCP zuerst tools/list und ein einzelner Probe-Call, dann den echten Read. Sonst verschwendet man drei Tool-Calls an Authentifizierungsfehler wie ich es hier gemacht habe.

uvx-stdio vs Container-MCP

Für ein einzelnes Projekt mit Performance-Bedenken ist uvx-stdio klar besser als Container:

  • kein zusätzlicher Host (DS923-Belastung entfällt)
  • keine macvlan-IP nötig (kein neuer Port-Range-Konflikt)
  • Tool-Calls direkt aus dem Claude/opencode-Prozess, kein Round-Trip
  • Nachteil: Token im Memory des Claude-Prozesses lebt so lange wie die Session. Bei Container-Lösung wäre der Token nur im MCP-Container. → Sicherheitsbedenken gegen Performance — die Direktive des Users ist hier explizit "Performance > Security weil LAN-only".

git rm --cached für gitignored-Configs

Eine bereits getrackte Datei (hier .mcp.json aus Commit 3426366) wird durch nachträgliches .gitignore-Pattern nicht ausgegraut — git rm --cached ist nötig, sonst bleibt sie im Index. Beim nächsten Commit verschwindet sie sauber.

Commit-Plan (für die nächste Session oder als Quick-Commit)

git add .gitignore mcp/INVENTORY.md docs/portainer-upgrade-20260828/
git commit -m "Portainer 2.40 → 2.42.0 Bump + portainer-mcp (uvx projektebene)

- Portainer-Server: 2.40.0 → 2.42.0 auf pve LXC 400, Pre-Upgrade-Snapshot
  (docker commit :2.40.0-preupgrade-20260828 + JSON-Dump 31 Stacks/4 Endpoints)
- .mcp.json aus Repo (war aus Commit 3426366 getrackt, jetzt gitignored)
- mcp/INVENTORY.md: portainer-mcp ⛔→🟢, Header um MCP-WARP-Direktive ergänzt
- docs/portainer-upgrade-20260828/: Rollback-Runbook + Pre-Upgrade-State.json

Hinweis: PyPI hat mcp-portainer bis 2.42.6, Docker-Hub nur bis 2.42.0 —
README im mcp/portainer/ ist auf 2.42.6 formuliert und sollte angepasst werden.

TODO (offene Punkte, NICHT Teil dieser Session)

  1. mcp/portainer/README.md ist überholt (steht noch auf 2.42.6-Bump, jetzt erledigt). Eigene 5-Minuten-Session, README auf den neuen Stand bringen.
  2. Cleanup nach 7 Tagen Bump-Stabilität: docker rmi portainer/portainer-ce:2.40.0-preupgrade-20260828
  3. Shelly-mcp-Deployment (das war Session B vor dem Portainer-Thema): shelly-mcp-Image ist gebaut, Stack-YML liegt auf DS923, Stack-Deploy steht aus. Sofort zurück zu Session B, weil die .mcp.json jetzt auch das shelly-mcp-Deployment erleichtert (kein wiederholtes curl-Poren).