Repository navigation
Filesystem server: Restrict access: Configure a base directory and allowed directories inside that. #3133
Description
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, andvideossubdirectories of my/pubfiles, but not confuse users' AI with all the stuff in/pubfiles/.gitand/pubfiles/.cache.
- In the trivial case, this is a single entry
- 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
[-]Filesystem server: Restrict access[/-][+]Filesystem server: Restrict access: Configure a base directory and allowed directories inside that.[/+]kpearson commentedon Mar 13, 2026
The filesystem MCP is completely non-functional in Claude Code.
Claude Code advertises
rootscapability and sends only the CWD as a root. Theoninitializedhandler inindex.ts(line 564) sees that the client supports roots, callslistRoots(), andupdateAllowedDirectoriesFromRoots()does a full replacement: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:
~/.claude.json:{ "mcpServers": { "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/some/other/directory"] } } }list_allowed_directories— only the CWD is returned/some/other/directoryis inaccessibleImpact: 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:
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.
cliffhall commentedon Oct 19, 2026
Triage: Priority Low (total 5)
Board: Servers V2 (#43), Status
Incoming, awaiting maintainer review (no milestone yet). Part of the backlog triage in #4875.cliffhall commentedon Oct 29, 2026
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.