From 58fdf20620f21d4598a4f4c6260305bf86c38b97 Mon Sep 17 00:00:00 2001 From: ale Date: Sun, 9 Nov 2025 22:10:51 +0100 Subject: [PATCH] fix endpoints Signed-off-by: ale --- src/index.ts | 28 ++++++--- src/server-sse.ts | 141 ++++++++++++++++++++++++++-------------------- 2 files changed, 100 insertions(+), 69 deletions(-) diff --git a/src/index.ts b/src/index.ts index b40e41f..9c26d0e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -833,11 +833,14 @@ function createMCPServer(): Server { * Endpoint MCP JSON-RPC directo (más compatible y simple) */ app.post('/mcp/v1', async (req: Request, res: Response) => { - console.log('MCP JSON-RPC Request:', req.body); + console.log('MCP JSON-RPC Request:', JSON.stringify(req.body, null, 2)); try { const { jsonrpc, method, params, id } = req.body; + // Establecer headers correctos + res.setHeader('Content-Type', 'application/json'); + // Validar JSON-RPC 2.0 if (jsonrpc !== '2.0') { return res.status(400).json({ @@ -852,7 +855,8 @@ app.post('/mcp/v1', async (req: Request, res: Response) => { // Initialize - Handshake inicial de MCP if (method === 'initialize') { - return res.json({ + console.log('MCP Initialize received'); + return res.status(200).json({ jsonrpc: '2.0', result: { protocolVersion: '2024-11-05', @@ -868,15 +872,16 @@ app.post('/mcp/v1', async (req: Request, res: Response) => { }); } - // Initialized - Confirmación del cliente + // Initialized - Confirmación del cliente (es una notificación, no requiere respuesta) if (method === 'notifications/initialized') { console.log('Cliente MCP inicializado'); - return res.status(204).send(); + return res.status(200).json({}); } // Listar herramientas if (method === 'tools/list') { - return res.json({ + console.log('MCP tools/list received'); + return res.status(200).json({ jsonrpc: '2.0', result: { tools }, id @@ -887,6 +892,8 @@ app.post('/mcp/v1', async (req: Request, res: Response) => { if (method === 'tools/call') { const { name, arguments: args } = params || {}; + console.log(`MCP tools/call: ${name}`, args); + if (!name) { return res.status(400).json({ jsonrpc: '2.0', @@ -900,7 +907,9 @@ app.post('/mcp/v1', async (req: Request, res: Response) => { const result = await handleToolCall(name, args || {}); - return res.json({ + console.log(`MCP tools/call result for ${name}: success`); + + return res.status(200).json({ jsonrpc: '2.0', result: { content: [ @@ -916,7 +925,7 @@ app.post('/mcp/v1', async (req: Request, res: Response) => { // Ping/Pong if (method === 'ping') { - return res.json({ + return res.status(200).json({ jsonrpc: '2.0', result: {}, id @@ -924,7 +933,8 @@ app.post('/mcp/v1', async (req: Request, res: Response) => { } // Método no soportado - return res.status(404).json({ + console.log(`MCP method not found: ${method}`); + return res.status(200).json({ jsonrpc: '2.0', error: { code: -32601, @@ -935,7 +945,7 @@ app.post('/mcp/v1', async (req: Request, res: Response) => { } catch (error: any) { console.error('Error en MCP:', error); - return res.status(500).json({ + return res.status(200).json({ jsonrpc: '2.0', error: { code: -32603, diff --git a/src/server-sse.ts b/src/server-sse.ts index 0695d46..66c3256 100644 --- a/src/server-sse.ts +++ b/src/server-sse.ts @@ -12,12 +12,14 @@ import type { Idioma } from './types/ine.types.js'; const PORT = process.env.PORT || 3001; const app = express(); -app.use(cors()); +app.use(cors({ + origin: '*', + methods: ['GET', 'POST', 'OPTIONS'], + allowedHeaders: ['Content-Type', 'Accept'], + credentials: false +})); app.use(express.json()); -// Almacenamiento de sesiones SSE -const sessions = new Map(); - /** * Maneja las llamadas a las herramientas MCP */ @@ -128,73 +130,86 @@ const tools = [ * Endpoint SSE para conexión MCP */ app.get('/sse', async (req: Request, res: Response) => { - const sessionId = Math.random().toString(36).substring(7); - - // Configurar SSE - res.writeHead(200, { - 'Content-Type': 'text/event-stream', - 'Cache-Control': 'no-cache', - 'Connection': 'keep-alive' - }); - - // Crear servidor MCP - const server = new Server( - { - name: 'ine-mcp-server-sse', - version: '1.0.0', - }, - { - capabilities: { - tools: {}, + console.log('Nueva conexión SSE iniciada'); + + try { + // Crear servidor MCP + const server = new Server( + { + name: 'ine-mcp-server-sse', + version: '1.0.0', }, - } - ); + { + capabilities: { + tools: {}, + }, + } + ); - // Registrar handlers - server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools })); + // Registrar handlers + server.setRequestHandler(ListToolsRequestSchema, async () => { + console.log('SSE: ListTools request received'); + return { tools }; + }); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - const result = await handleToolCall(name, args || {}); + server.setRequestHandler(CallToolRequestSchema, async (request) => { + const { name, arguments: args } = request.params; + console.log(`SSE: CallTool request - ${name}`, args); + + const result = await handleToolCall(name, args || {}); + + return { + content: [ + { + type: 'text', + text: JSON.stringify(result, null, 2) + } + ] + }; + }); + + // Crear transporte SSE - este configura los headers automáticamente + const transport = new SSEServerTransport('/message', res); - return { - content: [ - { - type: 'text', - text: JSON.stringify(result, null, 2) - } - ] - }; - }); + // Conectar servidor con transporte + await server.connect(transport); + + console.log('SSE: Servidor MCP conectado'); - // Crear transporte SSE - const transport = new SSEServerTransport('/messages', res); - await server.connect(transport); + // Manejar cierre de conexión + req.on('close', () => { + console.log('SSE: Conexión cerrada por el cliente'); + server.close().catch(err => console.error('Error cerrando servidor:', err)); + }); - sessions.set(sessionId, { server, transport }); - - // Limpiar al cerrar conexión - req.on('close', () => { - sessions.delete(sessionId); - console.log(`Sesión SSE cerrada: ${sessionId}`); - }); - - console.log(`Nueva sesión SSE iniciada: ${sessionId}`); + } catch (error: any) { + console.error('Error en conexión SSE:', error); + if (!res.headersSent) { + res.status(500).json({ + error: error.message, + stack: error.stack + }); + } + } }); /** * Endpoint para enviar mensajes (POST) + * Este endpoint recibe los mensajes JSON-RPC del cliente */ -app.post('/messages', async (req: Request, res: Response) => { +app.post('/message', express.json(), async (req: Request, res: Response) => { + console.log('SSE Message received:', JSON.stringify(req.body, null, 2)); + try { - // Este endpoint procesa mensajes enviados por el cliente - const message = req.body; - console.log('Mensaje recibido:', message); - - res.json({ success: true }); + // El SDK de MCP maneja esto internamente a través del SSEServerTransport + // Solo necesitamos confirmar la recepción + res.status(202).json({ received: true }); } catch (error: any) { - console.error('Error procesando mensaje:', error); - res.status(500).json({ error: error.message }); + console.error('Error procesando mensaje SSE:', error); + res.status(500).json({ + error: error.message, + stack: error.stack + }); } }); @@ -203,8 +218,14 @@ app.get('/health', (req: Request, res: Response) => { res.json({ status: 'ok', transport: 'SSE', - sessions: sessions.size, - timestamp: new Date().toISOString() + timestamp: new Date().toISOString(), + service: 'MCP INE Server (SSE)', + version: '1.0.0', + endpoints: { + sse: '/sse', + message: '/message', + health: '/health' + } }); });