Skip to main content
Glama

list_directory

Lists files and directories in a specified path with clear [FILE] and [DIR] labels, supports recursive listing with depth control, and includes overflow protection for large directories.

Instructions

                    Get a detailed listing of all files and directories in a specified path.
                    
                    Use this instead of 'execute_command' with ls/dir commands.
                    Results distinguish between files and directories with [FILE] and [DIR] prefixes.
                    
                    Supports recursive listing with the 'depth' parameter (default: 2):
                    - depth=1: Only direct contents of the directory
                    - depth=2: Contents plus one level of subdirectories
                    - depth=3+: Multiple levels deep
                    
                    CONTEXT OVERFLOW PROTECTION:
                    - Top-level directory shows ALL items
                    - Nested directories are limited to 100 items maximum per directory
                    - When a nested directory has more than 100 items, you'll see a warning like:
                      [WARNING] node_modules: 500 items hidden (showing first 100 of 600 total)
                    - This prevents overwhelming the context with large directories like node_modules
                    
                    Results show full relative paths from the root directory being listed.
                    Example output with depth=2:
                    [DIR] src
                    [FILE] src/index.ts
                    [DIR] src/tools
                    [FILE] src/tools/filesystem.ts
                    
                    If a directory cannot be accessed, it will show [DENIED] instead.
                    Only works within allowed directories.
                    
                    IMPORTANT: Always use absolute paths for reliability. Paths are automatically normalized regardless of slash direction. Relative paths may fail as they depend on the current working directory. Tilde paths (~/...) might not work in all contexts. Unless the user explicitly asks for relative paths, use absolute paths.
                    This command can be referenced as "DC: ..." or "use Desktop Commander to ..." in your instructions.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
pathYes
depthNo

Implementation Reference

  • The MCP tool handler function 'handleListDirectory' that validates input arguments using ListDirectoryArgsSchema, calls the listDirectory helper, measures execution time, joins results with newlines, and returns formatted ServerResult or error response.
    /**
     * Handle list_directory command
     */
    export async function handleListDirectory(args: unknown): Promise<ServerResult> {
        try {
            const startTime = Date.now();
            const parsed = ListDirectoryArgsSchema.parse(args);
            const entries = await listDirectory(parsed.path, parsed.depth);
            const duration = Date.now() - startTime;
    
            const resultText = entries.join('\n');
    
            return {
                content: [{ type: "text", text: resultText }],
            };
        } catch (error) {
            const errorMessage = error instanceof Error ? error.message : String(error);
            return createErrorResponse(errorMessage);
        }
    }
  • Zod input validation schema for the list_directory tool defining required 'path' (string) and optional 'depth' (number, default 2). Used in handler and tool registration.
    export const ListDirectoryArgsSchema = z.object({
      path: z.string(),
      depth: z.number().optional().default(2),
    });
  • src/server.ts:437-474 (registration)
    Tool registration in the MCP server's list_tools handler: defines name 'list_directory', detailed description of recursive listing with depth and protections, inputSchema from ListDirectoryArgsSchema, and read-only annotations.
    {
        name: "list_directory",
        description: `
                Get a detailed listing of all files and directories in a specified path.
                
                Use this instead of 'execute_command' with ls/dir commands.
                Results distinguish between files and directories with [FILE] and [DIR] prefixes.
                
                Supports recursive listing with the 'depth' parameter (default: 2):
                - depth=1: Only direct contents of the directory
                - depth=2: Contents plus one level of subdirectories
                - depth=3+: Multiple levels deep
                
                CONTEXT OVERFLOW PROTECTION:
                - Top-level directory shows ALL items
                - Nested directories are limited to 100 items maximum per directory
                - When a nested directory has more than 100 items, you'll see a warning like:
                  [WARNING] node_modules: 500 items hidden (showing first 100 of 600 total)
                - This prevents overwhelming the context with large directories like node_modules
                
                Results show full relative paths from the root directory being listed.
                Example output with depth=2:
                [DIR] src
                [FILE] src/index.ts
                [DIR] src/tools
                [FILE] src/tools/filesystem.ts
                
                If a directory cannot be accessed, it will show [DENIED] instead.
                Only works within allowed directories.
                
                ${PATH_GUIDANCE}
                ${CMD_PREFIX_DESCRIPTION}`,
        inputSchema: zodToJsonSchema(ListDirectoryArgsSchema),
        annotations: {
            title: "List Directory Contents",
            readOnlyHint: true,
        },
    },
  • Handler dispatch registration in MCP server's call_tool switch statement: maps 'list_directory' tool calls to handlers.handleListDirectory.
    case "list_directory":
        result = await handlers.handleListDirectory(args);
        break;
  • Core helper function implementing recursive directory listing up to specified depth. Validates paths, handles permissions ([DENIED]), limits nested directories to 100 items with warnings, formats output with [DIR]/[FILE] prefixes and relative paths.
    export async function listDirectory(dirPath: string, depth: number = 2): Promise<string[]> {
        const validPath = await validatePath(dirPath);
        const results: string[] = [];
    
        const MAX_NESTED_ITEMS = 100; // Maximum items to show per nested directory
    
        async function listRecursive(currentPath: string, currentDepth: number, relativePath: string = '', isTopLevel: boolean = true): Promise<void> {
            if (currentDepth <= 0) return;
    
            let entries;
            try {
                entries = await fs.readdir(currentPath, { withFileTypes: true });
            } catch (error) {
                // If we can't read this directory (permission denied), show as denied
                const displayPath = relativePath || path.basename(currentPath);
                results.push(`[DENIED] ${displayPath}`);
                return;
            }
    
            // Apply filtering for nested directories (not top level)
            const totalEntries = entries.length;
            let entriesToShow = entries;
            let filteredCount = 0;
    
            if (!isTopLevel && totalEntries > MAX_NESTED_ITEMS) {
                entriesToShow = entries.slice(0, MAX_NESTED_ITEMS);
                filteredCount = totalEntries - MAX_NESTED_ITEMS;
            }
    
            for (const entry of entriesToShow) {
                const fullPath = path.join(currentPath, entry.name);
                const displayPath = relativePath ? path.join(relativePath, entry.name) : entry.name;
    
                // Add this entry to results
                results.push(`${entry.isDirectory() ? "[DIR]" : "[FILE]"} ${displayPath}`);
    
                // If it's a directory and we have depth remaining, recurse
                if (entry.isDirectory() && currentDepth > 1) {
                    try {
                        // Validate the path before recursing
                        await validatePath(fullPath);
                        await listRecursive(fullPath, currentDepth - 1, displayPath, false);
                    } catch (error) {
                        // If validation fails or we can't access it, it will be marked as denied
                        // when we try to read it in the recursive call
                        continue;
                    }
                }
            }
    
            // Add warning message if items were filtered
            if (filteredCount > 0) {
                const displayPath = relativePath || path.basename(currentPath);
                results.push(`[WARNING] ${displayPath}: ${filteredCount} items hidden (showing first ${MAX_NESTED_ITEMS} of ${totalEntries} total)`);
            }
        }
    
        await listRecursive(validPath, depth, '', true);
        return results;
    }

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/wonderwhy-er/ClaudeComputerCommander'

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