#!/usr/bin/env node import http from 'http'; import cors from 'cors'; import express from 'express'; // Import configuration import { initializeAwsClients, loadServerConfig } from './config/index.js'; import { getLogger } from './utils/logging.js'; import { requestLogger, errorHandler } from './server/middleware.js'; import { requestTracker } from './server/request-tracking.js'; import { getTransportManager } from './server/transport.js'; import { createMcpServer } from './server/mcp-server.js'; import { setupGlobalErrorHandlers } from './utils/global-error-handler.js'; import { createMetricsMiddleware } from './utils/metrics.js'; import { getMetricsHandler, resetMetricsHandler } from './server/metrics-endpoint.js'; import { healthCheckHandler } from './server/health-check.js'; import { initializeTransport } from './transports/index.js'; // Get logger const logger = getLogger(); async function main() { try { // Set up global error handlers setupGlobalErrorHandlers(); // Initialize AWS clients await initializeAwsClients(); // Load server configuration const serverConfig = loadServerConfig(); // Create the MCP server const server = createMcpServer({ name: serverConfig.serverName, version: serverConfig.serverVersion, description: serverConfig.serverDescription, instructions: serverConfig.serverInstructions }); // Initialize the appropriate transport based on invocation mode const { isStdioMode } = await initializeTransport(server); // If using stdio transport, we don't need to start an HTTP server if (isStdioMode) { logger.info('Running in stdio mode - no HTTP server started'); // Stdio transport is already connected to the server by initializeTransport return; } // Continue with HTTP server setup for non-stdio mode // Set up Express server const app = express(); const port = serverConfig.port; // Configure CORS app.use(cors()); app.use(express.json()); // Add monitoring middleware app.use(requestTracker); app.use(createMetricsMiddleware()); app.use(requestLogger); // Monitoring endpoints app.get('/health', healthCheckHandler); app.get('/metrics', getMetricsHandler); app.post('/metrics/reset', resetMetricsHandler); // Create HTTP server const httpServer = http.createServer(app); // Get transport manager const transportManager = getTransportManager(); // Unified MCP endpoint for streamable HTTP app.all('/mcp', async (req, res) => { try { await transportManager.handleRequest(req, res); } catch (error) { logger.error('Error handling MCP request:', error); if (!res.headersSent) { res.status(500).json({ error: 'Error handling MCP request', message: error instanceof Error ? error.message : String(error) }); } } }); // Legacy SSE endpoint for backward compatibility // This will actually use streamable HTTP transport under the hood app.all('/sse', async (req, res) => { try { await transportManager.handleRequest(req, res); } catch (error) { logger.error('Error handling SSE request:', error); if (!res.headersSent) { res.status(500).json({ error: 'Error handling SSE request', message: error instanceof Error ? error.message : String(error) }); } } }); // Add error handling middleware app.use(errorHandler); // Start the HTTP server httpServer.listen(port, () => { logger.info(`AWS Logs MCP server started on port ${port}`); logger.info('MCP streamable HTTP endpoint available at:'); logger.info(`- http://localhost:${port}/mcp`); logger.info('Legacy SSE endpoint (now using streamable HTTP) available at:'); logger.info(`- http://localhost:${port}/sse`); }); // Handle shutdown const handleShutdown = () => { logger.info('Shutting down server...'); httpServer.close(); process.exit(0); }; process.on('SIGINT', handleShutdown); process.on('SIGTERM', handleShutdown); } catch (error) { logger.error('Error starting server:', error); process.exit(1); } } main();