# crowdlending-mcp-server Serveur MCP (HTTP, Streamable HTTP transport) pour le portefeuille de crowdlending. Il expose en lecture seule les données d'un investisseur (investissements, remboursements, dépôts/retraits, dashboard) à un client MCP — Claude Desktop, Claude Code, ou tout autre client compatible — en s'appuyant sur l'API publique `/api/v1` du backend. Il ne fait aucune écriture : toutes les modifications restent à faire dans l'app web. **Un seul serveur, un seul fichier (`server.js`)**, utilisé aussi bien en développement local (`npm run dev`, comme le backend et le frontend) qu'en production (service Docker `crowdlending-mcp`, derrière Traefik sur `mcp.crowdlending.croguennec.net`). Pas de distinction de code entre les deux — seule la configuration change (quelle API cibler, quels outils activer). ## Prérequis - Node.js ≥ 18 (fetch natif requis) - Une clé API générée dans l'app : **Mon compte → Clés API → Nouvelle clé** - Le backend accessible (en local `http://localhost:4000`, ou l'URL de votre instance en production) ## Développement local Comme pour `backend/` et `frontend/` : ``` cd mcp-server npm install npm run dev ``` `npm run dev` (comme `backend`) relance automatiquement le serveur à chaque modification de fichier (`node --watch`). Par défaut, il écoute sur `http://localhost:4100` et cible l'API locale (`http://localhost:4000/api/v1`). Connectez ensuite Claude Desktop : Réglages → Développeur → Serveurs MCP locaux → **Modifier la config**, puis ajoutez dans `mcpServers` : ```json // macOS / Linux { "mcpServers": { "crowdlending-dev": { "command": "npx", "args": [ "-y", "mcp-remote", "http://localhost:4100/mcp", "--header", "X-API-Key:${CROWDLENDING_API_KEY}" ], "env": { "CROWDLENDING_API_KEY": "clk_live_..." } } } } ``` ```json // Windows { "mcpServers": { "crowdlending-dev": { "command": "cmd", "args": [ "/c", "npx", "-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. **Sous Windows, le wrapper `cmd /c` est obligatoire** (voir le second bloc ci-dessus) : `npx` y est en réalité `npx.cmd` (un script), et la façon dont Claude Desktop lance les process (`spawn` sans interpréteur de commandes) ne sait pas l'exécuter directement — sans ce wrapper, le serveur reste affiché comme « running » dans Claude Desktop mais ne répond jamais (blocage silencieux, pas d'erreur explicite). C'est un problème Node.js/Windows connu, pas spécifique à ce serveur — la config générée automatiquement dans Mon compte → Serveur MCP l'applique déjà si elle détecte Windows. Notez aussi 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). ## Configuration Variables d'environnement, toutes optionnelles sauf pour un déploiement distant réel (en local, les valeurs par défaut conviennent) : | Variable | Défaut | Description | |---|---|---| | `PORT` | `4100` | Port d'écoute HTTP | | `CROWDLENDING_API_URL` | `http://localhost:4000/api/v1` | API v1 ciblée | | `MCP_LABEL` | — | Étiquette d'environnement (`dev`, `prod`...) — voir plus bas | | `MCP_ENABLE_FETCH_URL` | `false` | Active l'outil `crowdlending_fetch_url` (voir plus bas) | | `MCP_ALLOWED_HOSTS` | `mcp.crowdlending.croguennec.net,localhost` | En-têtes `Host` acceptés (protection anti DNS-rebinding) | 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 (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. ## Faire tourner dev et prod en même temps Claude Desktop peut se connecter à plusieurs serveurs MCP simultanément : il suffit de déclarer deux entrées dans `mcpServers`, une par URL. Chaque outil est automatiquement rattaché à son serveur d'origine — pas de collision possible, même si les noms d'outils sont identiques des deux côtés. ```json { "mcpServers": { "crowdlending-dev": { "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": { "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_..." } } } } ``` Sous Windows, remplacez `"command": "npx"` par `"command": "cmd", "args": ["/c", "npx", ...]` sur chacune des deux entrées (voir Développement local plus haut). Utilisez deux clés API différentes (une par instance) : ça permet de révoquer l'une sans affecter l'autre. Réglez `MCP_LABEL=dev` (côté serveur local, dans votre `.env` ou variable d'environnement au lancement) pour que le titre de chaque outil affiche `[DEV]` et lève toute ambiguïté — le serveur distant est déjà configuré avec `MCP_LABEL` correspondant en production. ## Déploiement en production (Docker) Le service `crowdlending-mcp` du `docker-compose.yml` à la racine construit et lance ce même `server.js`, exposé via Traefik sur `mcp.crowdlending.croguennec.net` (certificat TLS automatique). Contrairement au reste de l'app, ce service n'a **pas** le middleware `ipwhitelist-all` : il est volontairement accessible depuis internet, pour des utilisateurs distants qui ne peuvent pas faire tourner le serveur en local — la clé API est donc la seule barrière d'accès. Traitez-la comme un mot de passe, et révoquez-la immédiatement en cas de doute (Mon compte → Clés API). Un enregistrement DNS pour ce sous-domaine, pointant vers la même IP que `crowdlending.croguennec.net`, est nécessaire avant le premier déploiement. `MCP_ENABLE_FETCH_URL` reste à `false` en production (voir docker-compose.yml) : cet outil lit une URL arbitraire fournie par l'appelant, acceptable pour un usage perso où vous seul détenez la clé, mais risqué (SSRF) face à des utilisateurs distants non maîtrisés. Autres protections : limite de 60 requêtes/minute par IP (au-delà, `429`), et fermeture automatique des sessions inactives depuis plus de 30 minutes (mémoire uniquement, aucune persistance). ## Tester sans Claude Desktop Le [MCP Inspector](https://github.com/modelcontextprotocol/inspector) permet de lister et appeler les outils depuis une interface web : ``` npm run inspect ``` Dans l'interface, choisissez le transport **Streamable HTTP**, entrez l'URL (`http://localhost:4100/mcp` en dev) et ajoutez l'en-tête `X-API-Key` avec votre clé. ## Outils exposés Tous en lecture seule (`readOnlyHint: true`) : | Outil | Description | |---|---| | `crowdlending_get_investisseur` | Profil de l'investisseur lié à la clé (liste des membres si clé « Famille et entreprises ») | | `crowdlending_get_dashboard` | Synthèse KPI : capital investi, capital en risque, intérêts perçus (filtrable par année), cash | | `crowdlending_list_investissements` | Liste des investissements, filtrable par statut | | `crowdlending_get_investissement` | Détail d'un investissement + ses remboursements | | `crowdlending_list_remboursements` | Historique des remboursements, filtrable par période | | `crowdlending_list_depots_retraits` | Historique des mouvements de cash | | `crowdlending_fetch_url` | *(actif seulement si `MCP_ENABLE_FETCH_URL=true`)* Lit une page web (annonce de projet) et en extrait le texte propre — voir ci-dessous | ## Lire une annonce de projet (`crowdlending_fetch_url`) Désactivé par défaut — à activer avec `MCP_ENABLE_FETCH_URL=true`, typiquement en développement local uniquement (voir Configuration et Sécurité plus haut). Cet outil récupère une page web et en extrait le contenu lisible (titre + texte principal) via [Readability](https://github.com/mozilla/readability), la librairie du mode lecture de Firefox — menus, pubs, scripts et bandeaux cookies sont éliminés automatiquement. Il ne fait **aucune extraction métier** côté serveur (pas de tentative de deviner taux/montant/durée par regex) : c'est l'agent qui lit le texte retourné et en extrait les informations pertinentes dans la conversation, pour vous les proposer avant toute saisie. Cohérent avec le reste du serveur : lecture seule, aucune création automatique d'investissement (l'API v1 n'a pas de capacité d'écriture). Exemple d'usage : *« Regarde cette page et propose-moi les infos pour créer l'investissement : https://plateforme.fr/projets/xxx »*. Garde-fous : - http/https uniquement, pages HTML uniquement. - Hôtes locaux/privés bloqués (`localhost`, `127.0.0.1`, plages `10.x`/`172.16-31.x`/`192.168.x`...) — l'outil ne peut pas cibler votre réseau local, y compris votre propre backend. - Texte tronqué à 8000 caractères sur les pages très longues (le champ `truncated` de la réponse l'indique). ## Dépannage - **`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`. - **Le serveur reste sur « running » indéfiniment, « Preparing session… » puis « Could not attach »** — sous Windows, il manque le wrapper `cmd /c` (voir Développement local). C'est un problème de fond très courant : `npx` y est un script `.cmd` que `spawn()` ne sait pas exécuter directement, donc le process est lancé mais ne communique jamais réellement. Symptôme caractéristique : aucune erreur explicite, juste un blocage silencieux. - **`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 `CROWDLENDING_API_URL` pointe au mauvais endroit (vérifiez le port et le suffixe `/api/v1`). - **`Invalid Host` (403)** — l'en-tête `Host` de la requête ne correspond à aucune valeur de `MCP_ALLOWED_HOSTS`. En local, vérifiez que vous appelez bien `localhost:4100` (pas `127.0.0.1:4100`, absent de la liste par défaut — ajoutez-le à `MCP_ALLOWED_HOSTS` si besoin). - **Session `404` après une longue pause** — la session a expiré après 30 minutes d'inactivité, votre client MCP doit s'y reconnecter (généralement automatique).