UNPKG

@dollhousemcp/mcp-server

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.

74 lines 8.47 kB
/** * StartupTimer — Lightweight startup phase timing instrumentation. * * Tracks per-phase durations during server initialization, split into * critical (pre-connect) and deferred (post-connect) categories. * * Registered as a DI singleton so BuildInfoService can expose timings * via `get_build_info`. * * Issue #706: MCP Startup Race Hardening */ export class StartupTimer { phases = new Map(); originMs; connectAtMs = null; constructor() { this.originMs = Date.now(); } /** * Begin timing a named phase. * @param name Unique phase identifier (e.g. "config_manager") * @param critical true = pre-connect critical path, false = deferred */ startPhase(name, critical) { this.phases.set(name, { name, critical, startMs: Date.now(), endMs: null, durationMs: null, }); } /** * End a previously started phase. Idempotent — second call is a no-op. */ endPhase(name) { const phase = this.phases.get(name); if (!phase || phase.endMs !== null) return; phase.endMs = Date.now(); phase.durationMs = phase.endMs - phase.startMs; } /** * Record the instant MCP `server.connect()` completes. */ markConnect() { this.connectAtMs = Date.now(); } /** * Produce the final report. Un-ended phases are auto-closed. */ getReport() { const now = Date.now(); const completed = []; for (const phase of this.phases.values()) { const duration = phase.durationMs ?? (now - phase.startMs); completed.push({ name: phase.name, critical: phase.critical, durationMs: duration }); } const criticalPathMs = completed .filter(p => p.critical) .reduce((sum, p) => sum + p.durationMs, 0); const deferredMs = completed .filter(p => !p.critical) .reduce((sum, p) => sum + p.durationMs, 0); return { phases: completed, criticalPathMs, deferredMs, totalMs: now - this.originMs, connectAtMs: this.connectAtMs ? this.connectAtMs - this.originMs : null, }; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU3RhcnR1cFRpbWVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3RlbGVtZXRyeS9TdGFydHVwVGltZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7R0FVRztBQXNCSCxNQUFNLE9BQU8sWUFBWTtJQUNmLE1BQU0sR0FBRyxJQUFJLEdBQUcsRUFBc0IsQ0FBQztJQUN2QyxRQUFRLENBQVM7SUFDakIsV0FBVyxHQUFrQixJQUFJLENBQUM7SUFFMUM7UUFDRSxJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUM3QixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILFVBQVUsQ0FBQyxJQUFZLEVBQUUsUUFBaUI7UUFDeEMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFO1lBQ3BCLElBQUk7WUFDSixRQUFRO1lBQ1IsT0FBTyxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUU7WUFDbkIsS0FBSyxFQUFFLElBQUk7WUFDWCxVQUFVLEVBQUUsSUFBSTtTQUNqQixDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxRQUFRLENBQUMsSUFBWTtRQUNuQixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNwQyxJQUFJLENBQUMsS0FBSyxJQUFJLEtBQUssQ0FBQyxLQUFLLEtBQUssSUFBSTtZQUFFLE9BQU87UUFDM0MsS0FBSyxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDekIsS0FBSyxDQUFDLFVBQVUsR0FBRyxLQUFLLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUM7SUFDakQsQ0FBQztJQUVEOztPQUVHO0lBQ0gsV0FBVztRQUNULElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQ2hDLENBQUM7SUFFRDs7T0FFRztJQUNILFNBQVM7UUFDUCxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDdkIsTUFBTSxTQUFTLEdBQW1FLEVBQUUsQ0FBQztRQUVyRixLQUFLLE1BQU0sS0FBSyxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQztZQUN6QyxNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUMsVUFBVSxJQUFJLENBQUMsR0FBRyxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUMzRCxTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUUsSUFBSSxFQUFFLEtBQUssQ0FBQyxJQUFJLEVBQUUsUUFBUSxFQUFFLEtBQUssQ0FBQyxRQUFRLEVBQUUsVUFBVSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7UUFDdkYsQ0FBQztRQUVELE1BQU0sY0FBYyxHQUFHLFNBQVM7YUFDN0IsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQzthQUN2QixNQUFNLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUU3QyxNQUFNLFVBQVUsR0FBRyxTQUFTO2FBQ3pCLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQzthQUN4QixNQUFNLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUU3QyxPQUFPO1lBQ0wsTUFBTSxFQUFFLFNBQVM7WUFDakIsY0FBYztZQUNkLFVBQVU7WUFDVixPQUFPLEVBQUUsR0FBRyxHQUFHLElBQUksQ0FBQyxRQUFRO1lBQzVCLFdBQVcsRUFBRSxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLElBQUk7U0FDeEUsQ0FBQztJQUNKLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogU3RhcnR1cFRpbWVyIOKAlCBMaWdodHdlaWdodCBzdGFydHVwIHBoYXNlIHRpbWluZyBpbnN0cnVtZW50YXRpb24uXG4gKlxuICogVHJhY2tzIHBlci1waGFzZSBkdXJhdGlvbnMgZHVyaW5nIHNlcnZlciBpbml0aWFsaXphdGlvbiwgc3BsaXQgaW50b1xuICogY3JpdGljYWwgKHByZS1jb25uZWN0KSBhbmQgZGVmZXJyZWQgKHBvc3QtY29ubmVjdCkgY2F0ZWdvcmllcy5cbiAqXG4gKiBSZWdpc3RlcmVkIGFzIGEgREkgc2luZ2xldG9uIHNvIEJ1aWxkSW5mb1NlcnZpY2UgY2FuIGV4cG9zZSB0aW1pbmdzXG4gKiB2aWEgYGdldF9idWlsZF9pbmZvYC5cbiAqXG4gKiBJc3N1ZSAjNzA2OiBNQ1AgU3RhcnR1cCBSYWNlIEhhcmRlbmluZ1xuICovXG5cbmV4cG9ydCBpbnRlcmZhY2UgUGhhc2VFbnRyeSB7XG4gIG5hbWU6IHN0cmluZztcbiAgY3JpdGljYWw6IGJvb2xlYW47XG4gIHN0YXJ0TXM6IG51bWJlcjtcbiAgZW5kTXM6IG51bWJlciB8IG51bGw7XG4gIGR1cmF0aW9uTXM6IG51bWJlciB8IG51bGw7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU3RhcnR1cFJlcG9ydCB7XG4gIHBoYXNlczogQXJyYXk8e1xuICAgIG5hbWU6IHN0cmluZztcbiAgICBjcml0aWNhbDogYm9vbGVhbjtcbiAgICBkdXJhdGlvbk1zOiBudW1iZXI7XG4gIH0+O1xuICBjcml0aWNhbFBhdGhNczogbnVtYmVyO1xuICBkZWZlcnJlZE1zOiBudW1iZXI7XG4gIHRvdGFsTXM6IG51bWJlcjtcbiAgY29ubmVjdEF0TXM6IG51bWJlciB8IG51bGw7XG59XG5cbmV4cG9ydCBjbGFzcyBTdGFydHVwVGltZXIge1xuICBwcml2YXRlIHBoYXNlcyA9IG5ldyBNYXA8c3RyaW5nLCBQaGFzZUVudHJ5PigpO1xuICBwcml2YXRlIG9yaWdpbk1zOiBudW1iZXI7XG4gIHByaXZhdGUgY29ubmVjdEF0TXM6IG51bWJlciB8IG51bGwgPSBudWxsO1xuXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHRoaXMub3JpZ2luTXMgPSBEYXRlLm5vdygpO1xuICB9XG5cbiAgLyoqXG4gICAqIEJlZ2luIHRpbWluZyBhIG5hbWVkIHBoYXNlLlxuICAgKiBAcGFyYW0gbmFtZSAgIFVuaXF1ZSBwaGFzZSBpZGVudGlmaWVyIChlLmcuIFwiY29uZmlnX21hbmFnZXJcIilcbiAgICogQHBhcmFtIGNyaXRpY2FsICB0cnVlID0gcHJlLWNvbm5lY3QgY3JpdGljYWwgcGF0aCwgZmFsc2UgPSBkZWZlcnJlZFxuICAgKi9cbiAgc3RhcnRQaGFzZShuYW1lOiBzdHJpbmcsIGNyaXRpY2FsOiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5waGFzZXMuc2V0KG5hbWUsIHtcbiAgICAgIG5hbWUsXG4gICAgICBjcml0aWNhbCxcbiAgICAgIHN0YXJ0TXM6IERhdGUubm93KCksXG4gICAgICBlbmRNczogbnVsbCxcbiAgICAgIGR1cmF0aW9uTXM6IG51bGwsXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogRW5kIGEgcHJldmlvdXNseSBzdGFydGVkIHBoYXNlLiBJZGVtcG90ZW50IOKAlCBzZWNvbmQgY2FsbCBpcyBhIG5vLW9wLlxuICAgKi9cbiAgZW5kUGhhc2UobmFtZTogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3QgcGhhc2UgPSB0aGlzLnBoYXNlcy5nZXQobmFtZSk7XG4gICAgaWYgKCFwaGFzZSB8fCBwaGFzZS5lbmRNcyAhPT0gbnVsbCkgcmV0dXJuO1xuICAgIHBoYXNlLmVuZE1zID0gRGF0ZS5ub3coKTtcbiAgICBwaGFzZS5kdXJhdGlvbk1zID0gcGhhc2UuZW5kTXMgLSBwaGFzZS5zdGFydE1zO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlY29yZCB0aGUgaW5zdGFudCBNQ1AgYHNlcnZlci5jb25uZWN0KClgIGNvbXBsZXRlcy5cbiAgICovXG4gIG1hcmtDb25uZWN0KCk6IHZvaWQge1xuICAgIHRoaXMuY29ubmVjdEF0TXMgPSBEYXRlLm5vdygpO1xuICB9XG5cbiAgLyoqXG4gICAqIFByb2R1Y2UgdGhlIGZpbmFsIHJlcG9ydC4gVW4tZW5kZWQgcGhhc2VzIGFyZSBhdXRvLWNsb3NlZC5cbiAgICovXG4gIGdldFJlcG9ydCgpOiBTdGFydHVwUmVwb3J0IHtcbiAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICAgIGNvbnN0IGNvbXBsZXRlZDogQXJyYXk8eyBuYW1lOiBzdHJpbmc7IGNyaXRpY2FsOiBib29sZWFuOyBkdXJhdGlvbk1zOiBudW1iZXIgfT4gPSBbXTtcblxuICAgIGZvciAoY29uc3QgcGhhc2Ugb2YgdGhpcy5waGFzZXMudmFsdWVzKCkpIHtcbiAgICAgIGNvbnN0IGR1cmF0aW9uID0gcGhhc2UuZHVyYXRpb25NcyA/PyAobm93IC0gcGhhc2Uuc3RhcnRNcyk7XG4gICAgICBjb21wbGV0ZWQucHVzaCh7IG5hbWU6IHBoYXNlLm5hbWUsIGNyaXRpY2FsOiBwaGFzZS5jcml0aWNhbCwgZHVyYXRpb25NczogZHVyYXRpb24gfSk7XG4gICAgfVxuXG4gICAgY29uc3QgY3JpdGljYWxQYXRoTXMgPSBjb21wbGV0ZWRcbiAgICAgIC5maWx0ZXIocCA9PiBwLmNyaXRpY2FsKVxuICAgICAgLnJlZHVjZSgoc3VtLCBwKSA9PiBzdW0gKyBwLmR1cmF0aW9uTXMsIDApO1xuXG4gICAgY29uc3QgZGVmZXJyZWRNcyA9IGNvbXBsZXRlZFxuICAgICAgLmZpbHRlcihwID0+ICFwLmNyaXRpY2FsKVxuICAgICAgLnJlZHVjZSgoc3VtLCBwKSA9PiBzdW0gKyBwLmR1cmF0aW9uTXMsIDApO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHBoYXNlczogY29tcGxldGVkLFxuICAgICAgY3JpdGljYWxQYXRoTXMsXG4gICAgICBkZWZlcnJlZE1zLFxuICAgICAgdG90YWxNczogbm93IC0gdGhpcy5vcmlnaW5NcyxcbiAgICAgIGNvbm5lY3RBdE1zOiB0aGlzLmNvbm5lY3RBdE1zID8gdGhpcy5jb25uZWN0QXRNcyAtIHRoaXMub3JpZ2luTXMgOiBudWxsLFxuICAgIH07XG4gIH1cbn1cbiJdfQ==