Skip to content

Filesystem server: Restrict access: Configure a base directory and allowed directories inside that. #3133

Closed

Description

@mk-pmb

Is your feature request related to a problem? Please describe.
I want to host a public filesystem MCP via HTTPS, by installing it into a docker container, together with other stuff that users won't be interested in. I'd like a way to specify which directories users can see and access.

docs/docs/learn/client-concepts.mdx says that roots are mere hints:

Roots work best when […] users understand their advisory nature, and the goal is preventing accidents rather than stopping malicious behavior.

In my case it wouldn't even necessarily be malicious, but when users would want to see "all files on that MCP" they'd probably give / as the root, and would be confused to see the entire docker container. Also their AI might be confused about the vast amount of unexpected boring files. They'd have expected to only see the directories with my actual intended content, which would be /pubfiles/ in my docker container.

src/filesystem/README.md says about "Roots Protocol Handling":

Server replaces ALL allowed directories with client's roots

Note it says "allowed". That sounds like a mixup of the concepts of a client's declaration of intent about what to use, vs. a server operator's intent about what to share. In a similar manner, the

Note: The server will only allow operations within directories specified either via args or via Roots.

lacks explanation why something that the server operator can decide (command arguments) should be handled equivalent to something that arbitrary users can send (roots).

Describe the solution you'd like

  • Server operators can configure a base directory that will become the top level for all roots, i.e. it would be file:/// in the root URLs namespace.
  • Inside that, server operators can configure "allowed" directories, and only those (and their parent directories) will be visible and accessible.
    • In the trivial case, this is a single entry / for the top level.
    • Default is still the empty list = no access at all, to avoid accidents when people comment-out the last entry in their config.
    • The idea behind this feature is so I can easily expose the photos, books, and videos subdirectories of my /pubfiles, but not confuse users' AI with all the stuff in /pubfiles/.git and /pubfiles/.cache.
  • When a client has no roots support, assume it wants to see everything, i.e. act as if it had specified a single root with URI file:///
  • When roots are received, track them as "intended" directories, i.e. a voluntary additional restriction of the "allowed" directories. Any roots outside of the "allowed" directories is simply ignored, pretending the directory doesn't exist.
  • There should be an option about which kinds of symlinks to accept along the way: none = none (default), same-owner = symlink must be owned by the same user and group as its target, trust-all = yolo. For unacceptable symlinks, pretend they don't exist. (Not sure if that should be its own feature request issue.)

Describe alternatives you've considered

Additional context
I'm hosting the server publicly because parts of my audience won't be able to install their own MCP-related software. We have a web-based AI chat assistant for them, so my hope is that with a few screenshots of how to navigate the config, they can find the "MCP URL" field, paste my URL there, and it just works for them.

Activity

  1. changed the title [-]Filesystem server: Restrict access[/-] [+]Filesystem server: Restrict access: Configure a base directory and allowed directories inside that.[/+] on Dec 17, 2025
  2. kpearson commented on Mar 13, 2026

    @kpearson

    The filesystem MCP is completely non-functional in Claude Code.

    Claude Code advertises roots capability and sends only the CWD as a root. The oninitialized handler in index.ts (line 564) sees that the client supports roots, calls listRoots(), and updateAllowedDirectoriesFromRoots() does a full replacement:

    allowedDirectories = [...validatedRootDirs];

    This discards every directory passed via CLI args. Since Claude Code already has built-in Read/Write/Edit/Glob/Grep tools scoped to the CWD, the filesystem MCP now provides zero additional capability. The entire point of configuring it is to access directories outside the CWD — and that's exactly what this behavior prevents.

    Reproduction:

    1. Configure the filesystem MCP in ~/.claude.json:
    {
      "mcpServers": {
        "filesystem": {
          "command": "npx",
          "args": ["-y", "@modelcontextprotocol/server-filesystem", "/some/other/directory"]
        }
      }
    }
    1. Launch Claude Code from any project directory
    2. Call list_allowed_directories — only the CWD is returned
    3. /some/other/directory is inaccessible

    Impact: This affects every Claude Code user who installs the filesystem MCP to access directories outside their project. The MCP is effectively dead for Claude Code — redundant for the CWD, broken for everything else.

    Suggested fix: Merge roots with CLI args instead of replacing:

    allowedDirectories = [...new Set([...allowedDirectories, ...validatedRootDirs])];

    Or at minimum, treat CLI args as an operator-defined floor that roots can extend but not remove. The current behavior lets any roots-capable client silently override the operator's configured access scope, which is also a security concern as noted in the original issue.

  3. added
    server-filesystemReference implementation for the Filesystem MCP server - src/filesystem
    on Oct 19, 2026
  4. cliffhall commented on Oct 19, 2026

    @cliffhall
    Member

    Triage: Priority Low (total 5)

    • Severity 3: Client roots still replace the operator's command-line directories outright on 2025-era connections; confining roots within the configured directories is a reasonable usability request.
    • Urgency 2: wanted eventually
    • Bonuses: none

    Board: Servers V2 (#43), Status Incoming, awaiting maintainer review (no milestone yet). Part of the backlog triage in #4875.

  5. added this to the v2.3.0 milestone on Oct 25, 2026
  6. self-assigned this
    on Oct 28, 2026
  7. cliffhall commented on Oct 29, 2026

    @cliffhall
    Member

    Shipped in #5395, merged into v2/main; it releases with milestone v2.3.0. Tested together with the rest of the #5269 work in the rollup #5405.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestserver-filesystemReference implementation for the Filesystem MCP server - src/filesystemv2

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions