yszl-mcp
Version:
Scenic Area Tourist Flow Query Server with official MCP SDK
122 lines (104 loc) • 3.47 kB
JavaScript
/**
* 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;
}
}
}