import { randomUUID } from 'node:crypto'; import express from 'express'; import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; import { createServer } from '../server.js'; import { processManager } from '../lib/processManager.js'; import { browserManager } from '../tools/browser/index.js'; import { dockerManager } from '../tools/docker/index.js'; import { logger } from '../lib/logger.js'; import { config } from '../config.js'; const app = express(); app.use(express.json()); if (config.httpToken) { app.use((req, res, next) => { const auth = req.header('authorization'); if (auth === `Bearer ${config.httpToken}`) { next(); return; } res.status(401).json({ error: 'Unauthorized' }); }); } else if (config.httpHost !== '127.0.0.1' && config.httpHost !== 'localhost') { logger.error(`Refusing to bind to non-localhost host "${config.httpHost}" without MCP_HTTP_TOKEN set. ` + 'Set MCP_HTTP_TOKEN, or bind to 127.0.0.1/localhost for unauthenticated local use.'); process.exit(1); } const transports = new Map(); app.post('/mcp', async (req, res) => { try { const sessionId = req.header('mcp-session-id'); let transport = sessionId ? transports.get(sessionId) : undefined; if (!transport) { const server = createServer(); transport = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID(), onsessioninitialized: (id) => { transports.set(id, transport); logger.info(`http session initialized: ${id}`); }, onsessionclosed: (id) => { transports.delete(id); logger.info(`http session closed: ${id}`); }, }); await server.connect(transport); } await transport.handleRequest(req, res, req.body); } catch (error) { logger.error('error handling POST /mcp', { error: error instanceof Error ? error.message : error }); if (!res.headersSent) res.status(500).json({ error: 'Internal server error' }); } }); app.get('/mcp', async (req, res) => { const sessionId = req.header('mcp-session-id'); const transport = sessionId ? transports.get(sessionId) : undefined; if (!transport) { res.status(400).send('Invalid or missing mcp-session-id'); return; } await transport.handleRequest(req, res); }); app.delete('/mcp', async (req, res) => { const sessionId = req.header('mcp-session-id'); const transport = sessionId ? transports.get(sessionId) : undefined; if (!transport) { res.status(400).send('Invalid or missing mcp-session-id'); return; } await transport.handleRequest(req, res); }); app.get('/healthz', (_req, res) => { res.json({ status: 'ok', workspaceRoot: config.workspaceRoot }); }); const httpServer = app.listen(config.httpPort, config.httpHost, () => { logger.info(`web-dev-mcp HTTP server listening on http://${config.httpHost}:${config.httpPort}/mcp`); }); async function shutdown(signal) { logger.info(`received ${signal}, shutting down`); processManager.stopAll(); await browserManager.close(); await dockerManager.cleanupAll(); httpServer.close(() => process.exit(0)); } process.on('SIGINT', () => void shutdown('SIGINT')); process.on('SIGTERM', () => void shutdown('SIGTERM')); //# sourceMappingURL=http.js.map