From 6e58731a2061dfcf0b04b3863d71bc246fe48918 Mon Sep 17 00:00:00 2001 From: Olivier Date: Wed, 15 Jul 2026 23:08:36 +0200 Subject: [PATCH] Fix --- docker-compose.yml | 1 + frontend/src/pages/MonCompte.jsx | 106 ++++++++++++++++++------------- mcp-server/README.md | 50 +++++++++++---- 3 files changed, 101 insertions(+), 56 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index c062f69..83ccc3a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -67,6 +67,7 @@ services: PORT: 4100 CROWDLENDING_API_URL: http://crowdlending-backend:4000/api/v1 MCP_ALLOWED_HOSTS: mcp.crowdlending.croguennec.net,localhost + MCP_LABEL: prod # Explicitement désactivé : ce serveur sert des utilisateurs distants # non maîtrisés, l'outil de lecture d'URL arbitraire (SSRF) reste # réservé au développement local. Ne pas passer à true ici. diff --git a/frontend/src/pages/MonCompte.jsx b/frontend/src/pages/MonCompte.jsx index ceb970f..0a386b0 100644 --- a/frontend/src/pages/MonCompte.jsx +++ b/frontend/src/pages/MonCompte.jsx @@ -1091,27 +1091,30 @@ function ApiKeysSection() { } /* ── Serveur MCP ────────────────────────────────────────────── - Guide pas-à-pas pour connecter Claude Desktop au serveur MCP local - (mcp-server/ à la racine du projet). Le JSON de config est généré - côté client à partir des champs ci-dessous ; la clé API saisie ici - reste uniquement en mémoire du navigateur, elle n'est jamais envoyée - au backend — seulement utilisée pour composer l'aperçu à copier. ── */ + Guide pas-à-pas pour connecter Claude Desktop au serveur MCP + (mcp-server/ à la racine du projet, un seul modèle url+headers en HTTP, + que ce soit en développement local ou déployé à distance en prod — voir + mcp-server/README.md). Le JSON de config est généré côté client à partir + des champs ci-dessous ; la clé API saisie ici reste uniquement en mémoire + du navigateur, elle n'est jamais envoyée au backend — seulement utilisée + pour composer l'aperçu à copier. ── */ -/** Devine une URL d'API raisonnable selon l'environnement courant : - * en dev (Vite sur :5173), le process Node du serveur MCP ne passe pas - * par le proxy Vite, il faut donc viser directement le port du backend (4000). - * En prod (nginx sert front + /api sur la même origine), l'origine courante convient. */ -function guessMcpApiUrl() { - if (typeof window === 'undefined') return 'http://localhost:4000/api/v1'; - const { hostname, port, origin } = window.location; - if (port === '5173') return `http://${hostname}:4000/api/v1`; - return `${origin}/api/v1`; +/** Devine une URL de serveur MCP raisonnable selon l'environnement courant : + * en dev (Vite sur :5173 ou localhost), le serveur MCP tourne en local sur + * son port par défaut (npm run dev, :4100). En prod, il s'agit du + * sous-domaine dédié mcp., déjà déployé en continu. */ +function guessMcpUrl() { + if (typeof window === 'undefined') return 'http://localhost:4100/mcp'; + const { hostname, port } = window.location; + if (port === '5173' || hostname === 'localhost' || hostname === '127.0.0.1') { + return 'http://localhost:4100/mcp'; + } + return `https://mcp.${hostname}/mcp`; } /** Détecte automatiquement l'environnement ('dev' ou 'prod') à partir de - * l'URL de l'API : localhost/IP locale ou nom d'hôte contenant "dev" → - * dev, tout le reste → prod. Best-effort — reste modifiable manuellement - * pour les cas particuliers (domaine de test qui ne contient pas "dev"...). */ + * l'URL du serveur MCP : localhost/IP locale → dev, tout le reste → prod. + * Best-effort — reste modifiable manuellement pour les cas particuliers. */ function detectLabelFromUrl(url) { if (!url) return 'prod'; let hostname; @@ -1146,27 +1149,28 @@ function CopyBlock({ text }) { } function McpServerSection({ goToApiKeys }) { - const [mcpPath, setMcpPath] = useState('C:\\dev\\crowdlending-app\\mcp-server\\index.js'); - const [apiUrl, setApiUrl] = useState(guessMcpApiUrl()); + const [mcpUrl, setMcpUrl] = useState(guessMcpUrl()); const [apiKey, setApiKey] = useState(''); - const [manualLabel, setManualLabel] = useState(null); // null = auto-détecté depuis apiUrl, sinon override manuel + const [manualLabel, setManualLabel] = useState(null); // null = auto-détecté depuis mcpUrl, sinon override manuel - const detectedLabel = detectLabelFromUrl(apiUrl); + const detectedLabel = detectLabelFromUrl(mcpUrl); const label = manualLabel ?? detectedLabel; + const isLocal = label === 'dev'; const serverKey = `crowdlending-${label}`; - const env = { - CROWDLENDING_API_KEY: apiKey || '', - CROWDLENDING_API_URL: apiUrl, - CROWDLENDING_LABEL: label, - }; + // claude_desktop_config.json n'a pas de champ url/headers natif : on passe + // par mcp-remote (https://github.com/geelen/mcp-remote), un pont stdio↔HTTP + // que Claude Desktop lance comme n'importe quel serveur "command". La clé + // API passe en variable d'environnement plutôt que directement dans args + // (bug connu de Claude Desktop Windows qui tronque les valeurs à espaces). + const envVarName = `${label.toUpperCase()}_API_KEY`; const configJson = JSON.stringify({ mcpServers: { [serverKey]: { - command: 'node', - args: [mcpPath], - env, + command: 'npx', + args: ['-y', 'mcp-remote', mcpUrl, '--header', `X-API-Key:\${${envVarName}}`], + env: { [envVarName]: apiKey || '' }, }, }, }, null, 2); @@ -1176,8 +1180,8 @@ function McpServerSection({ goToApiKeys }) {

Serveur MCP

Permet à Claude Desktop (ou tout client MCP) de consulter votre portefeuille en lecture seule. - Le serveur (dossier mcp-server/ du projet) doit être installé sur cette machine - (npm install) — voir mcp-server/README.md pour le détail. + Un seul modèle de connexion, en développement local comme en production : une URL de serveur MCP + et votre clé API personnelle — voir mcp-server/README.md pour le détail.

1. Créer une clé API dédiée

@@ -1194,12 +1198,8 @@ function McpServerSection({ goToApiKeys }) {

2. Renseigner les paramètres

- - setMcpPath(e.target.value)} /> -
-
- - setApiUrl(e.target.value)} /> + + setMcpUrl(e.target.value)} />
@@ -1218,7 +1218,7 @@ function McpServerSection({ goToApiKeys }) { {manualLabel === null - ? <>déduit de l'URL de l'API ci-dessus (localhost / « dev » → dev, sinon prod) + ? <>déduit de l'URL ci-dessus (localhost → dev, sinon prod) : <>forcé manuellement}
@@ -1236,12 +1236,26 @@ function McpServerSection({ goToApiKeys }) { )}
-

+ + {isLocal ? ( +

+ En développement, ce serveur doit tourner sur votre machine pour que l'URL ci-dessus réponde : + + cd mcp-server && npm install && npm run dev + + comme pour le backend et le frontend. Laissez ce terminal ouvert tant que vous utilisez Claude Desktop. +

+ ) : ( +

+ En production, le serveur tourne déjà en continu (service crowdlending-mcp) — aucune + action nécessaire au-delà de renseigner l'URL et votre clé API. +

+ )} +

Claude Desktop peut se connecter à plusieurs serveurs MCP en même temps : pour avoir dev et - prod accessibles simultanément, répétez ces étapes une deuxième fois avec une URL d'API pointant - vers l'autre environnement (et une clé API distincte) — l'étiquette et la clé de config - ({serverKey} ci-dessous) s'ajustent automatiquement. Elle apparaît dans le titre et - la description de chaque outil, pour que l'agent ne confonde jamais les deux portefeuilles. + prod accessibles simultanément, répétez ces étapes une deuxième fois avec l'autre URL (et une clé + API distincte) — la clé de config ({serverKey} ci-dessous) s'ajuste automatiquement, + Claude Desktop ne confondra jamais les deux portefeuilles.

3. Copier la configuration

@@ -1268,8 +1282,10 @@ function McpServerSection({ goToApiKeys }) {

5. Vérifier

- Dans la liste des outils MCP de Claude Desktop, les 7 outils crowdlending_* doivent - apparaître. Testez avec une question du type « Quel est mon encours de crowdlending actuellement ? ». + Dans la liste des outils MCP de Claude Desktop, les outils crowdlending_* doivent + apparaître (6 en production, 7 en développement local si crowdlending_fetch_url est + activé — voir mcp-server/README.md). Testez avec une question du type « Quel est mon + encours de crowdlending actuellement ? ».

); diff --git a/mcp-server/README.md b/mcp-server/README.md index ae32460..dcf697e 100644 --- a/mcp-server/README.md +++ b/mcp-server/README.md @@ -44,15 +44,37 @@ locaux → **Modifier la config**, puis ajoutez dans `mcpServers` : { "mcpServers": { "crowdlending-dev": { - "url": "http://localhost:4100/mcp", - "headers": { - "X-API-Key": "clk_live_..." + "command": "npx", + "args": [ + "-y", + "mcp-remote", + "http://localhost:4100/mcp", + "--header", + "X-API-Key:${CROWDLENDING_API_KEY}" + ], + "env": { + "CROWDLENDING_API_KEY": "clk_live_..." } } } } ``` +**Important :** `claude_desktop_config.json` n'accepte que des entrées +`command`/`args` — il n'existe pas de champ `url`/`headers` natif dans ce +fichier (contrairement à d'autres clients MCP). Pour un serveur HTTP comme +celui-ci, on passe donc par +[`mcp-remote`](https://github.com/geelen/mcp-remote), un petit pont +stdio↔HTTP officiel : Claude Desktop lance `npx mcp-remote` comme d'habitude, +qui se charge de parler HTTP à notre serveur en coulisses, en-tête +`X-API-Key` inclus. Aucune installation manuelle requise, `npx` le télécharge +à la volée. + +Notez l'absence d'espace autour du `:` dans `--header` : Claude Desktop +(Windows) a un bug connu qui tronque les arguments contenant un espace — on +passe donc la valeur réelle (avec l'espace éventuel) via une variable +d'environnement dans `env` plutôt que directement dans `args`. + Redémarrez Claude Desktop. Les outils `crowdlending_*` doivent apparaître (voir la liste plus bas — `crowdlending_fetch_url` en plus si activé, voir Configuration). @@ -72,8 +94,8 @@ distant réel (en local, les valeurs par défaut conviennent) : Aucune clé API fixe n'est configurée côté serveur, contrairement à une ancienne version qui utilisait le transport stdio : chaque session MCP lit -sa propre clé dans l'en-tête `X-API-Key` de la requête qui l'initialise (le -bloc `headers` de la config Claude Desktop ci-dessus). Un même process peut +sa propre clé dans l'en-tête `X-API-Key` de la requête qui l'initialise +(transmis via `mcp-remote --header`, voir ci-dessus). Un même process peut donc servir plusieurs utilisateurs/sessions en parallèle sans jamais mélanger leurs données — voir le déploiement distant plus bas. @@ -88,12 +110,14 @@ possible, même si les noms d'outils sont identiques des deux côtés. { "mcpServers": { "crowdlending-dev": { - "url": "http://localhost:4100/mcp", - "headers": { "X-API-Key": "clk_live_..." } + "command": "npx", + "args": ["-y", "mcp-remote", "http://localhost:4100/mcp", "--header", "X-API-Key:${DEV_API_KEY}"], + "env": { "DEV_API_KEY": "clk_live_..." } }, "crowdlending-prod": { - "url": "https://mcp.crowdlending.croguennec.net/mcp", - "headers": { "X-API-Key": "clk_live_..." } + "command": "npx", + "args": ["-y", "mcp-remote", "https://mcp.crowdlending.croguennec.net/mcp", "--header", "X-API-Key:${PROD_API_KEY}"], + "env": { "PROD_API_KEY": "clk_live_..." } } } } @@ -186,8 +210,12 @@ Garde-fous : ## Dépannage -- **`En-tête X-API-Key manquant`** — vérifiez la section `headers` de votre - config Claude Desktop. +- **`En-tête X-API-Key manquant`** — vérifiez l'argument `--header` et la + variable d'environnement correspondante dans votre config Claude Desktop. +- **« Certains serveurs MCP n'ont pas pu être chargés » / entrée ignorée** — + votre config utilise un bloc `url`/`headers` directement, non supporté par + `claude_desktop_config.json` (voir Développement local plus haut) : il faut + passer par `command: "npx"` + `mcp-remote`. - **`Clé API invalide ou révoquée`** — régénérez une clé dans Mon compte → Clés API et mettez à jour la config. - **`Impossible de joindre l'API`** — le backend n'est pas démarré, ou