#!/usr/bin/env node /** * @fileoverview Main entry point for Laravel Healthcare MCP Server * Initializes and starts the MCP server with all components */ import { ConfigManager } from './src/config/ConfigManager.js'; import { AuthManager } from './src/auth/AuthManager.js'; import { ApiClient } from './src/proxy/ApiClient.js'; import { ToolGenerator } from './src/tools/ToolGenerator.js'; import { McpServer } from './src/server/McpServer.js'; import { logger, auditLog } from './src/utils/logger.js'; import { ErrorHandler } from './src/utils/errors.js'; /** * Main application class */ class HealthcareMcpServerApp { constructor() { this.config = null; this.authManager = null; this.apiClient = null; this.toolGenerator = null; this.mcpServer = null; this.isShuttingDown = false; } /** * Initialize the application */ async initialize() { try { logger.info('Initializing Laravel Healthcare MCP Server...'); // Load configuration this.config = new ConfigManager(); logger.info('Configuration loaded:', this.config.getSummary()); // Validate configuration const configValidation = this.config.isValid(); if (!configValidation) { throw new Error('Configuration validation failed'); } // Initialize authentication manager this.authManager = new AuthManager(null, this.config.getAll(true)); logger.info('Authentication manager initialized'); // Initialize API client this.apiClient = new ApiClient(this.config.getAll(), this.authManager); logger.info('API client initialized'); // Initialize tool generator this.toolGenerator = new ToolGenerator(this.apiClient); logger.info('Tool generator initialized'); // Initialize MCP server this.mcpServer = new McpServer(this.config.getAll(), this.toolGenerator); logger.info('MCP server initialized'); // Validate authentication credentials (optional) if (this.config.get('NODE_ENV') !== 'production') { await this.validateAuthCredentials(); } logger.info('Application initialization completed successfully'); } catch (error) { logger.error('Failed to initialize application:', error); throw error; } } /** * Validate authentication credentials for all configured auth types */ async validateAuthCredentials() { try { logger.info('Validating authentication credentials...'); const results = await this.authManager.validateAllCredentials(); const validCredentials = []; const invalidCredentials = []; Object.entries(results).forEach(([authType, result]) => { if (result.valid) { validCredentials.push(authType); } else { invalidCredentials.push({ authType, error: result.error }); } }); logger.info(`Authentication validation completed: ${validCredentials.length} valid, ${invalidCredentials.length} invalid`); if (validCredentials.length > 0) { logger.info('Valid credentials for:', validCredentials); } if (invalidCredentials.length > 0) { logger.warn('Invalid credentials:', invalidCredentials.map(c => `${c.authType}: ${c.error}`)); } } catch (error) { logger.warn('Authentication validation failed:', error.message); } } /** * Start the MCP server */ async start() { try { logger.info('Starting Laravel Healthcare MCP Server...'); // Setup graceful shutdown handlers this.setupShutdownHandlers(); // Start the MCP server await this.mcpServer.start(); // Log startup completion const stats = this.mcpServer.getStatistics(); logger.info('Server started successfully:', { toolCount: stats.toolCount, categories: Object.keys(stats.categorySummary).length, authTypes: Object.keys(stats.authTypeSummary).length }); // Audit log auditLog('server_started', 'system', { serverName: this.config.get('MCP_SERVER_NAME'), serverVersion: this.config.get('MCP_SERVER_VERSION'), toolCount: stats.toolCount }); logger.info('Laravel Healthcare MCP Server is ready to accept connections'); } catch (error) { logger.error('Failed to start server:', error); throw error; } } /** * Stop the MCP server */ async stop() { if (this.isShuttingDown) { return; } this.isShuttingDown = true; logger.info('Shutting down Laravel Healthcare MCP Server...'); try { // Stop MCP server if (this.mcpServer) { await this.mcpServer.stop(); logger.info('MCP server stopped'); } // Clear authentication tokens if (this.authManager) { this.authManager.clearAllTokens(); logger.info('Authentication tokens cleared'); } // Audit log auditLog('server_stopped', 'system', { reason: 'graceful_shutdown' }); logger.info('Server shutdown completed'); } catch (error) { logger.error('Error during shutdown:', error); } } /** * Setup graceful shutdown handlers */ setupShutdownHandlers() { const shutdownHandler = async (signal) => { logger.info(`Received ${signal}, initiating graceful shutdown...`); await this.stop(); process.exit(0); }; // Handle various shutdown signals process.on('SIGTERM', () => shutdownHandler('SIGTERM')); process.on('SIGINT', () => shutdownHandler('SIGINT')); process.on('SIGUSR2', () => shutdownHandler('SIGUSR2')); // nodemon restart // Handle uncaught exceptions process.on('uncaughtException', (error) => { logger.error('Uncaught exception:', error); auditLog('server_error', 'system', { error: error.message, type: 'uncaught_exception' }); this.stop().then(() => process.exit(1)); }); // Handle unhandled promise rejections process.on('unhandledRejection', (reason, promise) => { logger.error('Unhandled promise rejection:', { reason, promise }); auditLog('server_error', 'system', { error: reason, type: 'unhandled_rejection' }); this.stop().then(() => process.exit(1)); }); } /** * Get application health status */ getHealthStatus() { if (!this.mcpServer) { return { healthy: false, reason: 'Server not initialized' }; } try { const serverHealth = this.mcpServer.getHealthStatus(); const apiHealth = this.apiClient.getHealthStatus(); const authHealth = this.authManager.getCacheStats(); return { healthy: true, timestamp: new Date().toISOString(), server: serverHealth, api: apiHealth, auth: authHealth, uptime: process.uptime(), memory: process.memoryUsage(), version: this.config.get('MCP_SERVER_VERSION') }; } catch (error) { return { healthy: false, reason: error.message, timestamp: new Date().toISOString() }; } } } /** * Main execution function */ async function main() { const app = new HealthcareMcpServerApp(); try { // Initialize application await app.initialize(); // Start server await app.start(); } catch (error) { logger.error('Application startup failed:', error); ErrorHandler.logError(error, logger, { context: 'application_startup' }); process.exit(1); } } // Run the application if this file is executed directly if (import.meta.url === `file://${process.argv[1]}`) { main().catch((error) => { console.error('Fatal error:', error); process.exit(1); }); } export { HealthcareMcpServerApp };