@sei-js/mcp-server
Version:
Model Context Protocol (MCP) server for interacting with EVM-compatible networks
104 lines (103 loc) • 3.87 kB
JavaScript
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
import cors from 'cors';
import express from 'express';
export class HttpSseTransport {
constructor(port, host, path) {
this.port = port;
this.host = host;
this.path = path;
this.mode = 'http-sse';
this.httpServer = null;
this.connections = new Map();
this.mcpServer = null;
this.app = express();
this.setupMiddleware();
this.setupRoutes();
}
setupMiddleware() {
this.app.use(express.json());
this.app.use(cors({
origin: '*',
methods: ['GET', 'POST', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
exposedHeaders: ['Content-Type', 'Access-Control-Allow-Origin']
}));
this.app.options('*', cors());
}
setupRoutes() {
// Health check endpoint
this.app.get('/health', (req, res) => {
res.json({ status: 'ok', timestamp: new Date().toISOString() });
});
this.app.get(this.path, (req, res) => {
console.error(`SSE connection from ${req.ip}`);
// Create SSE transport - it will handle headers automatically
const transport = new SSEServerTransport(`${this.path}/message`, res);
const sessionId = Date.now().toString();
this.connections.set(sessionId, transport);
// Connect transport to MCP server
if (this.mcpServer) {
this.mcpServer.connect(transport);
}
// Clean up on disconnect
req.on('close', () => {
this.connections.delete(sessionId);
console.error(`SSE connection closed for session ${sessionId}`);
});
});
// Message endpoint for SSE transport
this.app.post(`${this.path}/message`, async (req, res) => {
try {
// Find the first available transport (simple approach for now)
const transport = Array.from(this.connections.values())[0];
if (!transport) {
res.status(404).json({ error: 'No active SSE connection' });
return;
}
await transport.handleMessage(req.body);
res.status(200).end();
}
catch (error) {
console.error('Error handling message:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
}
async start(server) {
this.mcpServer = server;
return new Promise((resolve, reject) => {
this.httpServer = this.app.listen(this.port, this.host, () => {
console.error(`MCP Server ready (http-sse transport on ${this.host}:${this.port}${this.path})`);
resolve();
});
this.httpServer.on('error', (error) => {
console.error('Error starting server:', error);
reject(error);
});
// Handle graceful shutdown
const cleanup = () => {
console.error('Shutting down HTTP SSE server...');
this.connections.clear();
if (this.httpServer) {
this.httpServer.close();
}
};
process.on('SIGINT', cleanup);
process.on('SIGTERM', cleanup);
});
}
async stop() {
return new Promise((resolve) => {
if (this.httpServer) {
this.httpServer.close(() => {
console.error('HTTP SSE server stopped');
resolve();
});
}
else {
resolve();
}
});
}
}