Skip to main content
Glama
saiprashanths

Code Analysis MCP Server

get_repo_structure

Retrieve the hierarchical structure of files and directories within a repository, specifying subdirectory paths and traversal depth for precise 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
depthNo
sub_pathNo

Implementation Reference

  • The @mcp.tool() decorator registers the tool and the async function implements the core logic: checks initialization, resolves path, calls analyzer.get_structure and format_structure to return the repo tree string.
    @mcp.tool() 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)}"
  • Core recursive logic to build the FileStructure tree, respecting gitignore, depth limits, child limits, path safety, symlinks. Called by the tool handler.
    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}")
  • Formats the FileStructure tree into a human-readable string with emojis, sizes, summaries for dirs.
    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)
  • The @mcp.tool() decorator registers the get_repo_structure function as an MCP tool, likely inferring name from function name and schema from signature/docstring.
    @mcp.tool()
  • Type hints and docstring define the input schema (optional sub_path:str, depth:int) and output str (formatted tree). Used by MCP framework for tool schema.
    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) """

Other Tools

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

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