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
| Name | Required | Description | Default |
|---|---|---|---|
| depth | No | ||
| sub_path | No |
Implementation Reference
- code_analysis.py:453-479 (handler)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)}"
- code_analysis.py:105-193 (helper)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}")
- code_analysis.py:66-99 (helper)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)
- code_analysis.py:453-453 (registration)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()
- code_analysis.py:454-460 (schema)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) """