/**
* Logging utility for MCP server
* Logs to stderr to avoid interfering with stdio protocol
*/
export enum LogLevel {
DEBUG = 0,
INFO = 1,
WARN = 2,
ERROR = 3,
}
class Logger {
private logLevel: LogLevel = LogLevel.INFO;
setLogLevel(level: LogLevel): void {
this.logLevel = level;
}
private formatMessage(level: string, message: string, context?: Record<string, unknown>): string {
const timestamp = new Date().toISOString();
const contextStr = context ? ` ${JSON.stringify(context)}` : '';
return `[${timestamp}] [${level}] ${message}${contextStr}`;
}
private log(level: LogLevel, levelName: string, message: string, context?: Record<string, unknown>): void {
if (level >= this.logLevel) {
console.error(this.formatMessage(levelName, message, context));
}
}
debug(message: string, context?: Record<string, unknown>): void {
this.log(LogLevel.DEBUG, 'DEBUG', message, context);
}
info(message: string, context?: Record<string, unknown>): void {
this.log(LogLevel.INFO, 'INFO', message, context);
}
warn(message: string, context?: Record<string, unknown>): void {
this.log(LogLevel.WARN, 'WARN', message, context);
}
error(message: string, error?: Error | unknown, context?: Record<string, unknown>): void {
const errorContext = {
...context,
...(error instanceof Error
? {
errorName: error.name,
errorMessage: error.message,
errorStack: error.stack,
}
: { error: String(error) }),
};
this.log(LogLevel.ERROR, 'ERROR', message, errorContext);
}
}
// Export singleton instance
export const logger = new Logger();
// Export convenience methods
export const debug = logger.debug.bind(logger);
export const info = logger.info.bind(logger);
export const warn = logger.warn.bind(logger);
export const error = logger.error.bind(logger);
export const setLogLevel = logger.setLogLevel.bind(logger);