Files
crowdlending-app/mcp-server/README.md
T
2026-07-15 23:08:36 +02:00

231 lines
10 KiB
Markdown

# 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": {
"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).
## 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_..." }
}
}
}
```
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 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
`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).