export interface LogContext {
[key: string]: any;
}
export enum LogLevel {
DEBUG = 'debug',
INFO = 'info',
WARN = 'warn',
ERROR = 'error'
}
/**
* FastMCP-compliant logging utility
*
* CRITICAL RULES:
* 1. ONLY use startup logging BEFORE server.start()
* 2. NEVER use console.* during MCP protocol operations
* 3. Use context.log inside tool execution only
*/
export class Logger {
private readonly component: string;
constructor(component: string = 'FastMCP') {
this.component = component;
}
/**
* Startup logging ONLY - use BEFORE server.start()
* After server.start(), any console output breaks MCP JSON-RPC protocol
*/
startup = {
debug: (message: string) => {
if (process.env.DEBUG === 'true') {
console.debug(`[${this.component}] ${message}`);
}
},
info: (message: string) => {
if (process.env.DEBUG === 'true') {
console.debug(`[${this.component}] ${message}`);
}
},
warn: (message: string) => {
if (process.env.DEBUG === 'true') {
console.debug(`[${this.component}] WARN: ${message}`);
}
},
error: (message: string) => {
// Critical startup errors can go to stderr
console.error(`[${this.component}] ERROR: ${message}`);
}
};
/**
* @deprecated Use context.log inside tool execution instead
* This exists only for backwards compatibility during transition
*/
internal = this.startup;
}
/**
* Type definition for FastMCP context.log
* Use this inside tool execution functions
*/
export interface FastMCPLog {
debug(message: string, data?: any): void;
info(message: string, data?: any): void;
warn(message: string, data?: any): void;
error(message: string, data?: any): void;
}
/**
* Helper function to safely log during tool execution
* Usage: safeLog(log, 'info', 'Message', { data });
*/
export function safeLog(
log: FastMCPLog | undefined,
level: keyof FastMCPLog,
message: string,
data?: any
): void {
try {
log?.[level](message, data);
} catch (error) {
// Silently fail - don't break MCP protocol
}
}
export default Logger;