logger.ts•2.71 kB
/**
* Logger Module
*
* This module provides a consistent logging interface for all MCP components.
* It handles log formatting, error handling, and ensures log output is directed
* to the appropriate destination based on the runtime environment.
*/
import winston from 'winston';
import path from 'path';
import fs from 'fs';
// Ensure logs directory exists
const logsDir = path.join(process.cwd(), 'logs');
if (!fs.existsSync(logsDir)) {
fs.mkdirSync(logsDir, { recursive: true });
}
// Special handling for stdio mode to ensure stdout stays clean for JSON-RPC
const isStdioMode = process.env.USE_STDIO_TRANSPORT === 'true';
const isDebugStdio = process.env.DEBUG_STDIO === 'true';
// Create base format that works with TypeScript
const baseFormat = winston.format.combine(
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
winston.format.errors({ stack: true }),
winston.format.json()
);
// Create logger with appropriate transports
const logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'error',
format: baseFormat,
defaultMeta: { service: 'mcp-server' },
transports: [
// Always log to files
new winston.transports.File({ filename: path.join(logsDir, 'error.log'), level: 'error' }),
new winston.transports.File({ filename: path.join(logsDir, 'combined.log') })
]
});
// Handle console output based on environment
if (process.env.NODE_ENV !== 'production' || process.env.CONSOLE_LOGGING === 'true') {
// Only add console/stderr logging if NOT in standard stdio mode
if (!isStdioMode) {
// Use console transport in normal (non-stdio) mode
logger.add(new winston.transports.Console({
format: winston.format.combine(
winston.format.colorize(),
winston.format.simple()
)
}));
} else if (isDebugStdio) {
// If in stdio mode AND debug is specifically enabled, log simple format to stderr
logger.add(new winston.transports.Stream({
stream: process.stderr,
format: winston.format.combine(
winston.format.simple() // Keep stderr logs simple
)
}));
}
// Implicit else: If isStdioMode is true and isDebugStdio is false, add NO console/stderr transport.
}
// Custom logger interface
export interface MCPLogger {
debug: (message: string, meta?: Record<string, any>) => void;
info: (message: string, meta?: Record<string, any>) => void;
warn: (message: string, meta?: Record<string, any>) => void;
error: (message: string, meta?: Record<string, any>) => void;
child: (options: Record<string, any>) => MCPLogger;
}
// Export the winston logger with MCPLogger interface
export { logger };
// Export default logger for convenience
export default logger;