Skip to content

filesystem: recursive search can hang on macOS CloudStorage / lazy provider paths #4162

@alemuenchen

Description

@alemuenchen

Hi — thanks for maintaining the filesystem server.

I'm filing this against @modelcontextprotocol/server-filesystem after several weeks of production use on macOS with provider-backed directories in allowedDirectories,
especially:

  • ~/Library/CloudStorage/GoogleDrive-.../...
  • ~/Library/Mobile Documents/com~apple~CloudDocs/...

Symptom

When allowedDirectories includes macOS CloudStorage / lazy provider paths, search_files and other operations that call validatePath() can intermittently hang for minutes.
Claude Desktop eventually reports the MCP server as unresponsive after roughly 4 minutes. The subprocess remains alive, but subsequent filesystem calls may continue to hang until
the server is restarted.

This may overlap with reports like #3281, but I'm filing separately because this issue points to specific filesystem code paths.

Code paths

In src/filesystem/lib.ts, validatePath() calls:

const realPath = await fs.realpath(absolute);

and, in the ENOENT branch:

const realParentPath = await fs.realpath(parentDir);

These calls have no timeout. On macOS provider-backed paths that are not locally materialized, realpath can block while the provider fetches metadata.

searchFilesWithValidation() then recursively does:

const entries = await fs.readdir(currentPath, { withFileTypes: true });
...
await validatePath(fullPath);
...
if (entry.isDirectory()) {
  await search(fullPath);
}

As far as I can tell, recursive search currently has no upper bound on visited entries, no timeout around readdir, and no abort path. A large or lazy-materialized tree can
therefore keep the server busy for a long time.

Why this matters

This is especially visible with CloudStorage / FileProvider-backed folders such as Google Drive and iCloud Drive, where metadata for subdirectories may be fetched lazily. It can
also affect very large local trees.

The libuv threadpool angle may make the symptom worse: filesystem operations use libuv's threadpool, whose default size is 4. A small number of slow filesystem calls can
therefore degrade unrelated filesystem operations in the same process. I mention this as a contributing factor, not necessarily as the main fix.

Suggested mitigations

The two minimal mitigations I'd suggest are:

  1. Add a timeout wrapper around fs.realpath in validatePath() and around fs.readdir in recursive search.

  2. Add a configurable maximum visited-entry count for search_files, returning a clear error such as:

    Search aborted after visiting N entries. Please refine the pattern or narrow the search path.

Optional follow-ups:

  • Document how to exclude / avoid recursive search over CloudStorage-style folders.
  • Consider an opt-in exclude-prefix configuration for recursive search.
  • Document UV_THREADPOOL_SIZE tuning for users who intentionally expose large / slow provider-backed trees.

I have tested equivalent mitigations locally in a patched installed build for several weeks with Google Drive and iCloud Drive paths in allowedDirectories. I'm not opening a PR
because the exact configuration surface — env vars vs config object, defaults, and docs placement — seems like a maintainer policy decision, but I'd be happy to test any
proposed fix.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions