Skip to main content
Glama

analyze_dependency_graph

Read-onlyIdempotent

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,
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already provide readOnlyHint=true, destructiveHint=false, idempotentHint=true, and openWorldHint=false, covering safety and idempotency. The description adds behavioral context by specifying what gets analyzed (e.g., circular dependencies, module clusters), which is useful beyond annotations. However, it doesn't disclose additional traits like performance implications, output format, or error handling. With annotations covering core safety, the description adds moderate value.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is appropriately sized and front-loaded, starting with a clear purpose statement followed by bullet points of analysis content and usage examples. It avoids redundancy and wastes no sentences, though the keyword list could be considered slightly extraneous. Overall, it's efficient and well-structured for quick understanding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's moderate complexity (5 parameters, no output schema), the description provides a good overview of what the analysis entails but lacks details on return values or error cases. Annotations cover safety aspects, but without an output schema, the description doesn't explain what results to expect (e.g., graph structure, report format). It's adequate but has gaps in completeness for a tool with no output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, with all 5 parameters well-documented in the schema (e.g., projectPath, targetFile, maxDepth). The description doesn't add parameter-specific details beyond what the schema provides, such as explaining how maxDepth affects analysis or what includeExternal entails. Since the schema does the heavy lifting, the baseline score of 3 is appropriate, as the description doesn't compensate with extra semantic insights.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool analyzes code dependency graphs, listing specific analysis aspects like import/export relationships, circular dependency detection, module clustering, and coupling analysis. It distinguishes from most siblings (e.g., analyze_complexity, check_coupling_cohesion) by focusing specifically on dependency graphs, though it doesn't explicitly differentiate from tools like get_memory_graph which might have overlapping concepts. The purpose is specific but could be more precise about sibling differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides usage examples that imply when to use this tool (e.g., analyzing src folder dependencies or index.ts relationships), giving some contextual guidance. However, it lacks explicit when-not-to-use advice or clear alternatives among siblings (e.g., vs. check_coupling_cohesion or analyze_complexity). The guidelines are helpful but not comprehensive for tool selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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