Skip to main content
Glama

analyze_dependency_graph

Analyze code dependency graphs to detect circular dependencies, identify module clusters, and examine import/export relationships between files.

Instructions

코드 의존성 그래프를 분석합니다.

키워드: 의존성, 관계 분석, 순환 참조, dependency graph, circular dependency

분석 내용:

  • 파일 간 import/export 관계

  • 순환 의존성 감지

  • 모듈 클러스터 식별

  • 코드 결합도 분석

사용 예시:

  • "src 폴더의 의존성 그래프 분석해줘"

  • "index.ts의 의존 관계 보여줘"

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
projectPathYes프로젝트 경로
targetFileNo특정 파일 분석 (선택사항)
maxDepthNo최대 탐색 깊이 (기본값: 3)
includeExternalNo외부 패키지 포함 여부 (기본값: false)
detectCircularNo순환 의존성 감지 (기본값: true)

Implementation Reference

  • Main handler function that performs dependency graph analysis on TypeScript projects using ts-morph. Builds graph from imports/exports, detects circular dependencies, identifies clusters, generates Mermaid diagrams and statistics.
    export async function analyzeDependencyGraph(args: AnalyzeDependencyGraphArgs): Promise<ToolResult> {
      try {
        const {
          projectPath,
          targetFile,
          maxDepth = 3,
          includeExternal = false,
          detectCircular = true
        } = args;
    
        const project = ProjectCache.getInstance().getOrCreate(projectPath);
        const sourceFiles = project.getSourceFiles();
    
        if (sourceFiles.length === 0) {
          return {
            content: [{
              type: 'text',
              text: `✗ 프로젝트에서 소스 파일을 찾을 수 없습니다: ${projectPath}`
            }]
          };
        }
    
        const graph: DependencyGraph = {
          nodes: [],
          edges: [],
          circularDependencies: [],
          clusters: []
        };
    
        const fileMap = new Map<string, DependencyNode>();
        const adjacencyList = new Map<string, Set<string>>();
    
        // Build dependency graph
        for (const sourceFile of sourceFiles) {
          const filePath = sourceFile.getFilePath();
          const relativePath = getRelativePath(filePath, projectPath);
    
          // Skip if targeting specific file and this isn't it or related
          if (targetFile && !relativePath.includes(targetFile) && !shouldIncludeInGraph(relativePath, targetFile, maxDepth)) {
            continue;
          }
    
          const imports: string[] = [];
          const exports: string[] = [];
    
          // Get imports
          const importDeclarations = sourceFile.getImportDeclarations();
          for (const imp of importDeclarations) {
            const moduleSpecifier = imp.getModuleSpecifierValue();
    
            // Skip external packages unless requested
            if (!includeExternal && (moduleSpecifier.startsWith('@') || !moduleSpecifier.startsWith('.'))) {
              continue;
            }
    
            const resolvedPath = resolveImportPath(moduleSpecifier, filePath, projectPath);
            if (resolvedPath) {
              imports.push(resolvedPath);
    
              // Add edge
              graph.edges.push({
                from: relativePath,
                to: resolvedPath,
                type: 'import'
              });
    
              // Update adjacency list
              if (!adjacencyList.has(relativePath)) {
                adjacencyList.set(relativePath, new Set());
              }
              adjacencyList.get(relativePath)!.add(resolvedPath);
            }
          }
    
          // Get exports
          const exportDeclarations = sourceFile.getExportDeclarations();
          for (const exp of exportDeclarations) {
            const namedExports = exp.getNamedExports();
            for (const named of namedExports) {
              exports.push(named.getName());
            }
          }
    
          // Also get exported declarations
          const exportedDeclarations = sourceFile.getExportedDeclarations();
          exportedDeclarations.forEach((declarations: any[], name: string) => {
            if (!exports.includes(name)) {
              exports.push(name);
            }
          });
    
          const node: DependencyNode = {
            file: relativePath,
            imports,
            exports,
            depth: 0
          };
    
          fileMap.set(relativePath, node);
          graph.nodes.push(node);
        }
    
        // Detect circular dependencies
        if (detectCircular) {
          graph.circularDependencies = findCircularDependencies(adjacencyList);
        }
    
        // Detect clusters (strongly connected components)
        graph.clusters = findClusters(adjacencyList);
    
        // Generate output
        let output = `## 의존성 그래프 분석\n\n`;
        output += `**프로젝트**: ${projectPath}\n`;
        output += `**분석된 파일**: ${graph.nodes.length}개\n`;
        output += `**의존 관계**: ${graph.edges.length}개\n\n`;
    
        // Show target file dependencies if specified
        if (targetFile) {
          const targetNode = graph.nodes.find(n => n.file.includes(targetFile));
          if (targetNode) {
            output += `### ${targetFile} 의존성\n\n`;
            output += `**Imports** (${targetNode.imports.length}개):\n`;
            for (const imp of targetNode.imports) {
              output += `- ← ${imp}\n`;
            }
            output += `\n**Exports** (${targetNode.exports.length}개):\n`;
            for (const exp of targetNode.exports) {
              output += `- → ${exp}\n`;
            }
            output += '\n';
          }
        }
    
        // Circular dependencies warning
        if (graph.circularDependencies.length > 0) {
          output += `### ⚠️ 순환 의존성 감지됨\n\n`;
          for (const cycle of graph.circularDependencies) {
            output += `- ${cycle.join(' → ')} → ${cycle[0]}\n`;
          }
          output += '\n';
        }
    
        // Clusters
        if (graph.clusters.length > 0) {
          output += `### 모듈 클러스터\n\n`;
          for (let i = 0; i < graph.clusters.length; i++) {
            if (graph.clusters[i].length > 1) {
              output += `**클러스터 ${i + 1}** (${graph.clusters[i].length}개):\n`;
              for (const file of graph.clusters[i].slice(0, 5)) {
                output += `  - ${file}\n`;
              }
              if (graph.clusters[i].length > 5) {
                output += `  - ... 외 ${graph.clusters[i].length - 5}개\n`;
              }
              output += '\n';
            }
          }
        }
    
        // Mermaid diagram for small graphs
        if (graph.nodes.length <= 20) {
          output += `### 의존성 다이어그램\n\n`;
          output += generateMermaidDiagram(graph);
        }
    
        // Statistics
        output += `### 통계\n\n`;
        output += generateStatistics(graph);
    
        return {
          content: [{
            type: 'text',
            text: output
          }]
        };
      } catch (error) {
        return {
          content: [{
            type: 'text',
            text: `✗ 의존성 분석 오류: ${error instanceof Error ? error.message : '알 수 없는 오류'}`
          }]
        };
      }
    }
  • ToolDefinition object defining the tool's name, description, input schema (projectPath required, optional targetFile, maxDepth, etc.), and annotations.
    export const analyzeDependencyGraphDefinition: ToolDefinition = {
      name: 'analyze_dependency_graph',
      description: `코드 의존성 그래프를 분석합니다.
    
    키워드: 의존성, 관계 분석, 순환 참조, dependency graph, circular dependency
    
    **분석 내용:**
    - 파일 간 import/export 관계
    - 순환 의존성 감지
    - 모듈 클러스터 식별
    - 코드 결합도 분석
    
    사용 예시:
    - "src 폴더의 의존성 그래프 분석해줘"
    - "index.ts의 의존 관계 보여줘"`,
      inputSchema: {
        type: 'object',
        properties: {
          projectPath: {
            type: 'string',
            description: '프로젝트 경로'
          },
          targetFile: {
            type: 'string',
            description: '특정 파일 분석 (선택사항)'
          },
          maxDepth: {
            type: 'number',
            description: '최대 탐색 깊이 (기본값: 3)'
          },
          includeExternal: {
            type: 'boolean',
            description: '외부 패키지 포함 여부 (기본값: false)'
          },
          detectCircular: {
            type: 'boolean',
            description: '순환 의존성 감지 (기본값: true)'
          }
        },
        required: ['projectPath']
      },
      annotations: {
        title: 'Analyze Dependency Graph',
        audience: ['user', 'assistant'],
        readOnlyHint: true,
        destructiveHint: false,
        idempotentHint: true,
        openWorldHint: false
      }
    };
  • TypeScript interface defining the input arguments for the handler function, matching the inputSchema.
    interface AnalyzeDependencyGraphArgs {
      projectPath: string;
      targetFile?: string;
      maxDepth?: number;
      includeExternal?: boolean;
      detectCircular?: boolean;
    }
  • src/index.ts:115-115 (registration)
    Registration of the tool definition in the tools array used by ListToolsRequestHandler.
    analyzeDependencyGraphDefinition,
  • src/index.ts:180-180 (registration)
    Registration of the tool handler in the toolHandlers object for dynamic dispatch in CallToolRequestHandler.
    'analyze_dependency_graph': analyzeDependencyGraph,

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/su-record/hi-ai'

If you have feedback or need assistance with the MCP directory API, please join our Discord server