This commit is contained in:
2026-07-15 23:08:36 +02:00
parent 56dd1f89bd
commit 6e58731a20
3 changed files with 101 additions and 56 deletions
+1
View File
@@ -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.
+61 -45
View File
@@ -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.<domaine de l'app>, 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 || '<VOTRE_CLE_API>',
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 || '<VOTRE_CLE_API>' },
},
},
}, null, 2);
@@ -1176,8 +1180,8 @@ function McpServerSection({ goToApiKeys }) {
<h3 style={{ margin: '0 0 4px' }}>Serveur MCP</h3>
<p className="text-muted" style={{ margin: '0 0 20px', fontSize: 'var(--fs-sm)' }}>
Permet à Claude Desktop (ou tout client MCP) de consulter votre portefeuille en lecture seule.
Le serveur (dossier <code>mcp-server/</code> du projet) doit être installé sur cette machine
(<code>npm install</code>) voir <code>mcp-server/README.md</code> 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 <code>mcp-server/README.md</code> pour le détail.
</p>
<h4 style={{ margin: '0 0 6px', fontSize: 'var(--fs-sm)' }}>1. Créer une clé API dédiée</h4>
@@ -1194,12 +1198,8 @@ function McpServerSection({ goToApiKeys }) {
<h4 style={{ margin: '0 0 10px', fontSize: 'var(--fs-sm)' }}>2. Renseigner les paramètres</h4>
<div style={{ display: 'flex', flexDirection: 'column', gap: 12, marginBottom: 20, maxWidth: 520 }}>
<div>
<label>Chemin vers mcp-server/index.js</label>
<input value={mcpPath} onChange={e => setMcpPath(e.target.value)} />
</div>
<div>
<label>URL de l'API</label>
<input value={apiUrl} onChange={e => setApiUrl(e.target.value)} />
<label>URL du serveur MCP</label>
<input value={mcpUrl} onChange={e => setMcpUrl(e.target.value)} />
</div>
<div>
<label>Clé API</label>
@@ -1218,7 +1218,7 @@ function McpServerSection({ goToApiKeys }) {
</span>
<span style={{ fontSize: 'var(--fs-sm)', color: 'var(--text-muted)' }}>
{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</>}
</span>
</div>
@@ -1236,12 +1236,26 @@ function McpServerSection({ goToApiKeys }) {
)}
</div>
</div>
<p style={{ margin: '-8px 0 20px', fontSize: 'var(--fs-sm)', color: 'var(--text-muted)' }}>
{isLocal ? (
<p style={{ margin: '-8px 0 20px', fontSize: 'var(--fs-sm)', color: 'var(--text-muted)' }}>
En développement, ce serveur doit tourner sur votre machine pour que l'URL ci-dessus réponde :
<code style={{ display: 'block', margin: '6px 0', padding: '6px 8px', borderRadius: 6, background: 'var(--surface-2, #f9fafb)' }}>
cd mcp-server &amp;&amp; npm install &amp;&amp; npm run dev
</code>
comme pour le backend et le frontend. Laissez ce terminal ouvert tant que vous utilisez Claude Desktop.
</p>
) : (
<p style={{ margin: '-8px 0 20px', fontSize: 'var(--fs-sm)', color: 'var(--text-muted)' }}>
En production, le serveur tourne déjà en continu (service <code>crowdlending-mcp</code>) aucune
action nécessaire au-delà de renseigner l'URL et votre clé API.
</p>
)}
<p style={{ margin: '0 0 20px', fontSize: 'var(--fs-sm)', color: 'var(--text-muted)' }}>
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
(<code>{serverKey}</code> 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 (<code>{serverKey}</code> ci-dessous) s'ajuste automatiquement,
Claude Desktop ne confondra jamais les deux portefeuilles.
</p>
<h4 style={{ margin: '0 0 6px', fontSize: 'var(--fs-sm)' }}>3. Copier la configuration</h4>
@@ -1268,8 +1282,10 @@ function McpServerSection({ goToApiKeys }) {
<h4 style={{ margin: '0 0 6px', fontSize: 'var(--fs-sm)' }}>5. Vérifier</h4>
<p style={{ margin: 0, fontSize: 'var(--fs-sm)', color: 'var(--text-muted)' }}>
Dans la liste des outils MCP de Claude Desktop, les 7 outils <code>crowdlending_*</code> 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 <code>crowdlending_*</code> doivent
apparaître (6 en production, 7 en développement local si <code>crowdlending_fetch_url</code> est
activé — voir <code>mcp-server/README.md</code>). Testez avec une question du type « Quel est mon
encours de crowdlending actuellement ? ».
</p>
</div>
);
+39 -11
View File
@@ -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