Skip to main content
Glama
cameronsjo

MCP Server Template

by cameronsjo
logger.ts3.16 kB
/** * Structured logging with RFC 5424 levels * * Logs to stderr for MCP protocol compatibility (stdout is for protocol messages). * Optionally logs to rotating daily files. */ import { appendFileSync, mkdirSync, existsSync } from 'node:fs'; import { join } from 'node:path'; import { getConfig } from '../config/index.js'; import type { LogLevel, LogEntry } from '../types/index.js'; const LOG_LEVEL_PRIORITY: Record<LogLevel, number> = { debug: 0, info: 1, notice: 2, warning: 3, error: 4, critical: 5, }; /** * Logger class with structured output and file rotation */ export class Logger { private readonly name: string; private readonly minLevel: number; private readonly logToFile: boolean; private readonly logDir: string; constructor(name: string) { const config = getConfig(); this.name = name; this.minLevel = LOG_LEVEL_PRIORITY[config.logLevel]; this.logToFile = config.logToFile; this.logDir = config.logDir; if (this.logToFile) { this.ensureLogDir(); } } private ensureLogDir(): void { if (!existsSync(this.logDir)) { mkdirSync(this.logDir, { recursive: true }); } } private getLogFilePath(): string { const date = new Date().toISOString().split('T')[0]; return join(this.logDir, `${getConfig().serverName}-${date}.log`); } private shouldLog(level: LogLevel): boolean { return LOG_LEVEL_PRIORITY[level] >= this.minLevel; } private formatEntry(entry: LogEntry): string { return JSON.stringify(entry); } private log(level: LogLevel, message: string, data?: Record<string, unknown>): void { if (!this.shouldLog(level)) { return; } const entry: LogEntry = { level, logger: this.name, message, data, timestamp: new Date().toISOString(), }; const formatted = this.formatEntry(entry); // Always log to stderr for MCP compatibility console.error(formatted); // Optionally log to file if (this.logToFile) { try { appendFileSync(this.getLogFilePath(), formatted + '\n'); } catch { // Silently fail file logging to avoid disrupting MCP protocol } } } debug(message: string, data?: Record<string, unknown>): void { this.log('debug', message, data); } info(message: string, data?: Record<string, unknown>): void { this.log('info', message, data); } notice(message: string, data?: Record<string, unknown>): void { this.log('notice', message, data); } warning(message: string, data?: Record<string, unknown>): void { this.log('warning', message, data); } error(message: string, data?: Record<string, unknown>): void { this.log('error', message, data); } critical(message: string, data?: Record<string, unknown>): void { this.log('critical', message, data); } /** * Create a child logger with a sub-namespace */ child(subName: string): Logger { return new Logger(`${this.name}/${subName}`); } } /** * Create a logger instance for a module */ export function createLogger(name: string): Logger { return new Logger(`${getConfig().serverName}/${name}`); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/cameronsjo/mcp-server-template'

If you have feedback or need assistance with the MCP directory API, please join our Discord server