# 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 { "mcpServers": { "crowdlending-dev": { "url": "http://localhost:4100/mcp", "headers": { "X-API-Key": "clk_live_..." } } } } ``` 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 (le bloc `headers` de la config Claude Desktop 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": { "url": "http://localhost:4100/mcp", "headers": { "X-API-Key": "clk_live_..." } }, "crowdlending-prod": { "url": "https://mcp.crowdlending.croguennec.net/mcp", "headers": { "X-API-Key": "clk_live_..." } } } } ``` 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é | | `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 la section `headers` de votre config Claude Desktop. - **`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).