UNPKG

@mickdarling/dollhousemcp

Version:

DollhouseMCP - A Model Context Protocol (MCP) server that enables dynamic AI persona management from markdown files, allowing Claude and other compatible AI assistants to activate and switch between different behavioral personas.

91 lines 9.68 kB
/** * MCP-safe logger that avoids writing to stdout/stderr during protocol communication * * In MCP servers, stdout and stderr are reserved for JSON-RPC protocol messages. * Any non-protocol output will cause "Unexpected token" errors in the MCP client. * * This logger: * - Writes to stderr ONLY during server initialization (before MCP connection) * - Stores all logs in memory during runtime * - Provides methods to retrieve logs via MCP tools if needed */ class MCPLogger { logs = []; maxLogs = 1000; isMCPConnected = false; /** * Call this after MCP connection is established to stop console output */ setMCPConnected() { this.isMCPConnected = true; } /** * Internal logging method */ log(level, message, data) { const entry = { timestamp: new Date(), level, message, data }; // Store in memory this.logs.push(entry); if (this.logs.length > this.maxLogs) { this.logs.shift(); } // Only write to console during initialization if (!this.isMCPConnected) { // Check NODE_ENV inside the method to ensure it's evaluated at runtime const isTest = process.env.NODE_ENV === 'test'; if (!isTest) { const prefix = `[${entry.timestamp.toISOString()}] [${level.toUpperCase()}]`; const fullMessage = data ? `${prefix} ${message} ${JSON.stringify(data)}` : `${prefix} ${message}`; // During initialization, we can use console if (level === 'error') { console.error(fullMessage); } else if (level === 'warn') { console.warn(fullMessage); } else { // For MCP, even during init, avoid stdout for info/debug console.error(fullMessage); } } } } debug(message, data) { this.log('debug', message, data); } info(message, data) { this.log('info', message, data); } warn(message, data) { this.log('warn', message, data); } error(message, data) { this.log('error', message, data); } /** * Get recent logs (for MCP tools to retrieve) */ getLogs(count = 100, level) { let filtered = this.logs; if (level) { filtered = this.logs.filter(log => log.level === level); } return filtered.slice(-count); } /** * Clear logs */ clearLogs() { this.logs = []; } } // Singleton instance export const logger = new MCPLogger(); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9nZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL2xvZ2dlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7OztHQVVHO0FBU0gsTUFBTSxTQUFTO0lBQ0wsSUFBSSxHQUFlLEVBQUUsQ0FBQztJQUN0QixPQUFPLEdBQUcsSUFBSSxDQUFDO0lBQ2YsY0FBYyxHQUFHLEtBQUssQ0FBQztJQUUvQjs7T0FFRztJQUNJLGVBQWU7UUFDcEIsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUM7SUFDN0IsQ0FBQztJQUVEOztPQUVHO0lBQ0ssR0FBRyxDQUFDLEtBQXdCLEVBQUUsT0FBZSxFQUFFLElBQVU7UUFDL0QsTUFBTSxLQUFLLEdBQWE7WUFDdEIsU0FBUyxFQUFFLElBQUksSUFBSSxFQUFFO1lBQ3JCLEtBQUs7WUFDTCxPQUFPO1lBQ1AsSUFBSTtTQUNMLENBQUM7UUFFRixrQkFBa0I7UUFDbEIsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDdEIsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDcEMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNwQixDQUFDO1FBRUQsOENBQThDO1FBQzlDLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7WUFDekIsdUVBQXVFO1lBQ3ZFLE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxLQUFLLE1BQU0sQ0FBQztZQUMvQyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7Z0JBQ1osTUFBTSxNQUFNLEdBQUcsSUFBSSxLQUFLLENBQUMsU0FBUyxDQUFDLFdBQVcsRUFBRSxNQUFNLEtBQUssQ0FBQyxXQUFXLEVBQUUsR0FBRyxDQUFDO2dCQUM3RSxNQUFNLFdBQVcsR0FBRyxJQUFJO29CQUN0QixDQUFDLENBQUMsR0FBRyxNQUFNLElBQUksT0FBTyxJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUU7b0JBQ2hELENBQUMsQ0FBQyxHQUFHLE1BQU0sSUFBSSxPQUFPLEVBQUUsQ0FBQztnQkFFM0IsNENBQTRDO2dCQUM1QyxJQUFJLEtBQUssS0FBSyxPQUFPLEVBQUUsQ0FBQztvQkFDdEIsT0FBTyxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsQ0FBQztnQkFDN0IsQ0FBQztxQkFBTSxJQUFJLEtBQUssS0FBSyxNQUFNLEVBQUUsQ0FBQztvQkFDNUIsT0FBTyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztnQkFDNUIsQ0FBQztxQkFBTSxDQUFDO29CQUNOLHlEQUF5RDtvQkFDekQsT0FBTyxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsQ0FBQztnQkFDN0IsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVNLEtBQUssQ0FBQyxPQUFlLEVBQUUsSUFBVTtRQUN0QyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDbkMsQ0FBQztJQUVNLElBQUksQ0FBQyxPQUFlLEVBQUUsSUFBVTtRQUNyQyxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDbEMsQ0FBQztJQUVNLElBQUksQ0FBQyxPQUFlLEVBQUUsSUFBVTtRQUNyQyxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDbEMsQ0FBQztJQUVNLEtBQUssQ0FBQyxPQUFlLEVBQUUsSUFBVTtRQUN0QyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDbkMsQ0FBQztJQUVEOztPQUVHO0lBQ0ksT0FBTyxDQUFDLEtBQUssR0FBRyxHQUFHLEVBQUUsS0FBeUI7UUFDbkQsSUFBSSxRQUFRLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQztRQUN6QixJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ1YsUUFBUSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssS0FBSyxLQUFLLENBQUMsQ0FBQztRQUMxRCxDQUFDO1FBQ0QsT0FBTyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDaEMsQ0FBQztJQUVEOztPQUVHO0lBQ0ksU0FBUztRQUNkLElBQUksQ0FBQyxJQUFJLEdBQUcsRUFBRSxDQUFDO0lBQ2pCLENBQUM7Q0FDRjtBQUVELHFCQUFxQjtBQUNyQixNQUFNLENBQUMsTUFBTSxNQUFNLEdBQUcsSUFBSSxTQUFTLEVBQUUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogTUNQLXNhZmUgbG9nZ2VyIHRoYXQgYXZvaWRzIHdyaXRpbmcgdG8gc3Rkb3V0L3N0ZGVyciBkdXJpbmcgcHJvdG9jb2wgY29tbXVuaWNhdGlvblxuICogXG4gKiBJbiBNQ1Agc2VydmVycywgc3Rkb3V0IGFuZCBzdGRlcnIgYXJlIHJlc2VydmVkIGZvciBKU09OLVJQQyBwcm90b2NvbCBtZXNzYWdlcy5cbiAqIEFueSBub24tcHJvdG9jb2wgb3V0cHV0IHdpbGwgY2F1c2UgXCJVbmV4cGVjdGVkIHRva2VuXCIgZXJyb3JzIGluIHRoZSBNQ1AgY2xpZW50LlxuICogXG4gKiBUaGlzIGxvZ2dlcjpcbiAqIC0gV3JpdGVzIHRvIHN0ZGVyciBPTkxZIGR1cmluZyBzZXJ2ZXIgaW5pdGlhbGl6YXRpb24gKGJlZm9yZSBNQ1AgY29ubmVjdGlvbilcbiAqIC0gU3RvcmVzIGFsbCBsb2dzIGluIG1lbW9yeSBkdXJpbmcgcnVudGltZVxuICogLSBQcm92aWRlcyBtZXRob2RzIHRvIHJldHJpZXZlIGxvZ3MgdmlhIE1DUCB0b29scyBpZiBuZWVkZWRcbiAqL1xuXG5pbnRlcmZhY2UgTG9nRW50cnkge1xuICB0aW1lc3RhbXA6IERhdGU7XG4gIGxldmVsOiAnZGVidWcnIHwgJ2luZm8nIHwgJ3dhcm4nIHwgJ2Vycm9yJztcbiAgbWVzc2FnZTogc3RyaW5nO1xuICBkYXRhPzogYW55O1xufVxuXG5jbGFzcyBNQ1BMb2dnZXIge1xuICBwcml2YXRlIGxvZ3M6IExvZ0VudHJ5W10gPSBbXTtcbiAgcHJpdmF0ZSBtYXhMb2dzID0gMTAwMDtcbiAgcHJpdmF0ZSBpc01DUENvbm5lY3RlZCA9IGZhbHNlO1xuICBcbiAgLyoqXG4gICAqIENhbGwgdGhpcyBhZnRlciBNQ1AgY29ubmVjdGlvbiBpcyBlc3RhYmxpc2hlZCB0byBzdG9wIGNvbnNvbGUgb3V0cHV0XG4gICAqL1xuICBwdWJsaWMgc2V0TUNQQ29ubmVjdGVkKCk6IHZvaWQge1xuICAgIHRoaXMuaXNNQ1BDb25uZWN0ZWQgPSB0cnVlO1xuICB9XG4gIFxuICAvKipcbiAgICogSW50ZXJuYWwgbG9nZ2luZyBtZXRob2RcbiAgICovXG4gIHByaXZhdGUgbG9nKGxldmVsOiBMb2dFbnRyeVsnbGV2ZWwnXSwgbWVzc2FnZTogc3RyaW5nLCBkYXRhPzogYW55KTogdm9pZCB7XG4gICAgY29uc3QgZW50cnk6IExvZ0VudHJ5ID0ge1xuICAgICAgdGltZXN0YW1wOiBuZXcgRGF0ZSgpLFxuICAgICAgbGV2ZWwsXG4gICAgICBtZXNzYWdlLFxuICAgICAgZGF0YVxuICAgIH07XG4gICAgXG4gICAgLy8gU3RvcmUgaW4gbWVtb3J5XG4gICAgdGhpcy5sb2dzLnB1c2goZW50cnkpO1xuICAgIGlmICh0aGlzLmxvZ3MubGVuZ3RoID4gdGhpcy5tYXhMb2dzKSB7XG4gICAgICB0aGlzLmxvZ3Muc2hpZnQoKTtcbiAgICB9XG4gICAgXG4gICAgLy8gT25seSB3cml0ZSB0byBjb25zb2xlIGR1cmluZyBpbml0aWFsaXphdGlvblxuICAgIGlmICghdGhpcy5pc01DUENvbm5lY3RlZCkge1xuICAgICAgLy8gQ2hlY2sgTk9ERV9FTlYgaW5zaWRlIHRoZSBtZXRob2QgdG8gZW5zdXJlIGl0J3MgZXZhbHVhdGVkIGF0IHJ1bnRpbWVcbiAgICAgIGNvbnN0IGlzVGVzdCA9IHByb2Nlc3MuZW52Lk5PREVfRU5WID09PSAndGVzdCc7XG4gICAgICBpZiAoIWlzVGVzdCkge1xuICAgICAgICBjb25zdCBwcmVmaXggPSBgWyR7ZW50cnkudGltZXN0YW1wLnRvSVNPU3RyaW5nKCl9XSBbJHtsZXZlbC50b1VwcGVyQ2FzZSgpfV1gO1xuICAgICAgICBjb25zdCBmdWxsTWVzc2FnZSA9IGRhdGEgXG4gICAgICAgICAgPyBgJHtwcmVmaXh9ICR7bWVzc2FnZX0gJHtKU09OLnN0cmluZ2lmeShkYXRhKX1gXG4gICAgICAgICAgOiBgJHtwcmVmaXh9ICR7bWVzc2FnZX1gO1xuICAgICAgICBcbiAgICAgICAgLy8gRHVyaW5nIGluaXRpYWxpemF0aW9uLCB3ZSBjYW4gdXNlIGNvbnNvbGVcbiAgICAgICAgaWYgKGxldmVsID09PSAnZXJyb3InKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihmdWxsTWVzc2FnZSk7XG4gICAgICAgIH0gZWxzZSBpZiAobGV2ZWwgPT09ICd3YXJuJykge1xuICAgICAgICAgIGNvbnNvbGUud2FybihmdWxsTWVzc2FnZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gRm9yIE1DUCwgZXZlbiBkdXJpbmcgaW5pdCwgYXZvaWQgc3Rkb3V0IGZvciBpbmZvL2RlYnVnXG4gICAgICAgICAgY29uc29sZS5lcnJvcihmdWxsTWVzc2FnZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgXG4gIHB1YmxpYyBkZWJ1ZyhtZXNzYWdlOiBzdHJpbmcsIGRhdGE/OiBhbnkpOiB2b2lkIHtcbiAgICB0aGlzLmxvZygnZGVidWcnLCBtZXNzYWdlLCBkYXRhKTtcbiAgfVxuICBcbiAgcHVibGljIGluZm8obWVzc2FnZTogc3RyaW5nLCBkYXRhPzogYW55KTogdm9pZCB7XG4gICAgdGhpcy5sb2coJ2luZm8nLCBtZXNzYWdlLCBkYXRhKTtcbiAgfVxuICBcbiAgcHVibGljIHdhcm4obWVzc2FnZTogc3RyaW5nLCBkYXRhPzogYW55KTogdm9pZCB7XG4gICAgdGhpcy5sb2coJ3dhcm4nLCBtZXNzYWdlLCBkYXRhKTtcbiAgfVxuICBcbiAgcHVibGljIGVycm9yKG1lc3NhZ2U6IHN0cmluZywgZGF0YT86IGFueSk6IHZvaWQge1xuICAgIHRoaXMubG9nKCdlcnJvcicsIG1lc3NhZ2UsIGRhdGEpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IHJlY2VudCBsb2dzIChmb3IgTUNQIHRvb2xzIHRvIHJldHJpZXZlKVxuICAgKi9cbiAgcHVibGljIGdldExvZ3MoY291bnQgPSAxMDAsIGxldmVsPzogTG9nRW50cnlbJ2xldmVsJ10pOiBMb2dFbnRyeVtdIHtcbiAgICBsZXQgZmlsdGVyZWQgPSB0aGlzLmxvZ3M7XG4gICAgaWYgKGxldmVsKSB7XG4gICAgICBmaWx0ZXJlZCA9IHRoaXMubG9ncy5maWx0ZXIobG9nID0+IGxvZy5sZXZlbCA9PT0gbGV2ZWwpO1xuICAgIH1cbiAgICByZXR1cm4gZmlsdGVyZWQuc2xpY2UoLWNvdW50KTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIENsZWFyIGxvZ3NcbiAgICovXG4gIHB1YmxpYyBjbGVhckxvZ3MoKTogdm9pZCB7XG4gICAgdGhpcy5sb2dzID0gW107XG4gIH1cbn1cblxuLy8gU2luZ2xldG9uIGluc3RhbmNlXG5leHBvcnQgY29uc3QgbG9nZ2VyID0gbmV3IE1DUExvZ2dlcigpOyJdfQ==