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.
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:
- 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/_dataist persistent, bleibt beim Image-Swap unangetastet. - Runflags aus
docker inspectins Runbook übernommen.
docker pull portainer/portainer-ce:2.42.0docker stop portainer && docker rm portainer && docker run -dmit identischen Flags.- 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
- HTTP 200 auf
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 Toolsbf-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=0weil self-signed Cert auf pve-LXC- Nur projektebene, kein Eintrag in
~/.claude.jsonoder~/.config/opencode/opencode.jsonc .mcp.jsonaus Repo entfernt (git rm --cached) —mcp/INVENTORY.mdzeigt 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)
mcp/portainer/README.mdist überholt (steht noch auf 2.42.6-Bump, jetzt erledigt). Eigene 5-Minuten-Session, README auf den neuen Stand bringen.- Cleanup nach 7 Tagen Bump-Stabilität:
docker rmi portainer/portainer-ce:2.40.0-preupgrade-20260828 - 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.jsonjetzt auch das shelly-mcp-Deployment erleichtert (kein wiederholtes curl-Poren).