Skip to main content
Glama
drewster99

xcode-mcp-server (drewster99)

by drewster99
get_directory_tree.py6.28 kB
#!/usr/bin/env python3 """get_directory_tree tool - Visual directory tree""" import os from typing import List from xcode_mcp_server.server import mcp from xcode_mcp_server.config_manager import apply_config from xcode_mcp_server.security import is_path_allowed from xcode_mcp_server.exceptions import AccessDeniedError, InvalidParameterError, XCodeMCPError from xcode_mcp_server.utils.applescript import show_access_denied_notification, show_error_notification @mcp.tool() @apply_config def get_directory_tree(directory_path: str, max_depth: int = 4) -> str: """ Get a visual tree of directories (folders only) in the specified path. Shows the folder structure as a tree diagram with box-drawing characters. Does not include individual files - use get_directory_listing for file details. Special behavior: If directory_path ends with .xcodeproj or .xcworkspace, the tree will show the parent directory structure (since these are typically at the root of a project folder). Args: directory_path: Path to directory to scan. Can also be a .xcodeproj or .xcworkspace path (will scan parent directory in that case). max_depth: Maximum recursion depth (default 4, prevents excessive output). Depth 1 = immediate subdirectories only, Depth 4 = up to 4 levels deep. Returns: A visual tree representation showing only directories/folders, with a note about using get_directory_listing for file-level details. Example: /Users/you/Projects/MyApp/ ├── Sources/ │ ├── Models/ │ └── Views/ ├── Tests/ └── Resources/ """ # Validate max_depth if max_depth < 1: raise InvalidParameterError("max_depth must be at least 1") # Basic validation if not directory_path or directory_path.strip() == "": raise InvalidParameterError("directory_path cannot be empty") directory_path = directory_path.strip() # Security check if not is_path_allowed(directory_path): show_access_denied_notification(f"Access denied: {directory_path}") raise AccessDeniedError(f"Access to path '{directory_path}' is not allowed. Set XCODEMCP_ALLOWED_FOLDERS environment variable.") # Check if path exists if not os.path.exists(directory_path): show_error_notification(f"Path not found: {directory_path}") raise InvalidParameterError(f"Path does not exist: {directory_path}") # Normalize the path directory_path = os.path.realpath(directory_path) # Determine which directory to scan # If path ends with .xcodeproj or .xcworkspace, scan the parent directory if directory_path.endswith('.xcodeproj') or directory_path.endswith('.xcworkspace'): scan_dir = os.path.dirname(directory_path) else: scan_dir = directory_path # Verify scan_dir is a directory if not os.path.isdir(scan_dir): error_msg = f"Not a directory: {scan_dir}" show_error_notification(error_msg) raise InvalidParameterError(f"Path is not a directory: {scan_dir}") # Build the hierarchy (directories only) def build_hierarchy(path: str, prefix: str = "", is_last: bool = True, base_path: str = "", current_depth: int = 0) -> List[str]: """Recursively build a visual hierarchy of directories only""" lines = [] if not base_path: base_path = path # Add current item (only if it's a directory and not the base) if path != base_path: connector = "└── " if is_last else "├── " name = os.path.basename(path) + "/" lines.append(prefix + connector + name) # Update prefix for children extension = " " if is_last else "│ " prefix = prefix + extension # Check if we've reached max depth if current_depth >= max_depth: return lines # If it's a directory, recurse into it (with restrictions) if os.path.isdir(path): # Skip certain directories if os.path.basename(path) in ['.build', 'build', 'DerivedData']: return lines # Don't recurse into .xcodeproj or .xcworkspace directories if path.endswith('.xcodeproj') or path.endswith('.xcworkspace'): return lines try: items = sorted(os.listdir(path)) # Filter to directories only, exclude hidden except for important ones dir_items = [] for item in items: item_path = os.path.join(path, item) if os.path.isdir(item_path): # Include if not hidden, or if it's an important hidden dir if not item.startswith('.') or item in ['.git']: dir_items.append(item) for i, item in enumerate(dir_items): item_path = os.path.join(path, item) is_last_item = (i == len(dir_items) - 1) lines.extend(build_hierarchy(item_path, prefix, is_last_item, base_path, current_depth + 1)) except PermissionError: pass return lines # Build hierarchy starting from scan directory hierarchy_lines = [scan_dir + "/"] try: items = sorted(os.listdir(scan_dir)) # Filter to directories only dir_items = [] for item in items: item_path = os.path.join(scan_dir, item) if os.path.isdir(item_path): if not item.startswith('.') or item in ['.git']: dir_items.append(item) for i, item in enumerate(dir_items): item_path = os.path.join(scan_dir, item) is_last_item = (i == len(dir_items) - 1) hierarchy_lines.extend(build_hierarchy(item_path, "", is_last_item, scan_dir, 1)) except Exception as e: raise XCodeMCPError(f"Error building directory tree for {directory_path}: {str(e)}") tree_output = '\n'.join(hierarchy_lines) return tree_output + "\n\nUse `get_directory_listing` to see files and details for a specific directory."

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/drewster99/xcode-mcp-server'

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