cross-repo-analysis
Analyze dependencies, API usage, and architectural patterns across multiple repositories to identify relationships and improve codebase understanding.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| analysisType | No | dependencies | |
| contextDepth | No | ||
| primaryRepoUrl | Yes | ||
| relatedRepoUrls | Yes |
Implementation Reference
- src/features/multi-repo/index.ts:8-44 (registration)Registers the "cross-repo-analysis" tool with the MCP server, including input schema and thin wrapper handler that delegates to analyzeMultipleRepositories.export function registerMultiRepoFeatures(server: McpServer) { // Tool to analyze relationships between multiple repositories server.tool( "cross-repo-analysis", { primaryRepoUrl: z.string(), relatedRepoUrls: z.array(z.string()), analysisType: z.enum(["dependencies", "api-usage", "architectural-patterns"]).default("dependencies"), contextDepth: z.number().min(1).max(3).default(2) }, async ({ primaryRepoUrl, relatedRepoUrls, analysisType, contextDepth }) => { try { const results = await analyzeMultipleRepositories( primaryRepoUrl, relatedRepoUrls, analysisType, contextDepth ); return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error in cross-repository analysis: ${(error as Error).message}` }], isError: true }; } } ); }
- Core handler logic for cross-repo analysis: clones repos, builds knowledge graphs, performs type-specific relationship analysis, and summarizes repositories.export async function analyzeMultipleRepositories( primaryRepoUrl: string, relatedRepoUrls: string[], analysisType: "dependencies" | "api-usage" | "architectural-patterns", contextDepth: number = 2 ): Promise<any> { // Step 1: Clone/update all repositories const primaryRepoPath = await getRepository(primaryRepoUrl); const relatedRepoPaths = await Promise.all( relatedRepoUrls.map(url => getRepository(url)) ); // Step 2: Build knowledge graphs for each repository console.log(`Building knowledge graph for primary repository: ${primaryRepoUrl}`); const primaryGraph = await buildKnowledgeGraph(primaryRepoUrl, contextDepth, false); console.log(`Building knowledge graphs for ${relatedRepoUrls.length} related repositories`); const relatedGraphsPromises = relatedRepoUrls.map(async (url, index) => { console.log(`Building graph for related repository ${index + 1}: ${url}`); return { url, graph: await buildKnowledgeGraph(url, contextDepth, false) }; }); const relatedGraphs = await Promise.all(relatedGraphsPromises); // Step 3: Analyze cross-repository relationships based on analysis type let crossRepoRelationships; switch (analysisType) { case "dependencies": crossRepoRelationships = await analyzeCrossDependencies( primaryRepoUrl, relatedRepoUrls ); break; case "api-usage": crossRepoRelationships = await analyzeApiUsage( primaryRepoUrl, relatedRepoUrls ); break; case "architectural-patterns": crossRepoRelationships = await analyzeArchitecturalPatterns( primaryRepoUrl, relatedRepoUrls ); break; default: throw new Error(`Unknown analysis type: ${analysisType}`); } // Step 4: Prepare the result return { primaryRepository: { url: primaryRepoUrl, summary: await summarizeRepository(primaryRepoUrl) }, relatedRepositories: await Promise.all(relatedRepoUrls.map(async (url) => ({ url, summary: await summarizeRepository(url) }))), relationships: crossRepoRelationships, analysisType }; }
- Helper function for 'dependencies' analysis type, identifying shared dependencies between primary and related repositories using knowledge graph queries.async function analyzeCrossDependencies( primaryRepoUrl: string, relatedRepoUrls: string[] ): Promise<any> { const results: any[] = []; // Step 1: Get dependency nodes from primary repo const primaryResult = await queryKnowledgeGraph({ query: "dependencies", repositoryUrl: primaryRepoUrl, contextDepth: 2 }); const primaryDependencies = primaryResult.nodes.filter( node => node.type === "dependency" ); // Step 2: For each related repo, find matching dependencies for (const relatedUrl of relatedRepoUrls) { const relatedResult = await queryKnowledgeGraph({ query: "dependencies", repositoryUrl: relatedUrl, contextDepth: 2 }); const relatedDependencies = relatedResult.nodes.filter( node => node.type === "dependency" ); // Find shared dependencies const sharedDependencies = primaryDependencies.filter(primaryDep => relatedDependencies.some(relatedDep => primaryDep.name === relatedDep.name ) ); if (sharedDependencies.length > 0) { results.push({ primaryRepository: primaryRepoUrl, relatedRepository: relatedUrl, type: "shared-dependencies", items: sharedDependencies.map(dep => ({ name: dep.name, details: dep.attributes })) }); } } return results; }
- Helper function to generate repository summaries including file stats, structure, and project type detection.async function summarizeRepository(repositoryUrl: string): Promise<any> { try { const repoPath = await getRepository(repositoryUrl); const files = listFiles(repoPath); // Count files by type const fileTypes: {[key: string]: number} = {}; files.forEach(file => { const ext = path.extname(file).slice(1); if (ext) { fileTypes[ext] = (fileTypes[ext] || 0) + 1; } }); // Analyze repository structure const rootDirs = new Set( files.map(file => { const parts = file.split('/'); return parts.length > 1 ? parts[0] : '__root__'; }) ); // Try to detect package.json or other project files const hasPackageJson = files.some(file => file.endsWith('package.json')); let packageInfo = null; if (hasPackageJson) { try { const packageJsonPath = path.join(repoPath, 'package.json'); const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf8'); const packageData = JSON.parse(packageJsonContent); packageInfo = { name: packageData.name, version: packageData.version, dependencies: Object.keys(packageData.dependencies || {}).length, devDependencies: Object.keys(packageData.devDependencies || {}).length }; } catch (error) { console.warn(`Error parsing package.json: ${(error as Error).message}`); } } return { fileCount: files.length, fileTypes, topLevelDirectories: Array.from(rootDirs), packageInfo, isJavaScriptProject: hasPackageJson, isPythonProject: files.some(file => file.endsWith('requirements.txt') || file.endsWith('setup.py')), isJavaProject: files.some(file => file.endsWith('pom.xml') || file.endsWith('build.gradle')) }; } catch (error) { console.error(`Error summarizing repository: ${(error as Error).message}`); return { error: (error as Error).message }; } }