Skip to main content
Glama
saiprashanths

Code Analysis MCP Server

get_repo_structure

Analyze repository file and directory structure to understand codebase organization. Specify subdirectory paths and traversal depth for targeted exploration.

Instructions

Get the structure of files and directories in the repository.

Args:
    sub_path: Optional subdirectory path relative to repository root
    depth: Optional maximum depth to traverse (default is 3)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
sub_pathNo
depthNo

Implementation Reference

  • Decorator that registers the get_repo_structure as an MCP tool.
    @mcp.tool()
  • The main asynchronous handler function implementing the tool logic. It checks if the repository is initialized, determines the target path, calls the analyzer's get_structure method, formats the result, and handles errors.
    async def get_repo_structure(sub_path: Optional[str] = None, depth: Optional[int] = None) -> str:
        """Get the structure of files and directories in the repository.
        
        Args:
            sub_path: Optional subdirectory path relative to repository root
            depth: Optional maximum depth to traverse (default is 3)
        """
        if not mcp.repo_path or not mcp.analyzer:
            return "No code repository has been initialized yet. Please use initialize_repository first."
    
        try:
            target_path = mcp.repo_path
            if sub_path:
                target_path = mcp.repo_path / sub_path
                if not mcp.analyzer._is_safe_path(target_path):
                    return "Error: Invalid path - directory traversal not allowed"
    
            structure = mcp.analyzer.get_structure(
                target_path,
                sub_path or '',
                max_depth=depth
            )
            return mcp.analyzer.format_structure(structure)
        except Exception as e:
            return f"Error analyzing repository structure: {str(e)}"
  • Helper method in RepoStructureAnalyzer that formats the FileStructure object into a human-readable tree string with sizes and summaries.
    def format_structure(self, structure: FileStructure) -> str:
        """Format the file structure into a readable string."""
        output = []
    
        def format_size(size: int) -> str:
            units = ['B', 'KB', 'MB', 'GB']
            value = float(size)
            index = 0
            while value >= 1024 and index < len(units) - 1:
                value /= 1024
                index += 1
            return f"{value:.1f} {units[index]}"
    
        def format_item(item: FileStructure, level: int = 0) -> None:
            indent = '  ' * level
            
            if item.type == 'directory':
                output.append(f"{indent}๐Ÿ“ {item.path}/")
                
                if item.summary:
                    summary = item.summary
                    output.append(
                        f"{indent}   Contains: {summary.file_count} files, "
                        f"{summary.dir_count} directories, "
                        f"{format_size(summary.total_size)}"
                    )
                elif item.children:
                    for child in item.children:
                        format_item(child, level + 1)
            else:
                output.append(f"{indent}๐Ÿ“„ {item.path} ({format_size(item.size or 0)})")
    
        format_item(structure)
        return '\n'.join(output)
  • Core recursive helper method in RepoStructureAnalyzer that builds the FileStructure tree, respecting depth limits, ignore patterns, and safety checks.
    def get_structure(
        self,
        current_path: Path,
        relative_path: str = '',
        current_depth: int = 0,
        max_depth: Optional[int] = None
    ) -> FileStructure:
        """Recursively get the structure of files and directories."""
        if max_depth is None:
            max_depth = self.MAX_DEPTH
    
        # Verify path safety
        if not self._is_safe_path(current_path):
            raise ValueError(f"Invalid path: {current_path}")
    
        # Skip symbolic links
        if current_path.is_symlink():
            raise ValueError(f"Symbolic links are not supported: {current_path}")
    
        stats = current_path.stat()
        rel_path = relative_path or current_path.name
    
        if relative_path and self.should_ignore(relative_path):
            raise ValueError(f"Path {relative_path} is ignored")
    
        if current_path.is_file():
            return FileStructure(
                path=rel_path,
                type="file",
                size=stats.st_size
            )
    
        if current_path.is_dir():
            children = []
            summary = Summary()
    
            if current_depth < max_depth:
                try:
                    entries = list(current_path.iterdir())
                    
                    for entry in entries:
                        if len(children) >= self.MAX_CHILDREN:
                            if entry.is_file() and not entry.is_symlink():
                                summary.file_count += 1
                                summary.total_size += entry.stat().st_size
                            elif entry.is_dir() and not entry.is_symlink():
                                summary.dir_count += 1
                            continue
    
                        entry_relative_path = str(entry.relative_to(self.repo_path))
    
                        try:
                            if self.should_ignore(entry_relative_path):
                                continue
    
                            if entry.is_symlink():
                                continue
    
                            entry_stats = entry.stat()
                            
                            if entry.is_file():
                                summary.file_count += 1
                                summary.total_size += entry_stats.st_size
                            elif entry.is_dir():
                                summary.dir_count += 1
    
                            child = self.get_structure(
                                entry,
                                entry_relative_path,
                                current_depth + 1,
                                max_depth
                            )
                            children.append(child)
    
                        except Exception as error:
                            print(f"Error processing {entry}: {error}")
                            continue
    
                except Exception as error:
                    print(f"Error reading directory {current_path}: {error}")
    
            return FileStructure(
                path=rel_path,
                type="directory",
                children=children if children else None,
                summary=summary if current_depth >= max_depth or len(children) >= self.MAX_CHILDREN else None
            )
    
        raise ValueError(f"Unsupported file type at {current_path}")
  • Docstring defining the input parameters and purpose, used by MCP for tool schema.
    """Get the structure of files and directories in the repository.
    
    Args:
        sub_path: Optional subdirectory path relative to repository root
        depth: Optional maximum depth to traverse (default is 3)
    """

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/saiprashanths/code-analysis-mcp'

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