UNPKG

@nutrient-sdk/document-engine-mcp-server

Version:
148 lines (147 loc) 5.52 kB
import { getEnvironment } from './Environment.js'; import * as process from 'node:process'; export var LogLevel; (function (LogLevel) { LogLevel[LogLevel["ERROR"] = 0] = "ERROR"; LogLevel[LogLevel["WARNING"] = 1] = "WARNING"; LogLevel[LogLevel["INFO"] = 2] = "INFO"; LogLevel[LogLevel["DEBUG"] = 3] = "DEBUG"; })(LogLevel || (LogLevel = {})); class Logger { logLevel; serviceName; mcpServer = null; constructor(serviceName = 'document-engine-mcp') { this.serviceName = serviceName; // Parse log level from validated environment try { const env = getEnvironment(); switch (env.LOG_LEVEL) { case 'ERROR': this.logLevel = LogLevel.ERROR; break; case 'WARN': case 'WARNING': this.logLevel = LogLevel.WARNING; break; case 'INFO': this.logLevel = LogLevel.INFO; break; case 'DEBUG': this.logLevel = LogLevel.DEBUG; break; default: this.logLevel = LogLevel.INFO; } } catch { // If environment validation fails, use default log level this.logLevel = LogLevel.INFO; } } /** * Set the MCP server instance to enable client logging */ setMCPServer(server) { this.mcpServer = server; } // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Context can be any type of metadata formatLogEntry(level, message, context) { const entry = { timestamp: new Date().toISOString(), level, message: `[${this.serviceName}] ${message}`, }; if (context !== undefined) { entry.context = context; } return JSON.stringify(entry); } shouldLog(level) { return level <= this.logLevel; } writeLog(level, stderrLevel, message, // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Context can be any type of metadata context) { const logLine = this.formatLogEntry(stderrLevel, message, context); const env = getEnvironment(); const isServerConnected = this.mcpServer?.isConnected(); const isStdIOMode = env.MCP_TRANSPORT === 'stdio'; // Send to server notifications when connected if (isServerConnected) { const params = { level, data: `[${this.serviceName}] ${message}`, }; try { this.mcpServer.server.sendLoggingMessage(params); } catch { // Fall through to console fallback if notification fails } } // Console output handling based on mode and connection status if (isStdIOMode) { if (!isServerConnected) { process.stderr.write(logLine + '\n'); } } else { // HTTP mode: write to stderr for errors, stdout for other log levels if (level === 'error') { process.stderr.write(logLine + '\n'); } else { process.stdout.write(logLine + '\n'); } } } // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Context can be any type of metadata error(message, context) { if (!this.shouldLog(LogLevel.ERROR)) return; this.writeLog('error', 'ERROR', message, context); } // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Context can be any type of metadata warn(message, context) { if (this.shouldLog(LogLevel.WARNING)) { this.writeLog('warning', 'WARNING', message, context); } } // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Context can be any type of metadata info(message, context) { if (this.shouldLog(LogLevel.INFO)) { this.writeLog('info', 'INFO', message, context); } } // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Context can be any type of metadata debug(message, context) { if (this.shouldLog(LogLevel.DEBUG)) { this.writeLog('debug', 'DEBUG', message, context); } } // Convenience methods for common logging patterns // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Context can be any type of metadata request(method, url, context) { this.info(`Request: ${method?.toUpperCase()} ${url}`, context); } // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Context can be any type of metadata response(status, url, context) { const level = status >= 400 ? LogLevel.ERROR : LogLevel.INFO; const message = `Response: ${status} ${url}`; if (level === LogLevel.ERROR) { this.error(message, context); } else { this.info(message, context); } } // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Context can be any type of metadata retry(attempt, maxRetries, delay, context) { this.warn(`Retry attempt ${attempt}/${maxRetries} after ${delay}ms`, context); } } // Create a singleton logger instance export const logger = new Logger(); // Export the Logger class for testing export { Logger };