@alcyone-labs/simple-mcp-logger
Version:
Logging solution for MCP servers. Prevents console output from corrupting MCP protocol communication. Drop-in replacement for console, Winston, and Pino with automatic STDOUT suppression in MCP mode.
1 lines • 14.7 kB
Source Map (JSON)
{"version":3,"file":"index.mjs","sources":["../../src/adapters/winston.ts","../../src/adapters/pino.ts"],"sourcesContent":["import { Logger, type LogLevel } from '../SimpleMcpLogger.js';\n\nimport TransportStream from 'winston-transport';\n\ninterface TransportStreamOptions {\n level?: string;\n silent?: boolean;\n handleExceptions?: boolean;\n handleRejections?: boolean;\n [key: string]: any;\n}\n\n/**\n * Winston transport that uses SimpleMcpLogger as the underlying logger\n */\nexport class SimpleMcpWinstonTransport extends TransportStream {\n private logger: Logger;\n private options: TransportStreamOptions;\n\n constructor(options: TransportStreamOptions & {\n mcpMode?: boolean;\n prefix?: string;\n logToFile?: string;\n } = {}) {\n super(options);\n this.options = options;\n\n const level = this.mapWinstonLevelToMcp(options.level || 'info');\n\n this.logger = new Logger({\n level,\n mcpMode: options.mcpMode || false,\n prefix: options.prefix,\n logToFile: options.logToFile\n });\n }\n\n /**\n * Emit method for Winston compatibility\n */\n emit(event: string, ...args: any[]): boolean {\n return super.emit(event, ...args);\n }\n\n /**\n * Map Winston log levels to SimpleMcpLogger levels\n */\n private mapWinstonLevelToMcp(winstonLevel: string): LogLevel {\n const levelMap: Record<string, LogLevel> = {\n 'error': 'error',\n 'warn': 'warn',\n 'info': 'info',\n 'http': 'info',\n 'verbose': 'debug',\n 'debug': 'debug',\n 'silly': 'debug'\n };\n \n return levelMap[winstonLevel] || 'info';\n }\n\n\n\n /**\n * Log method called by Winston\n */\n log(info: any, callback?: () => void): void {\n const level = this.mapWinstonLevelToMcp(info.level);\n const message = info.message || '';\n\n // Extract metadata from the info object, excluding Winston-specific fields\n const { level: _, message: __, timestamp: ___, ...meta } = info;\n\n // Remove any Symbol properties and other Winston internals\n const cleanMeta: any = {};\n for (const [key, value] of Object.entries(meta)) {\n if (typeof key === 'string' && !key.startsWith('Symbol(') && key !== 'splat') {\n cleanMeta[key] = value;\n }\n }\n\n const args = Object.keys(cleanMeta).length > 0 ? [cleanMeta] : [];\n\n switch (level) {\n case 'debug':\n this.logger.debug(message, ...args);\n break;\n case 'info':\n this.logger.info(message, ...args);\n break;\n case 'warn':\n this.logger.warn(message, ...args);\n break;\n case 'error':\n this.logger.error(message, ...args);\n break;\n default:\n this.logger.info(message, ...args);\n }\n\n // Emit the 'logged' event as expected by Winston\n setImmediate(() => {\n this.emit('logged', info);\n });\n\n if (callback) {\n callback();\n }\n }\n\n /**\n * Set MCP mode\n */\n setMcpMode(enabled: boolean): void {\n this.logger.setMcpMode(enabled);\n }\n\n /**\n * Set log level\n */\n setLevel(level: LogLevel): void {\n this.logger.setLevel(level);\n }\n\n /**\n * Set prefix\n */\n setPrefix(prefix: string): void {\n this.logger.setPrefix(prefix);\n }\n\n /**\n * Create child logger\n */\n child(prefix: string): SimpleMcpWinstonTransport {\n const childLogger = this.logger.child(prefix);\n const transport = new SimpleMcpWinstonTransport(this.options);\n transport.logger = childLogger;\n return transport;\n }\n\n /**\n * Get the underlying SimpleMcpLogger instance\n */\n getLogger(): Logger {\n return this.logger;\n }\n\n /**\n * Set log file path\n */\n async setLogFile(filePath: string): Promise<void> {\n await this.logger.setLogFile(filePath);\n }\n\n /**\n * Close file stream\n */\n async close(): Promise<void> {\n await this.logger.close();\n }\n}\n\n/**\n * Factory function to create Winston transport\n */\nexport function createWinstonTransport(options: TransportStreamOptions & {\n mcpMode?: boolean;\n prefix?: string;\n logToFile?: string;\n} = {}): SimpleMcpWinstonTransport {\n return new SimpleMcpWinstonTransport(options);\n}\n","import { Logger, type LogLevel } from '../SimpleMcpLogger.js';\n\n/**\n * Pino transport that uses SimpleMcpLogger as the underlying logger\n */\nexport class SimpleMcpPinoTransport {\n private logger: Logger;\n private options: PinoTransportOptions;\n\n constructor(options: PinoTransportOptions = {}) {\n this.options = options;\n const level = this.mapPinoLevelToMcp(options.level || 'info');\n\n this.logger = new Logger({\n level,\n mcpMode: options.mcpMode || false,\n prefix: options.prefix,\n logToFile: options.logToFile\n });\n }\n\n /**\n * Map Pino log levels to SimpleMcpLogger levels\n */\n private mapPinoLevelToMcp(pinoLevel: string | number): LogLevel {\n if (typeof pinoLevel === 'number') {\n if (pinoLevel >= 60) return 'error';\n if (pinoLevel >= 50) return 'error';\n if (pinoLevel >= 40) return 'warn';\n if (pinoLevel >= 30) return 'info';\n if (pinoLevel >= 20) return 'debug';\n return 'debug';\n }\n \n const levelMap: Record<string, LogLevel> = {\n 'fatal': 'error',\n 'error': 'error',\n 'warn': 'warn',\n 'info': 'info',\n 'debug': 'debug',\n 'trace': 'debug'\n };\n \n return levelMap[pinoLevel] || 'info';\n }\n\n /**\n * Transform function for Pino transport\n */\n transform(chunk: any): void {\n try {\n const logObj = typeof chunk === 'string' ? JSON.parse(chunk) : chunk;\n const level = this.mapPinoLevelToMcp(logObj.level);\n const message = logObj.msg || '';\n\n // Extract metadata from the log object, excluding Pino-specific fields\n const { level: _, msg: __, time: ___, hostname: ____, pid: _____, ...meta } = logObj;\n\n // Remove any other Pino internals that might be present\n const cleanMeta: any = {};\n for (const [key, value] of Object.entries(meta)) {\n if (typeof key === 'string' && !key.startsWith('Symbol(') && key !== 'v') {\n cleanMeta[key] = value;\n }\n }\n\n const args = Object.keys(cleanMeta).length > 0 ? [cleanMeta] : [];\n\n switch (level) {\n case 'debug':\n this.logger.debug(message, ...args);\n break;\n case 'info':\n this.logger.info(message, ...args);\n break;\n case 'warn':\n this.logger.warn(message, ...args);\n break;\n case 'error':\n this.logger.error(message, ...args);\n break;\n default:\n this.logger.info(message, ...args);\n }\n } catch (error) {\n this.logger.error('Failed to parse log message', error);\n }\n }\n\n /**\n * Set MCP mode\n */\n setMcpMode(enabled: boolean): void {\n this.logger.setMcpMode(enabled);\n }\n\n /**\n * Set log level\n */\n setLevel(level: LogLevel): void {\n this.logger.setLevel(level);\n }\n\n /**\n * Set prefix\n */\n setPrefix(prefix: string): void {\n this.logger.setPrefix(prefix);\n }\n\n /**\n * Create child logger\n */\n child(prefix: string): SimpleMcpPinoTransport {\n const childLogger = this.logger.child(prefix);\n const transport = new SimpleMcpPinoTransport(this.options);\n transport.logger = childLogger;\n return transport;\n }\n\n /**\n * Get the underlying SimpleMcpLogger instance\n */\n getLogger(): Logger {\n return this.logger;\n }\n\n /**\n * Set log file path\n */\n async setLogFile(filePath: string): Promise<void> {\n await this.logger.setLogFile(filePath);\n }\n\n /**\n * Close file stream\n */\n async close(): Promise<void> {\n await this.logger.close();\n }\n}\n\n/**\n * Options for Pino transport\n */\nexport interface PinoTransportOptions {\n level?: LogLevel;\n mcpMode?: boolean;\n prefix?: string;\n logToFile?: string;\n}\n\n/**\n * Factory function to create Pino transport\n */\nexport function createPinoTransport(options: PinoTransportOptions = {}): SimpleMcpPinoTransport {\n return new SimpleMcpPinoTransport(options);\n}\n\n/**\n * Create a Pino destination that uses SimpleMcpLogger\n */\nexport function createPinoDestination(options: PinoTransportOptions = {}) {\n const transport = new SimpleMcpPinoTransport(options);\n \n return {\n write(chunk: any) {\n transport.transform(chunk);\n },\n async end() {\n await transport.close();\n },\n async destroy() {\n await transport.close();\n }\n };\n}\n\n/**\n * Create a Pino logger that uses SimpleMcpLogger as the underlying transport\n * Note: This function requires Pino to be installed and available in the environment\n *\n * @deprecated This function uses dynamic imports which are not bundler-friendly.\n * Instead, import Pino directly in your application and use createPinoDestination:\n *\n * ```typescript\n * import pino from 'pino';\n * import { createPinoDestination } from '@alcyone-labs/simple-mcp-logger';\n *\n * const destination = createPinoDestination({ level: 'info' });\n * const logger = pino({ level: 'info' }, destination);\n * ```\n */\nexport function createPinoLogger(_options: PinoTransportOptions & {\n name?: string;\n} = {}) {\n // Check if we're in a browser environment\n if (typeof window !== 'undefined') {\n throw new Error('createPinoLogger is not supported in browser environments. Use createPinoDestination with a browser-compatible Pino build instead.');\n }\n\n // Throw an error encouraging users to import Pino directly for better bundling\n throw new Error(\n 'createPinoLogger is deprecated for bundling compatibility. ' +\n 'Please import Pino directly and use createPinoDestination instead:\\n\\n' +\n 'import pino from \\'pino\\';\\n' +\n 'import { createPinoDestination } from \\'@alcyone-labs/simple-mcp-logger\\';\\n\\n' +\n 'const destination = createPinoDestination({ level: \\'info\\' });\\n' +\n 'const logger = pino({ level: \\'info\\' }, destination);'\n );\n}\n"],"names":[],"mappings":"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"}