Summary
When a client supports the MCP roots protocol, server-filesystem unconditionally replaces CLI-provided allowed directories with the client's roots on initialization. This makes it impossible to scope the server to a directory outside the client's project root.
Reproduction
-
Configure a filesystem MCP server with an explicit directory argument:
{
"my-project": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/external-project"]
}
}
-
Use it from a client that supports MCP roots (e.g., Claude Code with project root at /path/to/my-repo).
-
Call list_allowed_directories — it returns /path/to/my-repo instead of /path/to/external-project.
Root cause
In dist/index.js, the oninitialized handler fetches roots from the client and calls updateAllowedDirectoriesFromRoots, which replaces the allowedDirectories array entirely — even when directories were explicitly provided via CLI args:
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);
// ^ this replaces CLI-provided directories
}
}
// ...
};
Expected behavior
CLI arguments should take precedence over MCP roots. If the user explicitly passes directories, those should be respected. MCP roots should only be used as a fallback when no CLI directories are provided.
Suggested fix
Only fetch and apply roots when no CLI args were provided:
if (clientCapabilities?.roots && allowedDirectories.length === 0) {
An alternative would be to merge both sources (CLI args + roots), but that changes the security model since CLI args are meant to be the explicit allowlist.
Version
2026.1.14
Summary
When a client supports the MCP roots protocol,
server-filesystemunconditionally replaces CLI-provided allowed directories with the client's roots on initialization. This makes it impossible to scope the server to a directory outside the client's project root.Reproduction
Configure a filesystem MCP server with an explicit directory argument:
{ "my-project": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/external-project"] } }Use it from a client that supports MCP roots (e.g., Claude Code with project root at
/path/to/my-repo).Call
list_allowed_directories— it returns/path/to/my-repoinstead of/path/to/external-project.Root cause
In
dist/index.js, theoninitializedhandler fetches roots from the client and callsupdateAllowedDirectoriesFromRoots, which replaces theallowedDirectoriesarray entirely — even when directories were explicitly provided via CLI args:Expected behavior
CLI arguments should take precedence over MCP roots. If the user explicitly passes directories, those should be respected. MCP roots should only be used as a fallback when no CLI directories are provided.
Suggested fix
Only fetch and apply roots when no CLI args were provided:
An alternative would be to merge both sources (CLI args + roots), but that changes the security model since CLI args are meant to be the explicit allowlist.
Version
2026.1.14