Skip to main content
Glama

EVM MCP Server

by mcpdotdirect
http-server.ts7.17 kB
import { config } from "dotenv"; import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; import startServer from "./server.js"; import express, { Request, Response } from "express"; import cors from "cors"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; // Environment variables - hardcoded values const PORT = 3001; const HOST = '0.0.0.0'; console.error(`Configured to listen on ${HOST}:${PORT}`); // Setup Express const app = express(); app.use(express.json()); app.use(cors({ origin: '*', methods: ['GET', 'POST', 'OPTIONS'], allowedHeaders: ['Content-Type', 'Authorization'], credentials: true, exposedHeaders: ['Content-Type', 'Access-Control-Allow-Origin'] })); // Add OPTIONS handling for preflight requests app.options('*', cors()); // Keep track of active connections with session IDs const connections = new Map<string, SSEServerTransport>(); // Initialize the server let server: McpServer | null = null; startServer().then(s => { server = s; console.error("MCP Server initialized successfully"); }).catch(error => { console.error("Failed to initialize server:", error); process.exit(1); }); // Define routes // @ts-ignore app.get("/sse", (req: Request, res: Response) => { console.error(`Received SSE connection request from ${req.ip}`); console.error(`Query parameters: ${JSON.stringify(req.query)}`); // Set CORS headers explicitly res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); if (!server) { console.error("Server not initialized yet, rejecting SSE connection"); return res.status(503).send("Server not initialized"); } // Generate a unique session ID if one is not provided // The sessionId is crucial for mapping SSE connections to message handlers const sessionId = generateSessionId(); console.error(`Creating SSE session with ID: ${sessionId}`); // Set SSE headers res.setHeader("Content-Type", "text/event-stream"); res.setHeader("Cache-Control", "no-cache, no-transform"); res.setHeader("Connection", "keep-alive"); // Create transport - handle before writing to response try { console.error(`Creating SSE transport for session: ${sessionId}`); // Create and store the transport keyed by session ID // Note: The path must match what the client expects (typically "/messages") const transport = new SSEServerTransport("/messages", res); connections.set(sessionId, transport); // Handle connection close req.on("close", () => { console.error(`SSE connection closed for session: ${sessionId}`); connections.delete(sessionId); }); // Connect transport to server - this must happen before sending any data server.connect(transport).then(() => { // Send an initial event with the session ID for the client to use in messages // Only send this after the connection is established console.error(`SSE connection established for session: ${sessionId}`); // Send the session ID to the client res.write(`data: ${JSON.stringify({ type: "session_init", sessionId })}\n\n`); }).catch((error: Error) => { console.error(`Error connecting transport to server: ${error}`); connections.delete(sessionId); }); } catch (error) { console.error(`Error creating SSE transport: ${error}`); connections.delete(sessionId); res.status(500).send(`Internal server error: ${error}`); } }); // @ts-ignore app.post("/messages", (req: Request, res: Response) => { // Extract the session ID from the URL query parameters let sessionId = req.query.sessionId?.toString(); // If no sessionId is provided and there's only one connection, use that if (!sessionId && connections.size === 1) { sessionId = Array.from(connections.keys())[0]; console.error(`No sessionId provided, using the only active session: ${sessionId}`); } console.error(`Received message for sessionId ${sessionId}`); console.error(`Message body: ${JSON.stringify(req.body)}`); // Set CORS headers res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); if (!server) { console.error("Server not initialized yet"); return res.status(503).json({ error: "Server not initialized" }); } if (!sessionId) { console.error("No session ID provided and multiple connections exist"); return res.status(400).json({ error: "No session ID provided. Please provide a sessionId query parameter or connect to /sse first.", activeConnections: connections.size }); } const transport = connections.get(sessionId); if (!transport) { console.error(`Session not found: ${sessionId}`); return res.status(404).json({ error: "Session not found" }); } console.error(`Handling message for session: ${sessionId}`); try { transport.handlePostMessage(req, res).catch((error: Error) => { console.error(`Error handling post message: ${error}`); res.status(500).json({ error: `Internal server error: ${error.message}` }); }); } catch (error) { console.error(`Exception handling post message: ${error}`); res.status(500).json({ error: `Internal server error: ${error}` }); } }); // Add a simple health check endpoint app.get("/health", (req: Request, res: Response) => { res.status(200).json({ status: "ok", server: server ? "initialized" : "initializing", activeConnections: connections.size, connectedSessionIds: Array.from(connections.keys()) }); }); // Add a root endpoint for basic info app.get("/", (req: Request, res: Response) => { res.status(200).json({ name: "MCP Server", version: "1.0.0", endpoints: { sse: "/sse", messages: "/messages", health: "/health" }, status: server ? "ready" : "initializing", activeConnections: connections.size }); }); // Helper function to generate a UUID-like session ID function generateSessionId(): string { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { const r = Math.random() * 16 | 0; const v = c === 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); } // Handle process termination gracefully process.on('SIGINT', () => { console.error('Shutting down server...'); connections.forEach((transport, sessionId) => { console.error(`Closing connection for session: ${sessionId}`); }); process.exit(0); }); // Start the HTTP server on a different port (3001) to avoid conflicts const httpServer = app.listen(PORT, HOST, () => { console.error(`Template MCP Server running at http://${HOST}:${PORT}`); console.error(`SSE endpoint: http://${HOST}:${PORT}/sse`); console.error(`Messages endpoint: http://${HOST}:${PORT}/messages (sessionId optional if only one connection)`); console.error(`Health check: http://${HOST}:${PORT}/health`); }).on('error', (err: Error) => { console.error(`Server error: ${err}`); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mcpdotdirect/evm-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server