Home / Function/ handlePrecache() — mcp Function Reference

handlePrecache() — mcp Function Reference

Architecture documentation for the handlePrecache() function in index.ts from the mcp codebase.

Entity Profile

Dependency Diagram

graph TD
  a7551c40_ae18_02d5_7ca4_311e0ad1edb9["handlePrecache()"]
  6f266567_35d5_7334_0233_87d521cf347b["main()"]
  6f266567_35d5_7334_0233_87d521cf347b -->|calls| a7551c40_ae18_02d5_7ca4_311e0ad1edb9
  9a818de6_4969_c29c_0dd7_dab4f6d4fbdb["error()"]
  a7551c40_ae18_02d5_7ca4_311e0ad1edb9 -->|calls| 9a818de6_4969_c29c_0dd7_dab4f6d4fbdb
  style a7551c40_ae18_02d5_7ca4_311e0ad1edb9 fill:#6366f1,stroke:#818cf8,color:#fff

Relationship Graph

Source Code

src/index.ts lines 52–203

async function handlePrecache(args: string[]) {
  if (args.length === 0) {
    console.error('Usage: supermodel-mcp precache <directory> [--output-dir <dir>] [--name <repo-name>]');
    console.error('');
    console.error('Pre-compute a code graph for a repository and save it to disk.');
    console.error('');
    console.error('Options:');
    console.error('  --output-dir <dir>   Directory to save the cache file (default: ./supermodel-cache)');
    console.error('  --name <name>        Repository name for the cache key (default: directory basename)');
    console.error('');
    console.error('Environment:');
    console.error('  SUPERMODEL_API_KEY   Required. API key for the Supermodel service.');
    console.error('  SUPERMODEL_CACHE_DIR Alternative to --output-dir.');
    process.exit(1);
  }

  // Parse args
  let directory = '';
  let outputDir = process.env.SUPERMODEL_CACHE_DIR || './supermodel-cache';
  let repoName = '';

  for (let i = 0; i < args.length; i++) {
    if (args[i] === '--output-dir' && i + 1 < args.length) {
      outputDir = args[++i];
    } else if (args[i] === '--name' && i + 1 < args.length) {
      repoName = args[++i];
    } else if (!args[i].startsWith('--')) {
      directory = args[i];
    }
  }

  if (!directory) {
    console.error('Error: directory argument is required');
    process.exit(1);
  }

  if (!process.env.SUPERMODEL_API_KEY) {
    console.error('Error: SUPERMODEL_API_KEY environment variable is required');
    process.exit(1);
  }

  const { resolve, basename, join } = require('path');
  const { execSync } = require('child_process');
  const { existsSync } = require('fs');
  const resolvedDir = resolve(directory);

  // Detect repo name from git remote, falling back to directory basename
  let detectedName = basename(resolvedDir);
  try {
    const remote = execSync('git remote get-url origin', {
      cwd: resolvedDir, encoding: 'utf-8', timeout: 2000,
    }).trim();
    const match = remote.match(/\/([^\/]+?)(?:\.git)?$/);
    if (match) detectedName = match[1];
  } catch {}

  // Get commit hash for commit-specific caching
  let commitHash = '';
  try {
    commitHash = execSync('git rev-parse --short HEAD', {
      cwd: resolvedDir, encoding: 'utf-8', timeout: 2000,
    }).trim();
  } catch {}

  const name = repoName || (commitHash ? `${detectedName}_${commitHash}` : detectedName);

  // Check if cache file already exists (skip redundant API calls)
  const { saveCacheToDisk, buildIndexes, sanitizeFileName } = require('./cache/graph-cache');
  const expectedPath = join(outputDir, `${sanitizeFileName(name)}.json`);
  if (existsSync(expectedPath)) {
    console.error(`Cache already exists: ${expectedPath}`);
    console.error('Skipping precache (graph already generated for this commit).');
    return;
  }

  console.error(`Pre-computing graph for: ${resolvedDir}`);
  console.error(`Repository name: ${detectedName}, commit: ${commitHash || 'unknown'}`);
  console.error(`Cache file: ${expectedPath}`);
  console.error('');

  // Import what we need
  const { Configuration, DefaultApi, SupermodelClient } = require('@supermodeltools/sdk');
  const { zipRepository } = require('./utils/zip-repository');
  const { readFile } = require('fs/promises');
  const { Blob } = require('buffer');
  const { generateIdempotencyKey } = require('./utils/api-helpers');
  const { Agent } = require('undici');

  const { DEFAULT_API_TIMEOUT_MS, CONNECTION_TIMEOUT_MS } = require('./constants');

  const parsedTimeout = parseInt(process.env.SUPERMODEL_TIMEOUT_MS || '', 10);
  const timeoutMs = Number.isFinite(parsedTimeout) && parsedTimeout > 0
    ? parsedTimeout
    : DEFAULT_API_TIMEOUT_MS;

  const httpAgent = new Agent({
    headersTimeout: timeoutMs,
    bodyTimeout: timeoutMs,
    connectTimeout: CONNECTION_TIMEOUT_MS,
  });

  const fetchWithTimeout: typeof fetch = (url: any, init: any) => {
    return fetch(url, { ...init, dispatcher: httpAgent } as any);
  };

  const config = new Configuration({
    basePath: process.env.SUPERMODEL_BASE_URL || 'https://api.supermodeltools.com',
    apiKey: process.env.SUPERMODEL_API_KEY,
    fetchApi: fetchWithTimeout,
  });

  const api = new DefaultApi(config);
  const client = new SupermodelClient(api);

  // Step 1: Zip
  console.error('Step 1/3: Creating ZIP archive...');
  const zipResult = await zipRepository(resolvedDir);
  console.error(`  ZIP created: ${zipResult.fileCount} files, ${(zipResult.sizeBytes / 1024 / 1024).toFixed(1)} MB`);

  // Step 2: API call
  console.error('Step 2/3: Analyzing codebase (this may take several minutes)...');
  const idempotencyKey = generateIdempotencyKey(resolvedDir);

  let progressInterval: NodeJS.Timeout | null = null;
  let elapsed = 0;
  progressInterval = setInterval(() => {
    elapsed += 15;
    console.error(`  Analysis in progress... (${elapsed}s elapsed)`);
  }, 15000);

  let response: any;
  try {
    const fileBuffer = await readFile(zipResult.path);
    const fileBlob = new Blob([fileBuffer], { type: 'application/zip' });

    response = await client.generateSupermodelGraph(fileBlob, { idempotencyKey });
  } finally {
    if (progressInterval) clearInterval(progressInterval);
    await zipResult.cleanup();
  }

  const graph = buildIndexes(response, `precache:${name}`);
  console.error(`  Analysis complete: ${graph.summary.nodeCount} nodes, ${graph.summary.relationshipCount} relationships`);
  console.error(`  Files: ${graph.summary.filesProcessed}, Functions: ${graph.summary.functions}, Classes: ${graph.summary.classes}`);

  // Step 3: Save to disk
  console.error('Step 3/3: Saving to disk...');
  const savedPath = await saveCacheToDisk(outputDir, name, response, commitHash || undefined);
  console.error(`  Saved to: ${savedPath}`);
  console.error('');
  console.error('Done! To use this cache, set SUPERMODEL_CACHE_DIR=' + outputDir);
}

Domain

Subdomains

Calls

Called By

Frequently Asked Questions

What does handlePrecache() do?
handlePrecache() is a function in the mcp codebase.
What does handlePrecache() call?
handlePrecache() calls 1 function(s): error.
What calls handlePrecache()?
handlePrecache() is called by 1 function(s): main.

Analyze Your Own Codebase

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

Try Supermodel Free