UNPKG

yszl-mcp

Version:

Scenic Area Tourist Flow Query Server with official MCP SDK

122 lines (104 loc) 3.47 kB
/** * Module for handling Server-Sent Events (SSE) communication protocol for MCP */ export class SseTransport { constructor(app, toolInstances) { this.app = app; this.toolInstances = toolInstances; this.clients = new Map(); } /** * Start SSE transport by setting up routes */ start() { // SSE connection endpoint this.app.get('/sse', (req, res) => { // Set SSE headers res.setHeader('Content-Type', 'text/event-stream'); res.setHeader('Cache-Control', 'no-cache'); res.setHeader('Connection', 'keep-alive'); // Send initial connection message res.write(`data: ${JSON.stringify({ type: 'connected' })}\n\n`); // Generate client ID and store the response object const clientId = Date.now().toString(); this.clients.set(clientId, res); // Handle client disconnect req.on('close', () => { this.clients.delete(clientId); }); }); // Tool execution endpoint for SSE this.app.post('/sse/execute', async (req, res) => { try { const { client_id, tool_name, inputs } = req.body; // Validate client ID if (!this.clients.has(client_id)) { return res.status(404).json({ status: 'error', message: 'Client not found' }); } // Get client's response object const clientRes = this.clients.get(client_id); try { // Execute the requested tool const result = await this.executeTool(tool_name, inputs); // Send result via SSE clientRes.write(`data: ${JSON.stringify({ type: 'tool_execution_response', status: 'success', tool_name, result })}\n\n`); // Respond to the HTTP request res.json({ status: 'success', message: 'Tool execution request submitted' }); } catch (error) { // Send error via SSE clientRes.write(`data: ${JSON.stringify({ type: 'tool_execution_response', status: 'error', tool_name, error: { message: error.message } })}\n\n`); // Respond to the HTTP request res.status(500).json({ status: 'error', message: error.message }); } } catch (error) { // Handle request processing errors res.status(500).json({ status: 'error', message: error.message }); } }); } /** * Execute a specific tool with given inputs */ async executeTool(toolName, inputs) { // Normalize tool name to match instance properties const toolKey = `${toolName.charAt(0).toLowerCase() + toolName.slice(1)}Tool`; // Check if the requested tool exists if (!this.toolInstances[toolKey]) { throw new Error(`Tool not found: ${toolName}`); } try { console.error(`Executing tool ${toolName} with inputs:`, inputs); // Execute the tool with inputs const result = await this.toolInstances[toolKey].execute(inputs); console.error(`Tool ${toolName} execution result:`, result); return result; } catch (error) { console.error(`Tool ${toolName} execution error:`, error); throw error; } } }