fix(mcp): intégration réelle passerelle MCP Portainer (image+auth) (v0.34.0)

Image portainer-mcp 0.6.0 (inexistant) -> 2.42.6. Passerelle HTTP :17717/mcp
attend Bearer (secret passerelle) + X-Portainer-API-Key (clé API restreinte
chlova) : ajout config.portainerApiKey + McpServerConfig.extraHeaders, backend
envoie les deux. socket-proxy supprimé (plus de socket monté). Compose prod,
.env.example, deploy.md à jour. Typecheck + 78 tests verts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016w5jRe87MGdd6AMvXQcHNi
This commit is contained in:
Kantin-Petit
2026-06-23 13:50:09 +02:00
parent 4e23828dae
commit 2d3c944699
8 changed files with 74 additions and 51 deletions
+14 -37
View File
@@ -32,44 +32,20 @@ services:
- chlova-egress
# AUCUN port publié : Ollama n'a pas d'auth native, jamais exposé.
# ── socket-proxy : accès Docker filtré, LECTURE SEULE (Phase 1) ────────
socket-proxy:
image: tecnativa/docker-socket-proxy:0.3.0
restart: unless-stopped
environment:
CONTAINERS: 1
IMAGES: 1
NETWORKS: 1
VOLUMES: 1
SERVICES: 1
TASKS: 1
NODES: 1
INFO: 1
VERSION: 1
POST: 0
EXEC: 0
AUTH: 0
SECRETS: 0
CONFIGS: 0
BUILD: 0
COMMIT: 0
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- chlova-internal
# AUCUN port publié.
# ── MCP Portainer (portainer/portainer-mcp) — read-only en Phase 1 ──────
# ── MCP Portainer (passerelle HTTP portainer/portainer-mcp) — read-only P1
# Parle à l'API Portainer (pas au socket Docker). Le backend s'y connecte en
# HTTP sur :17717/mcp avec le secret de passerelle (Bearer) + la clé API
# restreinte de chlova (X-Portainer-API-Key).
mcp-portainer:
image: portainer/portainer-mcp:0.6.0
image: portainer/portainer-mcp:2.42.6
restart: unless-stopped
environment:
PORTAINER_URL: ${PORTAINER_URL:-http://portainer:9000} # interne : Portainer sur le même hôte (local), réseau proxy
PORTAINER_MCP_AUTH_TOKEN: ${PORTAINER_MCP_AUTH_TOKEN:?requis} # token user chlova restreint
PORTAINER_READ_ONLY: ${PORTAINER_READ_ONLY:-true} # P1 : NE PAS passer à false
DOCKER_HOST: tcp://socket-proxy:2375
depends_on:
- socket-proxy
PORTAINER_MCP_AUTH_TOKEN: ${PORTAINER_MCP_AUTH_TOKEN:?requis} # secret de passerelle (partagé avec le backend)
PORTAINER_MCP_ALLOWED_HOSTS: mcp-portainer:17717 # hôte par lequel le backend appelle
PORTAINER_MCP_DANGEROUSLY_ALLOW_PLAINTEXT_HTTP: "1" # HTTP interne (réseau Docker privé)
PORTAINER_TLS_VERIFY: "0" # Portainer interne en HTTP : pas de TLS
PORTAINER_READ_ONLY: ${PORTAINER_READ_ONLY:-true} # P1 : GET/HEAD seulement (défense en profondeur)
networks:
- chlova-internal # joignable par le backend
- proxy # joint le serveur Portainer (http://portainer:9000)
@@ -95,9 +71,10 @@ services:
# — MCP n8n (natif, interne via réseau proxy) —
MCP_N8N_URL: ${MCP_N8N_URL:-http://n8n-chlova:5678/mcp-server/http}
MCP_N8N_AUTH_TOKEN: ${MCP_N8N_AUTH_TOKEN:?requis}
# — MCP Portainer (sidecar) —
MCP_PORTAINER_URL: ${MCP_PORTAINER_URL:-http://mcp-portainer:3000}
PORTAINER_MCP_AUTH_TOKEN: ${PORTAINER_MCP_AUTH_TOKEN:?requis}
# — MCP Portainer (passerelle) —
MCP_PORTAINER_URL: ${MCP_PORTAINER_URL:-http://mcp-portainer:17717/mcp}
PORTAINER_MCP_AUTH_TOKEN: ${PORTAINER_MCP_AUTH_TOKEN:?requis} # secret de passerelle (= côté sidecar)
PORTAINER_API_KEY: ${PORTAINER_API_KEY:?requis} # clé API Portainer restreinte de chlova
PORTAINER_READ_ONLY: ${PORTAINER_READ_ONLY:-true}
# — Alertes (Phase 3) : vide = log-only —
ALERT_WEBHOOK_URL: ${ALERT_WEBHOOK_URL:-}