Optimize Large Directory Listings Using Depth and Pagination in Desktop Commander MCP

Desktop Commander MCP prevents LLM context overflow by combining depth-limited recursion, a 100-item per-directory cap, and on-demand pagination via the list_directory tool.

Desktop Commander MCP, an open-source Model Context Protocol server by wonderwhy-er, provides sophisticated filesystem tooling designed to handle massive directory trees without exhausting token budgets. When you need to explore large codebases or directories containing thousands of files, the list_directory tool employs a three-layer defense mechanism to optimize large directory listings using depth and pagination.

How Depth-Limited Recursion Works

The foundation of Desktop Commander's optimization strategy lies in controlled recursion depth. Instead of walking entire directory trees indefinitely, the tool respects a configurable depth parameter that defaults to two levels.

The Core Algorithm in filesystem.ts

In src/tools/filesystem.ts, the listDirectory function implements recursive traversal with an explicit depth counter:

// src/tools/filesystem.ts (lines 27-34)
if (currentDepth <= 0) return;
// ... process directory ...
await listRecursive(fullPath, currentDepth - 1, ...);

Each recursive call decrements the currentDepth parameter. When the counter reaches zero, the traversal stops, preventing the tool from descending into deeply nested structures like node_modules or .git directories. The default value of depth: 2 strikes a balance between providing useful context and maintaining concise output.

Context Protection Through Item Caps

Beyond depth control, Desktop Commander implements a hard limit on the number of items displayed per nested directory to prevent individual folders from flooding the context window.

The MAX_NESTED_ITEMS Guard

The same src/tools/filesystem.ts file defines a constant MAX_NESTED_ITEMS = 100 that caps visibility for non-top-level directories:

// src/tools/filesystem.ts (lines 51-81)
if (!isTopLevel && totalEntries > MAX_NESTED_ITEMS) {
    entriesToShow = entries.slice(0, MAX_NESTED_ITEMS);
    filteredCount = totalEntries - MAX_NESTED_ITEMS;
}

if (filteredCount > 0) {
    results.push(`[WARNING] ${displayPath}: ${filteredCount} items hidden ...`);
}

When a directory exceeds 100 items, the tool emits only the first 100 entries followed by a [WARNING] marker indicating how many items remain hidden. This approach ensures that a single directory with thousands of files cannot monopolize the LLM's context window.

On-Demand Pagination for Deep Dives

The third optimization layer involves user-driven pagination, allowing selective expansion of truncated directories only when needed.

The Load More Pattern in the UI

The frontend component in src/ui/file-preview/src/directory-controller.ts renders interactive "Load More" buttons for any directory that triggered the item cap warning. When activated, it requests the full directory listing with depth: 1:

// src/ui/file-preview/src/directory-controller.ts (lines 182-194)
const result = await options.callTool?.('list_directory', { 
  path: loadPath, 
  depth: 1, 
  origin: 'ui' 
});

This lazy-loading approach keeps initial responses lightweight while preserving the ability to inspect large directories fully. Users drill down only into directories relevant to their current task, maintaining optimal token efficiency.

LLM Integration and Schema Documentation

The list_directory tool schema in src/server.ts (lines 774-892) explicitly documents these optimization features for the LLM. The description advises the model on proper depth usage and explains the context overflow protection mechanism, ensuring the LLM understands when to request deeper listings versus accepting the truncated summary.

According to the schema definition, valid depth values include:

  • depth: 1 — Only direct contents
  • depth: 2 — Contents plus one subdirectory level (default)
  • depth: 3+ — Multiple levels deep

Practical Implementation Examples

Listing with Default Depth Protection

To list a directory using the default safety settings:

await callTool('list_directory', {
  path: '/Users/alice/large-project',
  // depth defaults to 2
});

Expected output:


[DIR] src
[FILE] src/index.ts
[DIR] src/tools
[FILE] src/tools/filesystem.ts
[WARNING] node_modules: 3522 items hidden (showing first 100 of 3622 total)

Expanding a Large Directory on Demand

When encountering a warning, retrieve the complete listing for that specific directory:

await callTool('list_directory', {
  path: '/Users/alice/large-project/node_modules',
  depth: 1  // List all immediate children
});

Custom Depth for Specific Exploration

For targeted deep inspection:

await callTool('list_directory', {
  path: '/var/log',
  depth: 3  // Navigate three levels deep
});

Handling Access Errors

The tool also handles filesystem errors gracefully, returning structured markers:

// Error handling in src/tools/filesystem.ts
if (err.code === 'ENOENT') {
  results.push(`[NOT_FOUND] ${displayPath} — path does not exist`);
} else if (err.code === 'EPERM' || err.code === 'EACCES') {
  results.push(`[DENIED] ${displayPath} — not accessible`);
}

Summary

  • Depth-limited recursion in src/tools/filesystem.ts prevents runaway traversal by decrementing a currentDepth counter until reaching zero, with a sensible default of two levels.
  • Per-directory caps enforce a maximum of 100 items per nested folder via MAX_NESTED_ITEMS, emitting [WARNING] markers when truncation occurs.
  • On-demand pagination allows users to expand truncated directories selectively through the UI controller in src/ui/file-preview/src/directory-controller.ts, fetching full listings only when explicitly requested.
  • Schema documentation in src/server.ts ensures the LLM understands these constraints and can make informed decisions about depth parameters.
  • Error resilience provides clear [NOT_FOUND] and [DENIED] markers when filesystem access fails, maintaining robust operation across permission boundaries.

Frequently Asked Questions

What is the default depth for directory listings in Desktop Commander MCP?

The list_directory tool defaults to depth: 2, meaning it displays the target directory's immediate contents plus one level of subdirectories. This default prevents accidental enumeration of massive trees like node_modules while still providing useful structural context. You can override this by specifying depth: 1 for flat listings or higher values for deeper exploration.

How does Desktop Commander handle directories with more than 100 items?

When a nested directory contains more than 100 items, the tool truncates the output to the first 100 entries and appends a [WARNING] message indicating the total count of hidden items. For example: [WARNING] node_modules: 3522 items hidden (showing first 100 of 3622 total). The top-level directory remains exempt from this cap to ensure root visibility.

Can I paginate through large directories programmatically?

Yes. While the UI provides "Load More" buttons that trigger list_directory calls with depth: 1, you can implement the same pattern programmatically. When you encounter a [WARNING] marker in the output, issue a new list_directory request targeting that specific subdirectory with an appropriate depth parameter to retrieve the complete listing.

Where is the depth parameter validated in the codebase?

The depth parameter is defined in src/tools/schemas.ts using Zod schema validation, ensuring type safety before reaching the core logic in src/tools/filesystem.ts. The tool description in src/server.ts (lines 774-892) further documents the parameter's behavior for the LLM, explaining how different depth values affect the traversal scope.

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 →