Skip to main content
Glama

MCP Firebird

// enhanced-proxy.js // Proxy mejorado para SSE que aprovecha las nuevas características del servidor MCP Firebird import express from 'express'; import cors from 'cors'; import fetch from 'node-fetch'; // Configuración const PORT = process.env.PORT || 3005; const MCP_SERVER_URL = process.env.MCP_SERVER_URL || 'http://localhost:3003'; // Crear la aplicación Express const app = express(); // Habilitar CORS app.use(cors()); // Parsear JSON app.use(express.json()); // Almacenar las conexiones SSE activas const connections = new Map(); // Verificar si el servidor MCP soporta proxies async function checkProxySupport() { try { const response = await fetch(`${MCP_SERVER_URL}/proxy-support`); if (!response.ok) { console.warn('El servidor MCP no soporta el endpoint /proxy-support. Usando modo de compatibilidad.'); return false; } const data = await response.json(); console.log('Información de soporte de proxy:', data); return data.supported === true; } catch (error) { console.warn(`Error al verificar el soporte de proxy: ${error.message}. Usando modo de compatibilidad.`); return false; } } // Endpoint SSE para la conexión inicial app.get('/', async (req, res) => { try { console.log('Nueva conexión SSE recibida'); // Configurar la respuesta para SSE res.setHeader('Content-Type', 'text/event-stream'); res.setHeader('Cache-Control', 'no-cache, no-transform'); res.setHeader('Connection', 'keep-alive'); res.flushHeaders(); // Generar un ID de cliente único const clientId = `client-${Date.now()}-${Math.random().toString(36).substring(2, 10)}`; console.log(`ID de cliente generado: ${clientId}`); // Verificar si el servidor MCP soporta proxies const proxySupported = await checkProxySupport(); // Establecer una conexión SSE con el servidor MCP const headers = { 'Accept': 'text/event-stream' }; // Añadir headers específicos para proxy si es soportado if (proxySupported) { headers['x-mcp-proxy'] = 'true'; headers['x-proxy-client-id'] = clientId; } const mcpResponse = await fetch(MCP_SERVER_URL, { method: 'GET', headers }); if (!mcpResponse.ok) { throw new Error(`Error al conectar con el servidor MCP: ${mcpResponse.status} ${mcpResponse.statusText}`); } console.log('Conexión SSE establecida con el servidor MCP'); // Almacenar la conexión del cliente connections.set(clientId, { clientRes: res, createdAt: new Date(), mcpSessionId: null, // Se actualizará cuando recibamos el evento endpoint del servidor MCP proxySupported }); // Enviar el evento endpoint al cliente const endpointUrl = `/message?sessionId=${clientId}`; res.write(`event: endpoint\ndata: ${endpointUrl}\n\n`); console.log(`Evento endpoint enviado al cliente: ${endpointUrl}`); // Procesar los eventos del servidor MCP y reenviarlos al cliente const mcpBody = mcpResponse.body; let mcpSessionId = null; let buffer = ''; mcpBody.on('data', (chunk) => { const data = chunk.toString(); console.log(`Recibido del servidor MCP: ${data}`); // Añadir al buffer buffer += data; // Buscar el evento endpoint en el buffer const endpointMatch = buffer.match(/event: endpoint\ndata: ([^\n]+)/); if (endpointMatch && !mcpSessionId) { const endpointUrl = endpointMatch[1]; console.log(`Evento endpoint recibido: ${endpointUrl}`); try { // Extraer el ID de sesión de la URL del endpoint const url = new URL(endpointUrl, MCP_SERVER_URL); mcpSessionId = url.searchParams.get('sessionId'); console.log(`ID de sesión MCP: ${mcpSessionId}`); // Almacenar el ID de sesión MCP en la conexión del cliente const connection = connections.get(clientId); if (connection) { connections.set(clientId, { ...connection, mcpSessionId }); } // No reenviar el evento endpoint del servidor MCP al cliente // para evitar que el cliente actualice su ID de sesión return; } catch (error) { console.error(`Error al procesar la URL del endpoint: ${error.message}`); } } // Reenviar el evento al cliente (excepto el evento endpoint) if (!res.writableEnded) { res.write(data); } }); mcpBody.on('error', (error) => { console.error(`Error en la conexión con el servidor MCP: ${error.message}`); }); mcpBody.on('end', () => { console.log('Conexión con el servidor MCP cerrada'); // Cerrar la conexión con el cliente if (!res.writableEnded) { res.end(); } // Eliminar la conexión connections.delete(clientId); }); // Manejar la desconexión del cliente req.on('close', () => { console.log(`Cliente desconectado: ${clientId}`); // Cerrar la conexión con el servidor MCP mcpBody.destroy(); // Eliminar la conexión connections.delete(clientId); }); } catch (error) { console.error(`Error al establecer la conexión SSE: ${error.message}`); // Solo enviar una respuesta si los encabezados no se han enviado aún if (!res.headersSent) { res.status(500).send({ error: 'Error al establecer la conexión SSE', message: error.message }); } else if (!res.writableEnded) { res.end(); } } }); // Endpoint para mensajes app.post('/message', async (req, res) => { try { // Obtener el ID de cliente del parámetro de consulta const clientId = req.query.sessionId?.toString(); if (!clientId) { throw new Error('Se requiere un ID de cliente'); } console.log(`Mensaje recibido del cliente: ${clientId}`); // Verificar si el cliente existe if (!connections.has(clientId)) { throw new Error(`No se encontró una conexión activa para el ID: ${clientId}`); } // Obtener la conexión del cliente const connection = connections.get(clientId); // Verificar si tenemos un ID de sesión MCP if (!connection.mcpSessionId) { throw new Error('No hay un ID de sesión MCP disponible'); } console.log(`Reenviando mensaje al servidor MCP con ID de sesión: ${connection.mcpSessionId}`); // Preparar los headers para la solicitud al servidor MCP const headers = { 'Content-Type': 'application/json' }; // Añadir headers específicos para proxy si es soportado if (connection.proxySupported) { headers['x-mcp-proxy'] = 'true'; headers['x-proxy-client-id'] = clientId; } // Reenviar la solicitud al servidor MCP const mcpResponse = await fetch(`${MCP_SERVER_URL}/message?sessionId=${connection.mcpSessionId}`, { method: 'POST', headers, body: JSON.stringify(req.body) }); // Obtener la respuesta del servidor MCP const mcpResponseText = await mcpResponse.text(); // Intentar parsear la respuesta como JSON let mcpResponseJson; try { mcpResponseJson = JSON.parse(mcpResponseText); console.log(`Respuesta JSON: ${JSON.stringify(mcpResponseJson)}`); } catch (error) { console.error(`Error al parsear la respuesta del servidor MCP: ${error.message}`); console.error(`Respuesta del servidor MCP: ${mcpResponseText}`); // Enviar la respuesta como texto res.status(mcpResponse.status).send(mcpResponseText); return; } // Enviar la respuesta al cliente res.status(mcpResponse.status).json(mcpResponseJson); } catch (error) { console.error(`Error al procesar el mensaje: ${error.message}`); // Enviar una respuesta de error res.status(500).json({ jsonrpc: '2.0', id: req.body?.id, error: { code: -32603, message: error.message || 'Error interno del servidor' } }); } }); // Endpoint de información app.get('/info', (req, res) => { res.status(200).send({ name: 'MCP Firebird SSE Proxy', version: '1.0.0', connections: connections.size, mcpServerUrl: MCP_SERVER_URL }); }); // Iniciar el servidor app.listen(PORT, () => { console.log(`Proxy SSE para MCP Firebird escuchando en el puerto ${PORT}`); console.log(`Redirigiendo solicitudes a ${MCP_SERVER_URL}`); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/PuroDelphi/mcpFirebird'

If you have feedback or need assistance with the MCP directory API, please join our Discord server