Keep/MCP-SSE-ANALYSIS.md
sepehr 8d95f34fcc fix: Add debounced Undo/Redo system to avoid character-by-character history
- Add debounced state updates for title and content (500ms delay)
- Immediate UI updates with delayed history saving
- Prevent one-letter-per-undo issue
- Add cleanup for debounce timers on unmount
2026-01-04 14:28:11 +01:00

325 lines
7.6 KiB
Markdown

# MCP et SSE (Server-Sent Events) - Analyse
## Question
**Peut-on utiliser le MCP en SSE?**
## Réponse: OUI ✅ (avec nuances)
Le SDK MCP (@modelcontextprotocol/sdk) supporte **plusieurs transports**, dont certains utilisent SSE.
---
## Transports MCP Disponibles
### 1. **stdio** (Actuellement utilisé) ✅
```javascript
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
```
**Avantages**:
- Simple, direct, pas de réseau
- Idéal pour processus locaux
- Utilisé par Claude Desktop, Cline, etc.
**Inconvénients**:
- ❌ Nécessite accès fichier local
- ❌ Pas adapté pour N8N sur machine distante
- ❌ N8N doit avoir accès à `D:/dev_new_pc/Keep/mcp-server/index.js`
---
### 2. **SSE via HTTP** ✅ (RECOMMANDÉ pour N8N distant!)
```javascript
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
```
**Avantages**:
- ✅ Fonctionne sur le réseau (parfait pour N8N distant!)
- ✅ Connexion persistante unidirectionnelle
- ✅ Standard HTTP/HTTPS
- ✅ Pas de WebSocket nécessaire
- ✅ Compatible avec la plupart des firewalls
**Comment ça marche**:
1. Client (N8N) se connecte à `http://your-ip:3001/sse`
2. Serveur maintient la connexion ouverte
3. Envoie des événements SSE au format `data: {...}\n\n`
4. Client peut envoyer des requêtes via POST sur `/message`
---
### 3. **HTTP avec WebSockets** (Alternative)
```javascript
// Pas officiellement documenté dans SDK 1.0.4
// Mais possible avec implémentation custom
```
---
## Configuration SSE pour Memento MCP Server
### Option A: Créer un serveur SSE séparé
**Fichier**: `mcp-server/index-sse.js`
```javascript
#!/usr/bin/env node
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
import express from 'express';
import { PrismaClient } from '@prisma/client';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const app = express();
const PORT = 3001;
// Initialize Prisma
const prisma = new PrismaClient({
datasources: {
db: {
url: `file:${join(__dirname, '../keep-notes/prisma/dev.db')}`
}
}
});
// Helper function
function parseNote(dbNote) {
return {
...dbNote,
checkItems: dbNote.checkItems ? JSON.parse(dbNote.checkItems) : null,
labels: dbNote.labels ? JSON.parse(dbNote.labels) : null,
images: dbNote.images ? JSON.parse(dbNote.images) : null,
};
}
// Initialize MCP Server
const server = new Server(
{
name: 'memento-mcp-server',
version: '1.0.0',
},
{
capabilities: {
tools: {},
},
}
);
// Register all tools (same as stdio version)
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
// ... tous les tools comme create_note, get_notes, etc.
],
};
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
// ... même logique que stdio version
});
// SSE Endpoint
app.get('/sse', async (req, res) => {
const transport = new SSEServerTransport('/message', res);
await server.connect(transport);
});
// Message Endpoint
app.post('/message', express.json(), async (req, res) => {
// Handled by SSEServerTransport
});
app.listen(PORT, () => {
console.log(`MCP SSE Server running on http://localhost:${PORT}`);
console.log(`SSE endpoint: http://localhost:${PORT}/sse`);
});
```
**Dépendances à ajouter**:
```bash
cd mcp-server
npm install express
```
**Démarrage**:
```bash
node mcp-server/index-sse.js
```
---
### Option B: Utiliser Next.js API Route avec SSE
**Fichier**: `keep-notes/app/api/mcp/route.ts`
```typescript
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
import { prisma } from '@/lib/prisma';
import { NextRequest } from 'next/server';
const mcpServer = new Server(
{
name: 'memento-mcp-server',
version: '1.0.0',
},
{
capabilities: {
tools: {},
},
}
);
// Register tools...
export async function GET(req: NextRequest) {
const encoder = new TextEncoder();
const stream = new ReadableStream({
async start(controller) {
const transport = new SSEServerTransport('/api/mcp/message', {
write: (data) => controller.enqueue(encoder.encode(data)),
});
await mcpServer.connect(transport);
},
});
return new Response(stream, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
},
});
}
export async function POST(req: NextRequest) {
// Handle messages
const body = await req.json();
// Process via mcpServer
return Response.json({ success: true });
}
```
**Avantage**: Même serveur Next.js, pas de port séparé!
---
## Configuration N8N avec SSE
### Méthode 1: MCP Client Community Node (si supporte SSE)
**Configuration**:
```json
{
"name": "memento-sse",
"transport": "sse",
"url": "http://YOUR_IP:3001/sse"
}
```
### Méthode 2: HTTP Request Nodes (Fallback)
Si le MCP Client ne supporte pas SSE, utiliser les nodes HTTP Request standards de N8N avec l'API REST existante (comme actuellement).
---
## Comparaison: stdio vs SSE
| Feature | stdio | SSE |
|---------|-------|-----|
| **Connexion** | Process local | HTTP réseau |
| **N8N distant** | ❌ Non | ✅ Oui |
| **Latence** | Très faible | Faible |
| **Setup** | Simple | Moyen |
| **Firewall** | N/A | Standard HTTP |
| **Scaling** | 1 instance | Multiple clients |
| **Debugging** | Console logs | Network logs + curl |
---
## Recommandation pour ton cas
### Contexte
- N8N déployé sur une **machine séparée**
- Besoin d'accès distant au MCP server
- MCP Client Community Node installé
### Solution: **SSE via Express** ✅
**Pourquoi**:
1. stdio nécessite accès fichier local (impossible si N8N sur autre machine)
2. SSE fonctionne sur HTTP standard (réseau)
3. Facile à tester avec curl
4. Compatible avec la plupart des clients MCP
**Étapes**:
1. Créer `mcp-server/index-sse.js` avec Express + SSE
2. Ajouter `express` aux dépendances
3. Démarrer sur port 3001 (ou autre)
4. Trouver l'IP de ta machine Windows: `ipconfig`
5. Configurer N8N MCP Client avec `http://YOUR_IP:3001/sse`
6. Tester avec N8N workflows
---
## Test SSE sans N8N
### Avec curl:
```bash
# Test connexion SSE
curl -N http://localhost:3001/sse
# Test appel d'un tool
curl -X POST http://localhost:3001/message \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "get_notes",
"arguments": {}
},
"id": 1
}'
```
### Avec JavaScript (test rapide):
```javascript
const eventSource = new EventSource('http://localhost:3001/sse');
eventSource.onmessage = (event) => {
console.log('Received:', event.data);
};
eventSource.onerror = (error) => {
console.error('SSE Error:', error);
};
```
---
## Prochaines étapes
1.**Je peux créer le serveur SSE si tu veux**
2.**Tester localement avec curl**
3.**Configurer N8N pour pointer vers SSE endpoint**
4.**Vérifier que MCP Client Community Node supporte SSE**
**Tu veux que je crée le serveur SSE maintenant?**
---
## Ressources
- [MCP SDK Documentation](https://github.com/modelcontextprotocol/sdk)
- [SSE Specification](https://html.spec.whatwg.org/multipage/server-sent-events.html)
- [N8N MCP Integration](https://community.n8n.io/)
---
**Conclusion**: Oui, MCP peut utiliser SSE! C'est même **recommandé** pour ton cas avec N8N sur une machine distante. Le transport stdio actuel ne fonctionne que pour processus locaux.