Signed-off-by: ale <ale@manalejandro.com>
Este commit está contenido en:
ale
2025-10-09 03:29:48 +02:00
padre b26a2d2e61
commit 089dcb00a6

Ver fichero

@@ -3,6 +3,7 @@ import cors from 'cors';
import swaggerUi from 'swagger-ui-express'; import swaggerUi from 'swagger-ui-express';
import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
import { import {
CallToolRequestSchema, CallToolRequestSchema,
ListToolsRequestSchema, ListToolsRequestSchema,
@@ -16,8 +17,14 @@ const PORT = process.env.PORT || 3000;
const app = express(); const app = express();
// Middleware // Middleware
app.use(cors()); app.use(cors({
origin: '*',
methods: ['GET', 'POST', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Accept'],
credentials: false
}));
app.use(express.json()); app.use(express.json());
app.use(express.text());
// Swagger Documentation // Swagger Documentation
app.use('/api-docs', ...swaggerUi.serve as any); app.use('/api-docs', ...swaggerUi.serve as any);
@@ -459,62 +466,81 @@ async function handleToolCall(name: string, args: any): Promise<any> {
} }
/** /**
* Endpoint JSON-RPC para MCP * Crea un servidor MCP con los handlers configurados
*/ */
app.post('/mcp/v1', async (req: Request, res: Response) => { function createMCPServer(): Server {
const server = new Server(
{
name: 'ine-mcp-server',
version: '1.0.0',
},
{
capabilities: {
tools: {},
},
}
);
// Registrar handler para listar herramientas
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools
}));
// Registrar handler para llamar herramientas
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
const result = await handleToolCall(name, args || {});
return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2)
}
]
};
});
return server;
}
/**
* Endpoint MCP HTTP con SSE (Server-Sent Events)
* Este es el protocolo oficial de MCP para HTTP
*/
app.get('/mcp/v1/sse', async (req: Request, res: Response) => {
console.log('Nueva conexión SSE MCP');
try { try {
const { jsonrpc, method, params, id } = req.body; const server = createMCPServer();
const transport = new SSEServerTransport('/mcp/v1/message', res);
if (jsonrpc !== '2.0') {
return res.status(400).json({ await server.connect(transport);
jsonrpc: '2.0',
error: { code: -32600, message: 'Invalid Request' }, // La conexión se mantiene abierta hasta que el cliente se desconecte
id: null req.on('close', () => {
}); console.log('Conexión SSE cerrada');
} server.close().catch(console.error);
// Listar herramientas
if (method === 'tools/list') {
return res.json({
jsonrpc: '2.0',
result: { tools },
id
});
}
// Llamar a una herramienta
if (method === 'tools/call') {
const { name, arguments: args } = params;
const result = await handleToolCall(name, args || {});
return res.json({
jsonrpc: '2.0',
result: {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2)
}
]
},
id
});
}
// Método no soportado
return res.status(404).json({
jsonrpc: '2.0',
error: { code: -32601, message: 'Method not found' },
id
}); });
} catch (error: any) { } catch (error: any) {
console.error('Error en MCP:', error); console.error('Error en conexión SSE:', error);
return res.status(500).json({ if (!res.headersSent) {
jsonrpc: '2.0', res.status(500).json({ error: error.message });
error: { code: -32603, message: error.message || 'Internal error' }, }
id: req.body.id || null }
}); });
/**
* Endpoint para mensajes MCP (usado por SSE transport)
*/
app.post('/mcp/v1/message', async (req: Request, res: Response) => {
try {
// Este endpoint es manejado internamente por SSEServerTransport
// Solo necesitamos asegurarnos de que el body parser esté configurado
res.status(202).json({ received: true });
} catch (error: any) {
console.error('Error procesando mensaje:', error);
res.status(500).json({ error: error.message });
} }
}); });
@@ -563,43 +589,15 @@ app.get('/api/tablas-operacion/:idOperacion', async (req, res) => {
app.listen(PORT, () => { app.listen(PORT, () => {
console.log(`🚀 MCP INE Server ejecutándose en http://localhost:${PORT}`); console.log(`🚀 MCP INE Server ejecutándose en http://localhost:${PORT}`);
console.log(`📚 Documentación Swagger: http://localhost:${PORT}/api-docs`); console.log(`📚 Documentación Swagger: http://localhost:${PORT}/api-docs`);
console.log(`🔧 Endpoint MCP JSON-RPC: http://localhost:${PORT}/mcp/v1`); console.log(`🔧 Endpoint MCP SSE: http://localhost:${PORT}/mcp/v1/sse`);
console.log(`📨 Endpoint MCP Message: http://localhost:${PORT}/mcp/v1/message`);
console.log(`💚 Health check: http://localhost:${PORT}/health`); console.log(`💚 Health check: http://localhost:${PORT}/health`);
console.log(`\n📋 Herramientas disponibles: ${tools.length}`);
}); });
// Para uso con stdio (AI Toolkit) // Para uso con stdio (AI Toolkit local)
export async function runStdioServer() { export async function runStdioServer() {
const server = new Server( const server = createMCPServer();
{
name: 'ine-mcp-server',
version: '1.0.0',
},
{
capabilities: {
tools: {},
},
}
);
// Registrar handlers
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools
}));
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
const result = await handleToolCall(name, args || {});
return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2)
}
]
};
});
const transport = new StdioServerTransport(); const transport = new StdioServerTransport();
await server.connect(transport); await server.connect(transport);