How the `list_directory` Tool Handles Recursive Listings with Context Overflow Protection

The list_directory tool enforces a default depth limit of 2 levels and caps nested directories at 100 items each, with explicit warnings when truncation occurs.

Recursively listing directories in an AI-powered environment requires strict safeguards. The DesktopCommanderMCP repository implements list_directory as a bounded, deterministic tool that prevents massive file trees from overwhelming model context windows while delivering useful hierarchical data.

Depth-Based Recursion Control

The tool accepts an optional depth parameter that defaults to 2 levels. This limit propagates through the internal listRecursive helper function, which terminates early when currentDepth <= 0.

In [src/tools/filesystem.ts](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts#L720-L785), the recursion logic follows this pattern:

async function listRecursive(
  dirPath: string,
  currentDepth: number,
  prefix: string = ''
): Promise<string[]> {
  if (currentDepth <= 0) {
    return []; // Hard stop at depth limit
  }
  
  const entries = await fs.readdir(dirPath, { withFileTypes: true });
  // ... process and recurse for subdirectories with currentDepth - 1
}

This approach guarantees predictable output size regardless of how deeply nested the actual filesystem may be.

Per-Directory Item Limits (Context Overflow Protection)

The core overflow protection mechanism is MAX_NESTED_ITEMS = 100, applied to every directory except the top-level target. When a nested directory contains more than 100 entries, the tool:

  • Emits exactly 100 formatted lines
  • Appends a warning indicating the hidden count
  • Continues recursion only on the shown items

This prevents notoriously large directories—such as node_modules/, .git/objects/, or vendor/—from saturating the response.

Warning and Visibility System

When truncation occurs, the tool inserts an explicit warning line:


[WARNING] /path/to/large-dir: 237 items hidden (showing first 100 of 337 total)

This pattern appears in the implementation at approximately line 765 of filesystem.ts. The warning serves two purposes: it keeps users informed of data completeness, and it signals to downstream AI processors that the listing is partial.

Robust Error Handling

The tool distinguishes multiple failure modes with structured prefixes:

Error Type Prefix Typical Cause
Not found [NOT_FOUND] ENOENT—path does not exist
Access denied [DENIED] EPERM, EACCES, ETIMEDOUT—permission or timeout issues
General error [ERROR] Unexpected fs failures

Each error produces a single descriptive line rather than throwing, allowing the listing to continue for accessible portions of the requested tree.

Path Validation Before Recursion

Before entering any subdirectory, the tool invokes validatePath(fullPath) as implemented in the same file. Failed validation causes silent skipping of that branch, with the entry already marked appropriately. This enforces sandbox boundaries and prevents traversal outside allowed roots.

Output Format and Parser Compatibility

Every emitted line uses a machine-readable prefix convention:

[DIR]  relative/path/to/directory
[FILE] relative/path/to/file.ext

This format requires no additional path manipulation by consuming code, making it ideal for both human-readable tree views and automated parsing by AI agents.

Complete Usage Examples

Default shallow listing (depth 2)

const entries = await listDirectory('./src');
// Output: ['[DIR] components', '[FILE] index.ts', '[DIR] utils', ...]

Explicit deep listing (depth 4)

const deep = await listDirectory('/home/user/projects', 4);

Triggering overflow protection

const limited = await listDirectory('/var/log', 2);
// May include: '[WARNING] /var/log/nginx: 412 items hidden (showing first 100 of 512 total)'

Handling inaccessible paths

const result = await listDirectory('/root/secret');
// Output: ['[DENIED] /root/secret — not accessible (permission denied)']

Source File References

File Lines Responsibility
[src/tools/filesystem.ts](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts#L720-L785) 720–785 Core listDirectory implementation with overflow protection
[src/handlers/filesystem-handlers.ts](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/handlers/filesystem-handlers.ts) Tool registration and CLI integration
[src/utils/files/base.ts](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/files/base.ts) Notes read_file fallback to list_directory for directories

Summary

  • Hard depth limit (default: 2) prevents unbounded recursion regardless of filesystem depth
  • MAX_NESTED_ITEMS = 100 caps per-directory output, with explicit truncation warnings
  • Structured error prefixes maintain flow continuity when individual paths fail
  • validatePath enforcement preserves sandbox boundaries at every recursion step
  • Machine-readable format supports both AI parsing and human tree rendering

Frequently Asked Questions

What happens if I request depth 0 or a negative number?

The tool treats depth <= 0 as a request for zero recursion, returning only the top-level directory entry itself with no children enumerated.

Why is the 100-item limit applied only to nested directories?

The top-level directory is exempt from MAX_NESTED_ITEMS to ensure the user's explicitly requested target is fully visible. Subdirectories receive the limit because they are discovered incidentally and may contain unbounded automatic-generated content.

Can the overflow limits be configured at runtime?

No. Both the default depth (2) and MAX_NESTED_ITEMS (100) are compile-time constants in the current implementation. Callers must implement additional filtering if they need different bounds.

Each recursion step validates the path before proceeding, and the depth limit provides an absolute upper bound on traversal. The tool does not maintain a visited-set for symlink detection, relying instead on depth exhaustion to prevent infinite loops.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →