( mcpServer: MCPServer, port = DEFAULT_PORT, useHttps = false, certPath?: string, keyPath?: string, )
| 27 | * @returns Object containing the express app, http server |
| 28 | */ |
| 29 | export function createHttpServer( |
| 30 | mcpServer: MCPServer, |
| 31 | port = DEFAULT_PORT, |
| 32 | useHttps = false, |
| 33 | certPath?: string, |
| 34 | keyPath?: string, |
| 35 | ): { |
| 36 | app: ReturnType<typeof express>; |
| 37 | httpServer: http.Server | https.Server; |
| 38 | } { |
| 39 | // Create the Express app |
| 40 | const app = express(); |
| 41 | |
| 42 | // Create server based on protocol |
| 43 | let httpServer: http.Server | https.Server; |
| 44 | |
| 45 | if (useHttps) { |
| 46 | if (!certPath || !keyPath) { |
| 47 | throw new Error('Certificate and key paths are required for HTTPS'); |
| 48 | } |
| 49 | |
| 50 | // Validate certificate files exist |
| 51 | if (!fs.existsSync(certPath)) { |
| 52 | throw new Error(`Certificate file not found: ${certPath}`); |
| 53 | } |
| 54 | if (!fs.existsSync(keyPath)) { |
| 55 | throw new Error(`Key file not found: ${keyPath}`); |
| 56 | } |
| 57 | |
| 58 | try { |
| 59 | const httpsOptions = { |
| 60 | cert: fs.readFileSync(certPath), |
| 61 | key: fs.readFileSync(keyPath), |
| 62 | // Security options |
| 63 | minVersion: 'TLSv1.2' as const, |
| 64 | }; |
| 65 | // eslint-disable-next-line @typescript-eslint/no-misused-promises |
| 66 | httpServer = https.createServer(httpsOptions, app); |
| 67 | } catch (error) { |
| 68 | throw new Error( |
| 69 | `Failed to load TLS certificates: ${error instanceof Error ? error.message : String(error)}`, |
| 70 | ); |
| 71 | } |
| 72 | } else { |
| 73 | // eslint-disable-next-line @typescript-eslint/no-misused-promises |
| 74 | httpServer = http.createServer(app); |
| 75 | } |
| 76 | |
| 77 | // Track active transports by session ID |
| 78 | const transports: Record<string, SSEServerTransport> = {}; |
| 79 | const endpoint = '/mcp'; |
| 80 | |
| 81 | // Client limit enforcement middleware |
| 82 | app.use(endpoint, (req, res, next) => { |
| 83 | if (req.method === 'GET' && Object.keys(transports).length >= MAX_SSE_CLIENTS) { |
| 84 | res.status(503).json({ |
| 85 | success: false, |
| 86 | message: `Maximum number of SSE clients (${MAX_SSE_CLIENTS}) reached`, |
no outgoing calls
no test coverage detected