Skip to main content
Glama

Theneo MCP Server

by atombreak
logger.tsβ€’3.35 kB
/** * Structured logging utility with automatic secret masking * Logs to stderr to avoid interfering with MCP protocol (stdout) */ type LogLevel = "debug" | "info" | "warn" | "error"; interface LogEntry { level: LogLevel; message: string; timestamp: string; data?: unknown; } /** * Patterns that might indicate secrets * These will be masked in log output */ const SECRET_PATTERNS = [ /api[_-]?key["\s:=]+([a-zA-Z0-9_\-]+)/gi, /token["\s:=]+([a-zA-Z0-9_\-\.]+)/gi, /bearer\s+([a-zA-Z0-9_\-\.]+)/gi, /password["\s:=]+([^\s"']+)/gi, /secret["\s:=]+([^\s"']+)/gi, /(sk|pk)_[a-z]+_[a-zA-Z0-9]{20,}/gi, ]; /** * Mask sensitive data in strings */ function maskSecrets(text: string): string { let masked = text; for (const pattern of SECRET_PATTERNS) { masked = masked.replace(pattern, (match) => { // Keep first 4 and last 4 chars visible if long enough if (match.length > 16) { const parts = match.split(/[:=\s]+/); if (parts.length > 1) { const value = parts[parts.length - 1]; const prefix = match.substring(0, match.indexOf(value)); if (value.length > 8) { return `${prefix}${value.substring(0, 4)}${"*".repeat(value.length - 8)}${value.substring(value.length - 4)}`; } } } return match.replace(/[a-zA-Z0-9]/g, "*"); }); } return masked; } /** * Mask secrets in objects (recursive) */ function maskSecretsInObject(obj: unknown): unknown { if (typeof obj === "string") { return maskSecrets(obj); } if (Array.isArray(obj)) { return obj.map(maskSecretsInObject); } if (obj && typeof obj === "object") { const masked: Record<string, unknown> = {}; for (const [key, value] of Object.entries(obj)) { // Explicitly mask known secret fields const lowerKey = key.toLowerCase(); if ( lowerKey.includes("key") || lowerKey.includes("token") || lowerKey.includes("secret") || lowerKey.includes("password") ) { masked[key] = typeof value === "string" && value.length > 4 ? "***REDACTED***" : value; } else { masked[key] = maskSecretsInObject(value); } } return masked; } return obj; } /** * Format and write log entry to stderr */ function writeLog(entry: LogEntry): void { const maskedEntry = { ...entry, message: maskSecrets(entry.message), data: entry.data ? maskSecretsInObject(entry.data) : undefined, }; // Write to stderr (stdout is reserved for MCP protocol) console.error(JSON.stringify(maskedEntry)); } export const logger = { debug(message: string, data?: unknown): void { if (process.env.DEBUG) { writeLog({ level: "debug", message, timestamp: new Date().toISOString(), data, }); } }, info(message: string, data?: unknown): void { writeLog({ level: "info", message, timestamp: new Date().toISOString(), data, }); }, warn(message: string, data?: unknown): void { writeLog({ level: "warn", message, timestamp: new Date().toISOString(), data, }); }, error(message: string, data?: unknown): void { writeLog({ level: "error", message, timestamp: new Date().toISOString(), data, }); }, };

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/atombreak/theneo-mcp'

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