Files
mcp-tool/server.js
nasir@endelospay.com 8c74b0e23f first
2025-07-11 20:22:12 +05:00

273 lines
7.6 KiB
JavaScript

#!/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 };