@sei-js/mcp-server
Version:
Model Context Protocol (MCP) server for interacting with EVM-compatible networks
79 lines (78 loc) • 3.12 kB
JavaScript
import express from 'express';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import { createCorsMiddleware, validateSecurityConfig } from './security.js';
import { getServer } from '../server.js';
export class StreamableHttpTransport {
constructor(port = 8080, host = 'localhost', path = '/mcp', walletMode = 'disabled') {
this.mode = 'streamable-http';
this.port = port;
this.host = host;
this.path = path;
this.walletMode = walletMode;
}
// Note: server parameter ignored for now as this is a stateless server
// TODO: allow creating both stateless and stateful remote MCP servers
async start(_server) {
// Block wallet mode on HTTP transports
validateSecurityConfig(this.mode, this.walletMode);
this.app = express();
this.app.use(express.json());
// Secure CORS - no cross-origin allowed by default
this.app.use(createCorsMiddleware());
// Health check endpoint
this.app.get('/health', (_req, res) => {
res.json({ status: 'ok', timestamp: new Date().toISOString() });
});
this.app.post(this.path, async (req, res) => {
try {
// Create fresh MCP server for this request (stateless design)
const mcpServer = await getServer();
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined // For stateless servers
});
res.on('close', () => {
console.log('Request closed');
transport.close();
mcpServer.close();
});
await mcpServer.connect(transport);
await transport.handleRequest(req, res, req.body);
}
catch (error) {
console.error('Error handling MCP request:', error);
if (!res.headersSent) {
res.status(500).json({
jsonrpc: '2.0',
error: {
code: -32603,
message: 'Internal server error'
},
id: null
});
}
}
});
this.server = this.app.listen(this.port, this.host, () => {
console.error(`MCP Server ready (streamable-http transport on ${this.host}:${this.port}${this.path})`);
});
this.server.on('error', (error) => {
console.error('Error starting server:', error);
});
}
async stop() {
if (this.server) {
return new Promise((resolve) => {
if (this.server) {
this.server.close(() => {
this.server = undefined;
this.app = undefined;
resolve();
});
}
else {
resolve();
}
});
}
}
}