UNPKG

@civic/nexus-bridge

Version:

Stdio <-> HTTP/SSE MCP bridge with Civic auth handling

118 lines 4.47 kB
/** * index.ts * * Main entry point for the Nexus Bridge. Initializes the bridge, * handles process signals, and manages graceful shutdown. * Now uses the new Bridge implementation for improved reliability. */ import { Bridge } from './bridge.js'; import * as configVars from './config.js'; import { version } from './version.js'; import { runInstaller, AVAILABLE_TARGETS } from './installer/index.js'; // Redirect console.log to stderr to avoid interfering with MCP JSON messages // Note: Our custom logger (utils/logger.ts) already writes directly to stderr, but // these redirects ensure that any direct console.log calls or third-party libraries // that use console methods also have their output redirected to stderr. This provides // a comprehensive solution where ALL output is consistently sent to stderr regardless // of its source, maintaining clean stdout for the MCP protocol. console.log = (...args) => { process.stderr.write(`LOG: ${args.join(' ')}\n`); }; console.error = (...args) => { process.stderr.write(`ERROR: ${args.join(' ')}\n`); }; console.warn = (...args) => { process.stderr.write(`WARN: ${args.join(' ')}\n`); }; console.info = (...args) => { process.stderr.write(`INFO: ${args.join(' ')}\n`); }; // Log configuration values const logConfig = () => { console.log(`Civic Nexus Bridge v${version} (Node ${process.version})`); console.log('Configuration:'); console.log('MCP_REMOTE_URL:', configVars.REMOTE_MCP_URL); console.log('CIVIC_AUTH_URL:', configVars.CIVIC_AUTH_URL); console.log('CLIENT_ID:', configVars.CLIENT_ID); console.log('REQUEST_TIMEOUT_MS:', configVars.REQUEST_TIMEOUT_MS); console.log('NO_LOGIN:', configVars.NO_LOGIN); console.log('NO_AUTH_CAPTURE:', configVars.NO_AUTH_CAPTURE); }; let bridge = null; let isShuttingDown = false; // Prevent double shutdown calls /** * Handle installer mode when 'install' argument is passed */ async function handleInstaller() { const args = process.argv.slice(2); if (args.length > 0 && args[0] === 'install') { if (args.length < 2) { console.error('Error: Missing installation target. Use: nexus-bridge install <target>'); console.error(`Available targets: ${AVAILABLE_TARGETS.join(', ')}`); throw new Error('Missing installation target'); } const target = args[1]; try { await runInstaller(target); // Successfully completed installation return true; } catch (error) { console.error(`Error during installation: ${error}`); throw error; } return true; } return false; } async function main() { // Check if we should run in installer mode const isInstallerMode = await handleInstaller(); if (isInstallerMode) return; logConfig(); // Normal bridge operation bridge = new Bridge(); try { await bridge.start(); } catch (error) { console.error("Fatal error during bridge startup:", error); throw new Error(`Bridge startup failed: ${error instanceof Error ? error.message : String(error)}`); } } async function shutdown(signal) { if (isShuttingDown) return; isShuttingDown = true; console.log(`\nReceived ${signal}. Shutting down gracefully...`); if (bridge) { await bridge.shutdown(); } console.log("Shutdown complete."); // Node will exit naturally after all event handlers complete } // Handle termination signals process.on('SIGINT', () => shutdown('SIGINT')); process.on('SIGTERM', () => shutdown('SIGTERM')); // Basic error handling process.on('uncaughtException', (error, origin) => { console.error(`\nFATAL UNCAUGHT EXCEPTION (${origin}):`, error); // Attempt graceful shutdown, but it might fail if state is corrupted shutdown('uncaughtException').catch(() => { console.error('Failed to shutdown gracefully after uncaught exception'); throw error; }); }); process.on('unhandledRejection', (reason) => { console.error('\nFATAL UNHANDLED REJECTION:'); console.error('Reason:', reason); // Attempt graceful shutdown shutdown('unhandledRejection').catch(() => { console.error('Failed to shutdown gracefully after unhandled rejection'); throw reason instanceof Error ? reason : new Error(String(reason)); }); }); // Start the application main(); //# sourceMappingURL=index.js.map