modelcontextprotocol / modelcontextprotocol/servers

server-filesystem: MCP roots protocol overwrites CLI-provided allowed directories

Open Beginner friendly
#3,602 2 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
90.5k
Forks
11.7k
Avg merge
2d 2h
Merged PRs (30d)
5

Description

Description

When the MCP client supports the roots protocol, the filesystem server's oninitialized handler replaces all command-line allowed directories with only the roots provided by the client. This means any additional directories passed via CLI args are silently discarded.

Steps to Reproduce

  1. Configure the filesystem MCP server with multiple allowed directories via CLI args:
    npx @modelcontextprotocol/server-filesystem /home/user /mnt/Storage /mnt/Games /mnt/Emulators
    
  2. Connect from a client that supports the MCP roots protocol (e.g., Claude Code) where the working directory is /home/user
  3. Call list_allowed_directories

Expected Behavior

All four directories should be listed as allowed:

/home/user
/mnt/Storage
/mnt/Games
/mnt/Emulators

Actual Behavior

Only the client-provided root is listed:

/home/user

The other three directories are silently dropped and become inaccessible.

Root Cause

In dist/index.js, the oninitialized handler (around line 564) unconditionally replaces allowedDirectories with the client roots when the client supports the roots protocol:

server.server.oninitialized = async () => {
    const clientCapabilities = server.server.getClientCapabilities();
    if (clientCapabilities?.roots) {
        const response = await server.server.listRoots();
        if (response && 'roots' in response) {
            await updateAllowedDirectoriesFromRoots(response.roots);
        }
    }
};

And updateAllowedDirectoriesFromRoots does a full replacement:

allowedDirectories = [...validatedRootDirs];

Suggested Fix

CLI-provided directories should be preserved and merged with client roots, not replaced. For example:

async function updateAllowedDirectoriesFromRoots(requestedRoots) {
    const validatedRootDirs = await getValidRootDirectories(requestedRoots);
    if (validatedRootDirs.length > 0) {
        // Merge with existing CLI-provided directories instead of replacing
        const merged = new Set([...allowedDirectories, ...validatedRootDirs]);
        allowedDirectories = [...merged];
        setAllowedDirectories(allowedDirectories);
    }
}

The same fix should apply to the RootsListChangedNotificationSchema handler.

Environment

  • @modelcontextprotocol/server-filesystem version: 2026.1.14
  • Client: Claude Code (supports MCP roots protocol)
  • OS: Linux (openSUSE Tumbleweed)
  • All directories exist and are mounted ext4 partitions

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in dist/index.js around line 564, then inspect updateAllowedDirectoriesFromRoots and the RootsListChangedNotificationSchema handler. Reproduce with multiple CLI directories and a client root, call list_allowed_directories, and verify that all existing CLI and client directories remain listed after both initialization and root-list changes.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
backend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.