logger.ts•2.6 kB
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
export type LogLevel = 'debug' | 'info' | 'warning' | 'error';
class Logger {
private server?: McpServer;
private currentLevel: LogLevel = 'info';
private readonly levels: Record<LogLevel, number> = {
debug: 0,
info: 1,
warning: 2,
error: 3,
};
setServer(server: McpServer): void {
this.server = server;
}
setLevel(level: string): void {
if (this.isValidLevel(level)) {
this.currentLevel = level as LogLevel;
}
}
private isValidLevel(level: string): level is LogLevel {
return level in this.levels;
}
private shouldLog(level: LogLevel): boolean {
return this.levels[level] >= this.levels[this.currentLevel];
}
private async log(level: LogLevel, loggerName: string, data: unknown): Promise<void> {
if (!this.shouldLog(level)) {
return;
}
try {
const s = this.server as unknown;
const maybeNested = (s as { server?: unknown })?.server ?? s;
type SendCapable = { sendLoggingMessage?: (p: unknown) => Promise<void> };
type NotifyCapable = { notification?: (p: unknown) => Promise<void> };
const hasSend = (o: unknown): o is SendCapable =>
typeof (o as SendCapable)?.sendLoggingMessage === 'function';
const hasNotify = (o: unknown): o is NotifyCapable =>
typeof (o as NotifyCapable)?.notification === 'function';
if (hasSend(maybeNested)) {
await maybeNested.sendLoggingMessage({
level,
logger: loggerName,
data,
});
} else if (hasNotify(maybeNested)) {
await maybeNested.notification({
method: 'notifications/message',
params: { level, logger: loggerName, data },
});
}
} catch {}
const timestamp = new Date().toISOString();
const payload = typeof data === 'object' ? JSON.stringify(data) : String(data);
// eslint-disable-next-line no-console
console.log(`[${timestamp}] ${level.toUpperCase()} ${loggerName}: ${payload}`);
}
async debug(loggerName: string, data?: unknown): Promise<void> {
await this.log('debug', loggerName, data ?? {});
}
async info(loggerName: string, data?: unknown): Promise<void> {
await this.log('info', loggerName, data ?? {});
}
async warning(loggerName: string, data?: unknown): Promise<void> {
await this.log('warning', loggerName, data ?? {});
}
async error(loggerName: string, data?: unknown): Promise<void> {
await this.log('error', loggerName, data ?? {});
}
}
export const logger = new Logger();