analyze-dependencies
Analyzes dependencies within source code or repositories to identify and visualize relationships between modules, improving code understanding and maintenance for developers.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| fileContent | No | Source code content to analyze directly instead of from a repository | |
| language | No | Programming language of the code (e.g., 'javascript', 'python', 'typescript', 'rust') | |
| repositoryUrl | No | URL of the repository to analyze (e.g., 'https://github.com/username/repo') |
Implementation Reference
- Core handler function that orchestrates dependency analysis: detects project type (Node.js, Python, Java, generic) and calls specific analyzers to build dependency graph and summary.export async function analyzeDependencies(repositoryPath: string): Promise<{ graph: DependencyGraph; summary: { totalDependencies: number; directDependencies: number; devDependencies: number; internalDependencies: number; }; }> { if (!repositoryPath) { throw new Error("Repository path is required"); } // Detect project type const projectType = await detectProjectType(repositoryPath); let dependencyGraph: DependencyGraph; // Analyze based on project type switch (projectType) { case 'node': dependencyGraph = await analyzeNodeDependencies(repositoryPath); break; case 'python': dependencyGraph = await analyzePythonDependencies(repositoryPath); break; case 'java': dependencyGraph = await analyzeJavaDependencies(repositoryPath); break; default: dependencyGraph = await analyzeGenericDependencies(repositoryPath); } // Generate summary const summary = { totalDependencies: dependencyGraph.nodes.length, directDependencies: dependencyGraph.nodes.filter(n => n.type === 'direct').length, devDependencies: dependencyGraph.nodes.filter(n => n.type === 'dev').length, internalDependencies: dependencyGraph.nodes.filter(n => n.type === 'internal').length }; return { graph: dependencyGraph, summary }; }
- src/features/dependency-analysis/index.ts:5-55 (registration)Registration of the analyze-dependencies tool with MCP server, including wrapper handler that calls core analyzeDependencies and formats output (JSON, Mermaid, DOT). This function is called during server initialization.export function registerDependencyAnalysisTools(server: McpServer) { server.tool( "analyze-dependencies", { repositoryUrl: z.string().optional().describe("URL or path to the repository to analyze"), repositoryPath: z.string().optional().describe("Path to the repository to analyze"), fileContent: z.string().optional().describe("File content to analyze"), format: z.enum(["json", "mermaid", "dot"]).optional().describe("Output format for the dependency graph") }, async ({ repositoryUrl, repositoryPath, fileContent, format = "json" }) => { try { const repoPath = repositoryPath || repositoryUrl; // Use either one if (!repoPath && !fileContent) { throw new Error("Either repositoryUrl, repositoryPath, or fileContent must be provided"); } console.log(`Analyzing dependencies in: ${repoPath || 'provided content'}`); // Perform the analysis const analysis = await analyzeDependencies(repoPath || '.'); // Format the result based on requested format let formattedResult; switch (format) { case "mermaid": formattedResult = generateMermaidGraph(analysis.graph); break; case "dot": formattedResult = generateDotGraph(analysis.graph); break; default: formattedResult = JSON.stringify(analysis, null, 2); } return { content: [{ type: "text", text: formattedResult }] }; } catch (error) { return { content: [{ type: "text", text: `Error analyzing dependencies: ${(error as Error).message}` }], isError: true }; } } );
- Input schema using Zod for validating tool parameters.{ repositoryUrl: z.string().optional().describe("URL or path to the repository to analyze"), repositoryPath: z.string().optional().describe("Path to the repository to analyze"), fileContent: z.string().optional().describe("File content to analyze"), format: z.enum(["json", "mermaid", "dot"]).optional().describe("Output format for the dependency graph") },
- Language-specific helper for Node.js: parses package.json for deps/devDeps and scans JS/TS files for import/require statements to build graph.async function analyzeNodeDependencies(repositoryPath: string): Promise<DependencyGraph> { const nodes: DependencyNode[] = []; const edges: DependencyEdge[] = []; try { // Read package.json to extract dependencies const packageJsonPath = path.join(repositoryPath, 'package.json'); const packageJsonContent = await fs.readFile(packageJsonPath, 'utf8'); const packageJson = JSON.parse(packageJsonContent); // Add direct dependencies if (packageJson.dependencies) { for (const [name, version] of Object.entries(packageJson.dependencies)) { nodes.push({ name, version: version as string, type: 'direct' }); } } // Add dev dependencies if (packageJson.devDependencies) { for (const [name, version] of Object.entries(packageJson.devDependencies)) { nodes.push({ name, version: version as string, type: 'dev' }); } } // Find all JS/TS files const files = await findFiles(repositoryPath, ['.js', '.ts', '.jsx', '.tsx']); // Analyze imports in each file for (const file of files) { const fullPath = path.join(repositoryPath, file); const content = await fs.readFile(fullPath, 'utf8'); // Extract imports const imports = extractImports(content); for (const importPath of imports) { if (importPath.startsWith('.')) { // Internal file import const targetPath = path.resolve(path.dirname(fullPath), importPath); const relativePath = path.relative(repositoryPath, targetPath); // Add node if it doesn't exist if (!nodes.some(n => n.path === relativePath)) { nodes.push({ name: relativePath, type: 'internal', path: relativePath }); } // Add edge edges.push({ source: file, target: relativePath, type: 'imports' }); } else { // External package import const packageName = importPath.split('/')[0]; // Add edge to the dependency edges.push({ source: file, target: packageName, type: 'imports' }); } } } return { nodes, edges }; } catch (error) { console.error('Error analyzing Node.js dependencies:', error); return { nodes: [], edges: [] }; } }
- Helper function to format dependency graph as Mermaid diagram syntax for visualization.function generateMermaidGraph(graph: any): string { let mermaid = "graph TD;\n"; // Add nodes for (const node of graph.nodes) { mermaid += ` ${formatNodeId(node.name)}["${node.name}${node.version ? ` (${node.version})` : ''}"`; // Style nodes based on type if (node.type === 'direct') { mermaid += ' style="fill:#a8d08d"'; } else if (node.type === 'dev') { mermaid += ' style="fill:#ffcc99"'; } else if (node.type === 'internal') { mermaid += ' style="fill:#a4c2f4"'; } mermaid += "];\n"; } // Add edges for (const edge of graph.edges) { mermaid += ` ${formatNodeId(edge.source)} --> ${formatNodeId(edge.target)};\n`; } return mermaid; }