Skip to main content
Glama
cbunting99

MCP Code Analysis & Quality Server

by cbunting99
index.ts5.43 kB
// Copyright 2025 Chris Bunting // Brief: Logging infrastructure for MCP Code Analysis & Quality Server // Scope: Centralized logging system with multiple output support import { LoggerInterface, LogLevel } from '@mcp-code-analysis/shared-types'; export interface LogEntry { timestamp: Date; level: LogLevel; message: string; meta?: Record<string, any>; context?: string; } export interface LogTransport { log(entry: LogEntry): Promise<void>; flush(): Promise<void>; } export class ConsoleTransport implements LogTransport { async log(entry: LogEntry): Promise<void> { const timestamp = entry.timestamp.toISOString(); const level = entry.level.toUpperCase(); const context = entry.context ? `[${entry.context}]` : ''; const meta = entry.meta ? ` ${JSON.stringify(entry.meta)}` : ''; const logMessage = `${timestamp} ${level}${context}: ${entry.message}${meta}`; switch (entry.level) { case LogLevel.ERROR: console.error(logMessage); break; case LogLevel.WARN: console.warn(logMessage); break; case LogLevel.INFO: console.info(logMessage); break; case LogLevel.DEBUG: console.debug(logMessage); break; } } async flush(): Promise<void> { // Console transport doesn't need flushing } } export class FileTransport implements LogTransport { private filePath: string; private fs: typeof import('fs'); private path: typeof import('path'); constructor(filePath: string) { this.filePath = filePath; this.fs = require('fs'); this.path = require('path'); this.ensureLogDirectory(); } private ensureLogDirectory(): void { const dir = this.path.dirname(this.filePath); if (!this.fs.existsSync(dir)) { this.fs.mkdirSync(dir, { recursive: true }); } } async log(entry: LogEntry): Promise<void> { const timestamp = entry.timestamp.toISOString(); const level = entry.level.toUpperCase(); const context = entry.context ? `[${entry.context}]` : ''; const meta = entry.meta ? ` ${JSON.stringify(entry.meta)}` : ''; const logMessage = `${timestamp} ${level}${context}: ${entry.message}${meta}\n`; try { this.fs.appendFileSync(this.filePath, logMessage); } catch (error) { console.error('Failed to write to log file:', error); } } async flush(): Promise<void> { // File transport doesn't need explicit flushing } } export class Logger implements LoggerInterface { private context?: string; private transports: LogTransport[] = []; private minLevel: LogLevel; constructor( minLevel: LogLevel = LogLevel.INFO, context?: string ) { this.minLevel = minLevel; this.context = context; } addTransport(transport: LogTransport): void { this.transports.push(transport); } setContext(context: string): void { this.context = context; } private shouldLog(level: LogLevel): boolean { const levels = [LogLevel.DEBUG, LogLevel.INFO, LogLevel.WARN, LogLevel.ERROR]; return levels.indexOf(level) >= levels.indexOf(this.minLevel); } private async log( level: LogLevel, message: string, meta?: Record<string, any> ): Promise<void> { if (!this.shouldLog(level)) { return; } const entry: LogEntry = { timestamp: new Date(), level, message, meta, context: this.context }; for (const transport of this.transports) { try { await transport.log(entry); } catch (error) { console.error('Log transport error:', error); } } } debug(message: string, ...args: any[]): void { const meta = args.length > 0 ? { args } : undefined; this.log(LogLevel.DEBUG, message, meta).catch(console.error); } info(message: string, ...args: any[]): void { const meta = args.length > 0 ? { args } : undefined; this.log(LogLevel.INFO, message, meta).catch(console.error); } warn(message: string, ...args: any[]): void { const meta = args.length > 0 ? { args } : undefined; this.log(LogLevel.WARN, message, meta).catch(console.error); } error(message: string, ...args: any[]): void { const meta = args.length > 0 ? { args } : undefined; this.log(LogLevel.ERROR, message, meta).catch(console.error); } child(context: string): Logger { const fullContext = this.context ? `${this.context}:${context}` : context; const childLogger = new Logger(this.minLevel, fullContext); childLogger.transports = [...this.transports]; return childLogger; } async flush(): Promise<void> { for (const transport of this.transports) { try { await transport.flush(); } catch (error) { console.error('Error flushing log transport:', error); } } } } // Factory functions export function createLogger( minLevel: LogLevel = LogLevel.INFO, context?: string ): Logger { const logger = new Logger(minLevel, context); // Add default console transport logger.addTransport(new ConsoleTransport()); return logger; } export function createFileLogger( filePath: string, minLevel: LogLevel = LogLevel.INFO, context?: string ): Logger { const logger = new Logger(minLevel, context); // Add console and file transports logger.addTransport(new ConsoleTransport()); logger.addTransport(new FileTransport(filePath)); return logger; }

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/cbunting99/mcp-code-analysis-server'

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