Home / Class/ GraphCache Class — mcp Architecture

GraphCache Class — mcp Architecture

Architecture documentation for the GraphCache class in graph-cache.ts from the mcp codebase.

Entity Profile

Relationship Graph

Source Code

src/cache/graph-cache.ts lines 262–365

export class GraphCache {
  private cache = new Map<string, CacheEntry>();
  private maxGraphs: number;
  private maxNodes: number;
  private maxAgeMs: number;
  private currentNodes = 0;

  constructor(options?: { maxGraphs?: number; maxNodes?: number; maxAgeMs?: number }) {
    this.maxGraphs = options?.maxGraphs || DEFAULT_MAX_GRAPHS;
    this.maxNodes = options?.maxNodes || DEFAULT_MAX_NODES;
    this.maxAgeMs = options?.maxAgeMs || DEFAULT_CACHE_TTL_MS;
  }

  get(cacheKey: string): IndexedGraph | null {
    const entry = this.cache.get(cacheKey);
    if (entry) {
      // Update access time (LRU)
      entry.lastAccessed = Date.now();
      return entry.graph;
    }
    return null;
  }

  set(cacheKey: string, graph: IndexedGraph): void {
    const nodeCount = graph.summary.nodeCount;

    // Evict stale entries first
    this.evictStale();

    // Evict if needed
    while (
      (this.cache.size >= this.maxGraphs || this.currentNodes + nodeCount > this.maxNodes) &&
      this.cache.size > 0
    ) {
      this.evictOldest();
    }

    // Store
    const now = Date.now();
    this.cache.set(cacheKey, {
      graph,
      nodeCount,
      lastAccessed: now,
      createdAt: now,
    });
    this.currentNodes += nodeCount;
  }

  has(cacheKey: string): boolean {
    return this.cache.has(cacheKey);
  }

  private evictOldest(): void {
    let oldestKey: string | null = null;
    let oldestTime = Infinity;

    for (const [key, entry] of this.cache) {
      if (entry.lastAccessed < oldestTime) {
        oldestTime = entry.lastAccessed;
        oldestKey = key;
      }
    }

    if (oldestKey) {
      const entry = this.cache.get(oldestKey)!;
      this.currentNodes -= entry.nodeCount;
      this.cache.delete(oldestKey);
    }
  }

  /**
   * Evict all cache entries that have exceeded their TTL (maxAgeMs)
   * This method can be called manually or is automatically invoked before adding new entries
   * @returns Number of entries evicted
   */
  evictStale(): number {
    const now = Date.now();
    const keysToEvict: string[] = [];

    // Find all stale entries
    for (const [key, entry] of this.cache) {
      if (now - entry.createdAt > this.maxAgeMs) {
        keysToEvict.push(key);
      }
    }

    // Evict them
    for (const key of keysToEvict) {
      const entry = this.cache.get(key)!;
      this.currentNodes -= entry.nodeCount;
      this.cache.delete(key);
    }

    return keysToEvict.length;
  }

  status(): { graphs: number; nodes: number; keys: string[] } {
    return {
      graphs: this.cache.size,
      nodes: this.currentNodes,
      keys: Array.from(this.cache.keys()),
    };
  }
}

Domain

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free