From ceddb86198af395ce666ef1ff0a5bce80da066ac Mon Sep 17 00:00:00 2001 From: Kantin-Petit Date: Tue, 23 Jun 2026 01:40:49 +0200 Subject: [PATCH] =?UTF-8?q?refactor(infra):=20MCP=20n8n=20natif,=20retrait?= =?UTF-8?q?=20du=20conteneur=20d=C3=A9di=C3=A9=20(v0.15.0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit n8n ≥ 2.18.4 sert son propre MCP : suppression du service mcp-n8n, MCP_N8N_URL pointe vers l'endpoint natif de l'instance (auth MCP Access Token Bearer). Portainer reste un sidecar officiel. Aucun changement de code (registry HTTP+Bearer inchangé). Docs + .env alignés, compose revalidé. Palier de risque : n/a (infra + config). Co-Authored-By: Claude Opus 4.8 --- .env.example | 11 ++++++----- CHANGELOG.md | 9 +++++++++ CLAUDE.md | 5 +++-- docs/architecture.md | 8 ++++---- infra/docker-compose.yml | 20 ++++++-------------- infra/networks.md | 2 +- 6 files changed, 29 insertions(+), 26 deletions(-) diff --git a/.env.example b/.env.example index 2297c96..9dd51f5 100644 --- a/.env.example +++ b/.env.example @@ -9,11 +9,12 @@ OLLAMA_BASE_URL=http://ollama:11434 OLLAMA_API_KEY= # SECRET — clé API Ollama cloud OLLAMA_MODEL=qwen3:cloud # modèle cloud (suffixe :cloud), tool-calling -# ── MCP n8n (czlonkowski/n8n-mcp) ────────────────────────────────────── -N8N_API_URL=http://n8n:5678 # interne uniquement -N8N_API_KEY= # SECRET — token n8n à portée RESTREINTE -MCP_N8N_URL=http://mcp-n8n:3000 # endpoint du serveur MCP n8n (interne) -MCP_N8N_AUTH_TOKEN= # SECRET — auth du serveur MCP n8n +# ── MCP n8n : NATIF (instance n8n ≥ 2.18.4) ──────────────────────────── +# Pas de conteneur dédié : n8n sert son propre MCP. Activer côté instance +# (env d'instance + activation par workflow), puis copier l'URL + le token +# depuis n8n → Connection details. URL = endpoint MCP de l'instance (interne). +MCP_N8N_URL=http://n8n:5678/mcp # à confirmer dans Connection details de n8n +MCP_N8N_AUTH_TOKEN= # SECRET — "MCP Access Token" n8n (Bearer) # ── MCP Portainer (portainer/portainer-mcp) ──────────────────────────── PORTAINER_URL=https://portainer:9443 # interne uniquement diff --git a/CHANGELOG.md b/CHANGELOG.md index b39a9e4..27a9c86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,15 @@ incompatibles. Chaque ligne renvoie à un commit dédié (un artefact = un commi ## [Unreleased] +## [0.15.0] — 2026-06-23 +### Changed +- MCP n8n = **natif** (instance n8n ≥ 2.18.4) au lieu d'un conteneur dédié : + suppression du service `mcp-n8n` du compose ; `MCP_N8N_URL` pointe vers + l'endpoint MCP de l'instance n8n, auth par "MCP Access Token" (Bearer). + MCP Portainer reste un sidecar officiel. Aucun changement de code (le registry + parle déjà HTTP+Bearer). Docs (CLAUDE.md, architecture, networks) + `.env.example` + mis à jour. Compose revalidé (services : ollama, socket-proxy, mcp-portainer, backend). + ## [0.14.0] — 2026-06-23 — fin Phase 2 (écriture + need-review) ### Added - `docs/need-review.md` : documentation complète du cycle (états, sursis, diff --git a/CLAUDE.md b/CLAUDE.md index 2e8d077..5b24f9c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -37,8 +37,9 @@ existant. Le cerveau est un LLM en boucle tool-calling : - Backend/API : **Fastify**. - LLM : client Ollama `/api/chat` (tool-calling natif), modèles `:cloud`. - Surface texte Phase 1 : **bot Telegram** (long-polling → zéro port ouvert). -- MCP : conteneurs `portainer/portainer-mcp` + `czlonkowski/n8n-mcp`, tags - épinglés, **read-only en Phase 1**. +- MCP : **n8n natif** (instance ≥ 2.18.4, pas de conteneur — endpoint MCP servi + par n8n, à activer) + **Portainer sidecar** `portainer/portainer-mcp` (tag + épinglé). **Read-only en Phase 1.** - Tests : **Vitest** (gatekeeper + scoping read-only). - État assets : **SQLite** (table posée dès P0/P1, câblée en P2+). diff --git a/docs/architecture.md b/docs/architecture.md index 9fbd7d2..8e332d1 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -21,8 +21,8 @@ d'un homelab Debian + Docker + Traefik existant. │ - audit log │ └───────────┘ └─────────────────────────┘ │ MCP (stdio/http interne) - ├───────────────► MCP n8n ──► n8n API (interne) - └───────────────► MCP Portainer ─► socket-proxy ─► Docker / Portainer + ├───────────────► MCP n8n natif (endpoint sur l'instance n8n, interne) + └───────────────► MCP Portainer (sidecar) ─► socket-proxy ─► Docker / Portainer ``` ## Invariants @@ -54,6 +54,6 @@ sont exposés : aucun risque d'écriture. |---|---|---|---| | Backend CHLOVA | code maison (TS) | seule surface | — | | Ollama (proxy cloud) | `ollama/ollama` épinglé | interne | — | -| MCP n8n | `czlonkowski/n8n-mcp` épinglé | interne | read-only (P1) | -| MCP Portainer | `portainer/portainer-mcp` épinglé | interne | read-only (P1) | +| MCP n8n | **natif** dans n8n ≥ 2.18.4 (pas de conteneur) | interne | read-only (P1) | +| MCP Portainer | `portainer/portainer-mcp` épinglé (sidecar) | interne | read-only (P1) | | socket-proxy | `tecnativa/docker-socket-proxy` épinglé | interne | scoping Docker | diff --git a/infra/docker-compose.yml b/infra/docker-compose.yml index 2627f76..0101872 100644 --- a/infra/docker-compose.yml +++ b/infra/docker-compose.yml @@ -53,18 +53,11 @@ services: - chlova-internal # AUCUN port publié. - # ── MCP n8n (czlonkowski/n8n-mcp) — read-only en Phase 1 ──────────────── - mcp-n8n: - image: ghcr.io/czlonkowski/n8n-mcp:2.18.3 # TODO confirmer tag + épingler digest - restart: unless-stopped - environment: - MCP_MODE: http # transport HTTP (backend distant via réseau) - MCP_AUTH_TOKEN: ${MCP_N8N_AUTH_TOKEN:?requis} - N8N_API_URL: ${N8N_API_URL} # instance n8n existante (interne) - N8N_API_KEY: ${N8N_API_KEY:?requis} # token n8n à portée RESTREINTE (lecture P1) - networks: - - chlova-internal - # AUCUN port publié. + # ── MCP n8n : NATIF (instance n8n ≥ 2.18.4) — pas de conteneur dédié ───── + # n8n expose son propre serveur MCP. À activer côté instance n8n (variable + # d'env d'instance + activation par workflow), puis copier l'URL + le "MCP + # Access Token" depuis n8n → Connection details. Le backend s'y connecte via + # MCP_N8N_URL (réseau interne). n8n doit être attaché à chlova-internal. # ── MCP Portainer (portainer/portainer-mcp) — read-only en Phase 1 ────── mcp-portainer: @@ -93,13 +86,12 @@ services: CHLOVA_ENV: ${CHLOVA_ENV:-production} CHLOVA_PHASE: ${CHLOVA_PHASE:-1} # 1 = lecture seule (défaut) ; 2 = écriture sous review OLLAMA_BASE_URL: ${OLLAMA_BASE_URL:-http://ollama:11434} - MCP_N8N_URL: ${MCP_N8N_URL:-http://mcp-n8n:3000} + MCP_N8N_URL: ${MCP_N8N_URL} # endpoint MCP natif de n8n MCP_PORTAINER_URL: ${MCP_PORTAINER_URL:-http://mcp-portainer:3000} volumes: - chlova-data:/app/data # SQLite (table assets, P2+) depends_on: - ollama - - mcp-n8n - mcp-portainer networks: - chlova-internal diff --git a/infra/networks.md b/infra/networks.md index 61bf376..a5c52b5 100644 --- a/infra/networks.md +++ b/infra/networks.md @@ -7,7 +7,7 @@ | Réseau | Type | Membres | But | |---|---|---|---| -| `chlova-internal` | `internal: true` | backend, ollama, mcp-n8n, mcp-portainer, socket-proxy, (n8n, portainer existants) | bus interne ; **aucun accès externe** | +| `chlova-internal` | `internal: true` | backend, ollama, mcp-portainer, socket-proxy, (n8n + Portainer existants, à attacher) | bus interne ; **aucun accès externe** | | `chlova-egress` | bridge | ollama uniquement | sortie contrôlée vers `ollama.com` | - `chlova-internal` est déclaré `internal: true` : **pas de route vers l'extérieur**.