- 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
325 lines
7.6 KiB
Markdown
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.
|