MAj MCP Serveur

This commit is contained in:
2026-07-20 17:30:08 +02:00
parent 6e58731a20
commit 9eb19efd92
4 changed files with 268 additions and 19 deletions
+24 -7
View File
@@ -17,10 +17,11 @@
* des outils de CETTE session uniquement (voir createSession). Deux sessions
* ne partagent jamais d'état ni de données.
*
* Connexion depuis Claude Desktop (dev comme prod) :
* { "url": "http://localhost:4100/mcp", "headers": { "X-API-Key": "..." } }
* (remplacer l'URL par https://mcp.crowdlending.croguennec.net/mcp pour la
* prod). Voir README.md pour le détail.
* Connexion depuis Claude Desktop (dev comme prod) : ce fichier expose du
* HTTP pur, mais claude_desktop_config.json n'accepte que des entrées
* command/args — la connexion passe donc par le pont mcp-remote
* (https://github.com/geelen/mcp-remote), voir README.md pour la config
* exacte (et le wrapper cmd /c obligatoire sous Windows).
*/
import { randomUUID } from 'node:crypto';
@@ -63,6 +64,17 @@ const SESSION_IDLE_TIMEOUT_MS = 30 * 60 * 1000; // 30 min
console.error(`[crowdlending-mcp${LABEL ? `-${LABEL}` : ''}] démarrage — API cible : ${API_BASE}, hôtes autorisés : ${ALLOWED_HOSTS.join(', ')}, fetch_url : ${ENABLE_FETCH_URL ? 'activé' : 'désactivé'}`);
/** Préfixe commun à toutes les lignes de log applicatif. */
const LOG_PREFIX = `[crowdlending-mcp${LABEL ? `-${LABEL}` : ''}]`;
/** Résumé lisible d'une requête JSON-RPC entrante (nom d'outil pour un
* tools/call, méthode sinon), pour le log applicatif — jamais la clé API. */
function describeRequest(body) {
if (!body || typeof body !== 'object') return 'requête inconnue';
if (body.method === 'tools/call') return `tools/call ${body.params?.name || '?'}`;
return body.method || 'requête inconnue';
}
/** Ajoute le libellé d'environnement au titre d'un outil (ex. "[PROD]"). */
const withLabel = (title) => LABEL ? `${title} [${LABEL.toUpperCase()}]` : title;
@@ -118,7 +130,7 @@ setInterval(() => {
const now = Date.now();
for (const [sessionId, s] of sessions.entries()) {
if (now - s.lastActivity > SESSION_IDLE_TIMEOUT_MS) {
console.error(`[crowdlending-mcp${LABEL ? `-${LABEL}` : ''}] session ${sessionId} inactive depuis plus de 30 min, fermeture.`);
console.error(`${LOG_PREFIX} session ${sessionId.slice(0, 8)} inactive depuis plus de 30 min, fermeture.`);
s.transport.close();
sessions.delete(sessionId);
}
@@ -179,7 +191,10 @@ app.post('/mcp', async (req, res) => {
return;
}
touchSession(sessionId);
const label = describeRequest(req.body);
const startedAt = Date.now();
await session.transport.handleRequest(req, res, req.body);
console.error(`${LOG_PREFIX} session ${sessionId.slice(0, 8)}${label}${res.statusCode} (${Date.now() - startedAt}ms)`);
return;
}
@@ -195,9 +210,11 @@ app.post('/mcp', async (req, res) => {
}
const transport = await createSession(apiKey);
const startedAt = Date.now();
await transport.handleRequest(req, res, req.body);
console.error(`${LOG_PREFIX} nouvelle session ${transport.sessionId ? transport.sessionId.slice(0, 8) : '?'} — initialize — ${res.statusCode} (${Date.now() - startedAt}ms)`);
} catch (e) {
console.error(`[crowdlending-mcp${LABEL ? `-${LABEL}` : ''}] erreur /mcp POST :`, e);
console.error(`${LOG_PREFIX} erreur /mcp POST :`, e);
if (!res.headersSent) res.status(500).json({ jsonrpc: '2.0', error: { code: -32603, message: e.message }, id: null });
}
});
@@ -220,5 +237,5 @@ app.get('/mcp', handleExistingSession);
app.delete('/mcp', handleExistingSession);
app.listen(PORT, '0.0.0.0', () => {
console.error(`[crowdlending-mcp${LABEL ? `-${LABEL}` : ''}] à l'écoute sur le port ${PORT}`);
console.error(`${LOG_PREFIX} à l'écoute sur le port ${PORT}`);
});