Skip to content

perf: cache config validation results to improve scan performance #48

Description

@gsong

Summary

The mcp-scanner.ts validates config files on every scan. Caching validation results based on file modification time or hash (similar to the existing selection cache) could improve performance.

Current State

Currently in /Users/george/src/gsong/ccmcp/src/mcp-scanner.ts, every call to scanMcpConfigs() performs full validation:

// Lines 51-102: Process files in parallel
const configs = await Promise.all(
  jsonFiles.map(async (file): Promise<McpConfig> => {
    const filePath = join(resolvedConfigDir, file);
    const name = file.replace(".json", "");

    try {
      const content = await readFile(filePath, "utf-8");
      const parsed = JSON.parse(content);
      
      // Schema-based validation using Zod - happens every time
      const validationResult = validateMcpConfig(parsed);
      // ...
    }
  })
);

Performance Impact

While validation is fast, it's still unnecessary work when:

  • Config files haven't changed since last scan
  • User runs ccmcp multiple times in quick succession
  • Large number of config files exist

Proposed Solution

Implement validation caching similar to the existing selection cache pattern:

  1. Create validation cache structure:
interface ValidationCache {
  version: 1;
  entries: Record<string, {
    filePath: string;
    mtime: string;  // or hash
    valid: boolean;
    error?: string;
    description?: string;
  }>;
}
  1. Cache location: Use same pattern as selection cache (~/.cache/ccmcp/validation-cache.json)

  2. Cache invalidation: Compare file mtime or content hash

    • Use stat() to get mtime
    • Only re-validate if file changed
  3. Fallback: If cache read fails or file is modified, perform full validation

Example Implementation

async function getCachedValidation(
  filePath: string
): Promise<ValidationResult | null> {
  const cache = await loadValidationCache();
  const stats = await stat(filePath);
  const cached = cache.entries[filePath];
  
  if (cached && cached.mtime === stats.mtime.toISOString()) {
    return cached;
  }
  
  return null;
}

Impact

  • Performance: Faster subsequent scans when configs haven't changed
  • User Experience: Reduced latency when running ccmcp multiple times
  • Trade-offs: Adds complexity and another cache to manage
  • Effort: Medium (similar to existing selection cache implementation)

Considerations

  1. Cache invalidation: mtime is simpler but less reliable; hash is more reliable but slower
  2. Cache cleanup: Should validation cache have TTL or be cleared with --clear-cache?
  3. Value vs Complexity: Is the performance gain worth the added complexity?

Alternative: Profile First

Before implementing, consider profiling to determine if validation is actually a bottleneck:

  • Measure time spent in validation vs file I/O
  • Measure with varying numbers of config files (1, 10, 50, 100)
  • Compare cost of validation vs cost of cache management

Recommendation: Implement only if profiling shows validation is a measurable bottleneck.

Files to Update (if implemented)

  1. /Users/george/src/gsong/ccmcp/src/mcp-scanner.ts - Add cache checking logic
  2. New file: /Users/george/src/gsong/ccmcp/src/validation-cache.ts - Cache management
  3. /Users/george/src/gsong/ccmcp/src/selection-cache.ts - Maybe share cache utilities
  4. /Users/george/src/gsong/ccmcp/src/index.ts - Include validation cache in --clear-cache

Priority

Low - This is an optimization that should be data-driven. Profile first to confirm it's needed.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions