# Performance of Recursive Directory Listing with Depth in Desktop Commander MCP

> Explore the performance of recursive directory listing with depth in Desktop Commander MCP. Learn how it prevents unbounded traversal and optimizes performance.

- Repository: [Eduard Ruzga/DesktopCommanderMCP](https://github.com/wonderwhy-er/DesktopCommanderMCP)
- Tags: performance
- Published: 2026-07-12

---

**Desktop Commander MCP implements a depth-limited recursive directory listing in [`src/tools/filesystem.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts) that caps sub-directory entries at 100 items and uses iterative depth decrementing to prevent unbounded traversal.**

Desktop Commander MCP is a Model Context Protocol server that provides secure filesystem access for AI assistants. Understanding the **performance of recursive directory listing with depth in MCP** is critical for developers building file management tools that must handle large directory trees without blocking the event loop or consuming excessive memory.

## How Recursive Directory Listing Works in Desktop Commander MCP

### Entry Point and Security Validation

The `listDirectory` function in [`src/tools/filesystem.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts) serves as the primary entry point. It accepts a `dirPath` string and an optional `depth` parameter defaulting to `2`. Before any filesystem access, it validates the path through `validatePath` to enforce MCP's security sandbox.

```typescript
export async function listDirectory(dirPath: string, depth: number = 2): Promise<string[]> {
  // Security validation and initialization
  validatePath(dirPath);
  const result: string[] = [];
  // Delegation to recursive helper...
}

```

### The Recursive Traversal Engine

The internal `listRecursive` helper performs the actual filesystem walk. It accepts `currentPath`, `currentDepth`, and `relativePath` parameters, tracking depth through the recursion stack. Each call decrements the depth counter (`currentDepth - 1`) until reaching zero.

```typescript
async function listRecursive(
  currentPath: string, 
  currentDepth: number, 
  relativePath: string = '', 
  isTopLevel: boolean = true
): Promise<void> {
  // Depth-controlled traversal logic
}

```

### Depth Control and Safety Limits

The implementation guards against excessive recursion using a simple depth check: `if (currentDepth <= 0) return;`. This ensures the traversal stops exactly at the requested level, preventing accidental deep crawls of massive directory structures.

The recursion step explicitly passes the decremented depth:

```typescript
await listRecursive(fullPath, currentDepth - 1, displayPath, false);

```

## Performance Optimizations and Memory Management

### Truncation with MAX_NESTED_ITEMS

To prevent memory blow-ups, the code limits non-top-level directories to **MAX_NESTED_ITEMS** (100 entries). When truncation occurs, the output appends a warning like `[WARNING] Projects/Archive: 250 items hidden (showing first 100 of 350 total)`.

The truncation logic lives at lines 51-53 of [`src/tools/filesystem.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts):

```typescript
if (!isTopLevel && totalEntries > MAX_NESTED_ITEMS) {
  // Truncate and append warning marker
}

```

### Lazy I/O and Error Handling

The function uses `await fs.readdir` for asynchronous directory reading and only calls `fs.stat` when necessary. Errors translate to markers like `[NOT_FOUND]` or `[DENIED]` rather than thrown exceptions, allowing the traversal to continue past inaccessible directories while keeping I/O overhead minimal.

## Implementation Examples

### Default Two-Level Listing

```typescript
import { listDirectory } from './src/tools/filesystem.js';

const entries = await listDirectory('/Users/alice/Documents');
console.log(entries.join('\n'));

```

*Result (excerpt):*

```

[DIR] Projects
[FILE] notes.txt
[DIR] Projects/Archive
[FILE] Projects/report.pdf
[WARNING] Projects/Archive: 250 items hidden (showing first 100 of 350 total)

```

### Shallow Listing with Depth 1

```typescript
const shallow = await listDirectory('/Users/alice/Documents', 1);

```

Only immediate contents return; sub-directories appear as `[DIR]` entries but remain un traversed.

### Deep Listing with Depth 3

```typescript
const deep = await listDirectory('/Users/alice/Documents', 3);

```

The traversal proceeds three levels deep, respecting the truncation rule at each non-top level.

### Graceful Error Handling

```typescript
try {
  const result = await listDirectory('/path/does/not/exist', 2);
  console.log(result);
} catch (e) {
  console.error('Listing failed:', e.message);
}

```

The function returns `[NOT_FOUND]` path entries rather than throwing, allowing UI code to present helpful messages.

## Summary

- **Depth-limited recursion**: The `listDirectory` function accepts a configurable depth parameter (default 2) and decrements it at each recursive level until reaching zero.
- **Memory protection**: Non-top-level directories truncate at 100 items (`MAX_NESTED_ITEMS`) to prevent O(N) memory consumption in large folders.
- **Non-blocking I/O**: All filesystem operations use async `fs.readdir` and `fs.stat`, keeping the Node.js event loop responsive.
- **Resilient error handling**: Permission errors and missing files generate string markers (`[DENIED]`, `[NOT_FOUND]`) instead of aborting the entire operation.

## Frequently Asked Questions

### What is the default recursion depth in Desktop Commander MCP?

The default recursion depth is **2**, defined in the `listDirectory` function signature in [`src/tools/filesystem.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts). This provides a balance between showing useful context and preventing excessive filesystem scanning.

### How does MCP prevent memory issues when listing huge directories?

The implementation limits non-top-level directories to **100 entries** using the `MAX_NESTED_ITEMS` constant. When truncation occurs, the output includes a warning indicating how many items remain hidden, ensuring predictable memory usage regardless of directory size.

### Can the recursive listing continue past permission errors?

Yes. According to the source code in [`src/tools/filesystem.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts), errors from `fs.readdir` are caught and translated into user-friendly markers like `[NOT_FOUND]` or `[DENIED]`. This design allows the traversal to skip inaccessible directories and continue processing siblings rather than aborting the entire operation.

### Where does the depth decrement logic reside?

The depth check occurs at lines 27-29 of [`src/tools/filesystem.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts) with the guard clause `if (currentDepth <= 0) return;`. The recursive call at lines 63-68 passes `currentDepth - 1`, ensuring the depth limit propagates correctly through the call stack.