Skip to main content
Glama
safurrier

MCP Filesystem Server

directory_tree

Generate a recursive tree view of files and directories with customizable depth, filtering, and output formats.

Instructions

Get a recursive tree view of files and directories.

Args: path: Root directory max_depth: Maximum recursion depth include_files: Whether to include files (not just directories) pattern: Optional glob pattern to filter entries exclude_patterns: Optional patterns to exclude format: Output format ('text' or 'json') ctx: MCP context Returns: Formatted directory tree

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
pathYes
max_depthNo
include_filesNo
patternNo
exclude_patternsNo
formatNotext

Implementation Reference

  • MCP tool handler and registration for 'directory_tree'. Dispatches to JSON or formatted output based on 'format' parameter.
    @mcp.tool() async def directory_tree( path: str, ctx: Context, max_depth: int = 3, include_files: bool = True, pattern: Optional[str] = None, exclude_patterns: Optional[List[str]] = None, format: str = "text", ) -> str: """Get a recursive tree view of files and directories. Args: path: Root directory max_depth: Maximum recursion depth include_files: Whether to include files (not just directories) pattern: Optional glob pattern to filter entries exclude_patterns: Optional patterns to exclude format: Output format ('text' or 'json') ctx: MCP context Returns: Formatted directory tree """ try: components = get_components() if format.lower() == "json": tree = await components["advanced"].directory_tree( path, max_depth, include_files, pattern, exclude_patterns ) return json.dumps(tree, indent=2) else: tree_text = await components["advanced"].directory_tree_formatted( path, max_depth, include_files, pattern, exclude_patterns ) return tree_text except Exception as e: return f"Error creating directory tree: {str(e)}"
  • Data class for directory tree nodes, with methods to convert to dict (JSON output) and format as tree text.
    class DirectoryTreeNode: """Node in a directory tree.""" def __init__(self, path: Path, is_dir: bool = False, depth: int = 0): """Initialize a tree node. Args: path: Path this node represents is_dir: Whether this is a directory depth: Depth in the tree (0 = root) """ self.path = path self.name = path.name or str(path) # Use path string for root self.is_dir = is_dir self.depth = depth self.children: List["DirectoryTreeNode"] = [] def add_child(self, child: "DirectoryTreeNode") -> None: """Add a child node. Args: child: Child node to add """ self.children.append(child) def to_dict(self) -> Dict: """Convert to dictionary representation. Returns: Dictionary representing this node and its children """ result: Dict[str, Union[str, List[Dict[str, Any]]]] = { "name": self.name, "path": str(self.path), "type": "directory" if self.is_dir else "file", } if self.is_dir: result["children"] = [child.to_dict() for child in self.children] return result def format(self, include_files: bool = True, line_prefix: str = "") -> List[str]: """Format this node as text lines. Args: include_files: Whether to include files (not just directories) line_prefix: Prefix for each line (used for recursion) Returns: List of formatted lines """ result: List[str] = [] # Skip files if not requested if not include_files and not self.is_dir: return result # Format this node node_type = "📁" if self.is_dir else "📄" result.append(f"{line_prefix}{node_type} {self.name}") # Format children if self.children: for i, child in enumerate( sorted(self.children, key=lambda x: (not x.is_dir, x.name)) ): is_last = i == len(self.children) - 1 if is_last: child_prefix = f"{line_prefix}└── " next_prefix = f"{line_prefix} " else: child_prefix = f"{line_prefix}├── " next_prefix = f"{line_prefix}│ " result.extend(child.format(include_files, child_prefix + next_prefix)) return result
  • Builds the directory tree structure as a nested dict, called by handler for JSON format.
    async def directory_tree( self, root_path: Union[str, Path], max_depth: int = 3, include_files: bool = True, pattern: Optional[str] = None, exclude_patterns: Optional[List[str]] = None, ) -> Dict: """Build a directory tree structure. Args: root_path: Root directory for the tree max_depth: Maximum depth to traverse include_files: Whether to include files (not just directories) pattern: Optional glob pattern to filter entries exclude_patterns: Optional patterns to exclude Returns: Dictionary representation of the directory tree Raises: ValueError: If root_path is outside allowed directories """ abs_path, allowed = await self.validator.validate_path(root_path) if not allowed: raise ValueError(f"Path outside allowed directories: {root_path}") if not abs_path.is_dir(): raise ValueError(f"Not a directory: {root_path}") # Compile exclude patterns if provided exclude_regexes = [] if exclude_patterns: for exclude in exclude_patterns: try: exclude_regexes.append(re.compile(exclude)) except re.error: logger.warning(f"Invalid exclude pattern: {exclude}") # Create root node root_node = DirectoryTreeNode(abs_path, True, 0) # Build tree recursively await self._build_tree_node( root_node, max_depth, include_files, pattern, exclude_regexes ) return root_node.to_dict()
  • Builds the directory tree and formats it as ASCII art text, called by handler for text format.
    async def directory_tree_formatted( self, root_path: Union[str, Path], max_depth: int = 3, include_files: bool = True, pattern: Optional[str] = None, exclude_patterns: Optional[List[str]] = None, ) -> str: """Build a formatted directory tree. Args: root_path: Root directory for the tree max_depth: Maximum depth to traverse include_files: Whether to include files (not just directories) pattern: Optional glob pattern to filter entries exclude_patterns: Optional patterns to exclude Returns: Formatted string representation of the directory tree """ abs_path, allowed = await self.validator.validate_path(root_path) if not allowed: raise ValueError(f"Path outside allowed directories: {root_path}") if not abs_path.is_dir(): raise ValueError(f"Not a directory: {root_path}") # Compile exclude patterns if provided exclude_regexes = [] if exclude_patterns: for exclude in exclude_patterns: try: exclude_regexes.append(re.compile(exclude)) except re.error: logger.warning(f"Invalid exclude pattern: {exclude}") # Create root node root_node = DirectoryTreeNode(abs_path, True, 0) # Build tree recursively await self._build_tree_node( root_node, max_depth, include_files, pattern, exclude_regexes ) # Format the tree formatted = root_node.format(include_files) return "\n".join(formatted)
  • Recursive helper that traverses directories, applies filters, and builds the tree nodes.
    async def _build_tree_node( self, node: DirectoryTreeNode, max_depth: int, include_files: bool, pattern: Optional[str], exclude_regexes: List[re.Pattern], ) -> None: """Recursively build a directory tree node. Args: node: Current node to populate max_depth: Maximum depth to traverse include_files: Whether to include files pattern: Optional glob pattern to filter entries exclude_regexes: Compiled regular expressions to exclude """ # Stop if we've reached the maximum depth if node.depth >= max_depth: return try: entries = await anyio.to_thread.run_sync(list, node.path.iterdir()) for entry in entries: # Skip if matched by exclude pattern path_str = str(entry) excluded = False for exclude_re in exclude_regexes: if exclude_re.search(path_str): excluded = True break if excluded: continue # Apply pattern filter if specified if pattern and not entry.match(pattern): continue try: is_dir = entry.is_dir() # Skip files if not requested if not include_files and not is_dir: continue # Create and add the child node child = DirectoryTreeNode(entry, is_dir, node.depth + 1) node.add_child(child) # Recursively build the tree for directories if is_dir: await self._build_tree_node( child, max_depth, include_files, pattern, exclude_regexes ) except (PermissionError, FileNotFoundError): # Skip entries we can't access pass except (PermissionError, FileNotFoundError): # Skip directories we can't access pass

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/safurrier/mcp-filesystem'

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