Skip to main content
Glama
express-index.ts5.47 kB
#!/usr/bin/env node import { randomUUID } from 'node:crypto'; import { createMcpExpressApp } from '@modelcontextprotocol/sdk/server/express.js'; import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'; import dotenv from 'dotenv'; import type { Request, Response, NextFunction } from 'express'; import { alexaMcp } from './mcp/server.js'; dotenv.config(); const PORT = Number(process.env.PORT) || 8787; // Create MCP server instance const server = alexaMcp.getMcpServer(); // Create Express app with MCP SDK helper const app = createMcpExpressApp({ host: '0.0.0.0', allowedHosts: ['localhost', '127.0.0.1', '::1', '[::1]', 'alexa-mcp-server.onrender.com', process.env.RENDER_EXTERNAL_HOSTNAME].filter( (h): h is string => !!h ), }); // CORS middleware app.use((req: Request, res: Response, next: NextFunction) => { res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); if (req.method === 'OPTIONS') { res.status(200).end(); return; } next(); }); // Store SSE transports by session ID const sseTransports: Map<string, SSEServerTransport> = new Map(); // Health check app.get('/health', (_req: Request, res: Response) => { res.json({ status: 'healthy', timestamp: new Date().toISOString() }); }); // Root endpoint app.get('/', (_req: Request, res: Response) => { res.json({ name: 'Alexa MCP Server', version: '1.3.0', endpoints: { sse: '/sse', messages: '/api/mcp' } }); }); // SSE endpoint app.get('/sse', (req: Request, res: Response) => { const clientIp = req.ip || req.socket.remoteAddress; const sessionId = `sse-${randomUUID()}`; console.log(`[SSE] Connection attempt from ${clientIp} (session: ${sessionId})`); // Create SSE transport with raw Express response object const transport = new SSEServerTransport('/api/mcp', res); // Get actual session ID from transport const actualSessionId = (transport as any).sessionId || sessionId; // Store transport sseTransports.set(actualSessionId, transport); // Setup cleanup handler transport.onclose = () => { console.log(`[SSE] Transport closed for session ${actualSessionId}`); sseTransports.delete(actualSessionId); }; console.log(`[SSE] Creating transport (session: ${actualSessionId})...`); server .connect(transport) .then(() => { console.log(`[SSE] ✅ Transport connected successfully (session: ${actualSessionId})`); }) .catch((error) => { console.error('[SSE] ❌ Error connecting SSE transport:', error); sseTransports.delete(actualSessionId); if (!res.headersSent) { res.status(500).json({ error: 'Failed to establish SSE connection' }); } }); // Clean up on connection close res.on('close', () => { console.log(`[SSE] Connection closed (session: ${actualSessionId})`); if (sseTransports.has(actualSessionId)) { try { const t = sseTransports.get(actualSessionId); if (t) { t.close(); } } catch (_e) { // Ignore cleanup errors } sseTransports.delete(actualSessionId); } }); }); // Messages endpoint app.post('/api/mcp', async (req: Request, res: Response) => { const sessionId = req.query.sessionId as string | undefined; if (!sessionId) { // Fallback: if only one active transport, use it const transportsArray = Array.from(sseTransports.entries()); if (transportsArray.length === 1) { const [, transport] = transportsArray[0]; await transport.handlePostMessage(req, res, req.body); return; } else if (transportsArray.length === 0) { res.status(503).json({ error: 'Transport not initialized', message: 'No active SSE connections. Connect to /sse first.', }); return; } else { res.status(400).json({ error: 'Session ID required', message: 'Multiple active sessions detected. Please include sessionId parameter.', }); return; } } const transport = sseTransports.get(sessionId); if (!transport) { res.status(404).json({ error: 'Session not found', message: `No active transport found for session: ${sessionId}`, }); return; } try { await transport.handlePostMessage(req, res, req.body); } catch (error) { console.error(`[SSE] Error handling message for session ${sessionId}:`, error); if (!res.headersSent) { res.status(500).json({ error: 'Internal server error', message: error instanceof Error ? error.message : 'Unknown error', }); } } }); // Start server app.listen(PORT, '0.0.0.0', () => { console.log(`🚀 Alexa MCP Server is running on http://0.0.0.0:${PORT}`); console.log(` SSE endpoint: http://0.0.0.0:${PORT}/sse`); console.log(` Messages endpoint: http://0.0.0.0:${PORT}/api/mcp`); });

Latest Blog Posts

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/guitarbeat/alexa-mcp-server'

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