How to Configure Allowed Directories in the MCP Filesystem Server

The MCP Filesystem server restricts all file operations to a whitelist of directories that you can configure via command-line arguments at startup or dynamically through the MCP Roots protocol.

The modelcontextprotocol/servers repository implements a security-first filesystem server that validates every read and write operation against an explicit list of permitted paths. Understanding how to populate and manage this allowed directories whitelist is essential for securely deploying the server in production environments.

Configuration Methods Overview

The server supports two distinct mechanisms for defining which directories are accessible. Both methods ultimately populate the same global allowedDirectories array used by the validation pipeline.

Command-Line Arguments

When launching the server directly from a terminal, pass absolute or relative paths as positional arguments. The server resolves these during initialization in src/filesystem/index.ts (lines 45–66), expanding tildes (~), converting to absolute paths, and normalizing through normalizePath.


# Grant access to specific project folders

mcp-server-filesystem /home/user/projects /var/shared/data

If no directories are provided and the connecting client does not support the Roots capability, the server aborts immediately with an error (approximately line 49 in index.ts).

For clients that support the Roots capability, configuration happens dynamically after connection. During the oninitialized phase (lines 130–150 in src/filesystem/index.ts), the server requests the client's root set via listRoots. The client returns an array of directory URIs, which the server validates, resolves (including symlinks via fs.realpath), and stores in the global whitelist.

This approach allows runtime updates without restarting the server.

Path Validation and Security Pipeline

Every filesystem operation passes through a three-stage validation process regardless of which configuration method you use.

Resolution and Normalization

Before storage, all paths undergo expansion and normalization. Symlinks are resolved using fs.realpath to prevent bypass attacks—for example, treating /tmp and /private/tmp as identical on macOS systems. This occurs in the initialization logic at src/filesystem/index.ts lines 45–66.

Access Checking with validatePath

Every tool implementation calls validatePath from src/filesystem/lib.ts, which invokes isPathWithinAllowedDirectories (lines 98–110). This function ensures the requested target lives inside one of the stored allowed directories before any operation executes.

Runtime Updates via Roots

When a client sends a roots/list_changed notification (handled around line 176 in index.ts), the server triggers updateAllowedDirectoriesFromRoots. This function rewrites the global array and calls setAllowedDirectories so subsequent operations immediately respect the new boundaries (lines 107–110).

Practical Configuration Examples

Starting with Command-Line Directories

Launch the server with explicit paths to create the initial whitelist:


# Multiple directories supported

mcp-server-filesystem ~/Documents /opt/shared /var/log/app

The server prints the resolved list to stderr on startup for verification.

Setting Directories via MCP Roots

When connecting through an MCP client that supports Roots, the server automatically requests permissions:

// Client response to roots/list request
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "roots": [
      { "uri": "file:///home/user/projects" },
      { "uri": "file:///var/shared/data" }
    ]
  }
}

The server validates each URI, extracts the file path, resolves any symlinks, and updates its internal whitelist.

Updating Whitelist at Runtime

Send a notification to trigger reconfiguration without restarting:

// Client sends change notification
{
  "jsonrpc": "2.0",
  "method": "roots/list_changed",
  "params": {}
}

The server automatically calls listRoots() again, re-validates the new set, and replaces the previous allowed directories array.

Querying Current Allowed Directories

Check the active whitelist using the server's exposed tool:

{
  "jsonrpc": "2.0",
  "method": "list_allowed_directories",
  "id": 2,
  "params": {}
}

The implementation resides in src/filesystem/index.ts (lines 84–92) and returns the current resolved paths:

Allowed directories:
/home/user/projects
/var/shared/data

Summary

  • Two configuration methods: Command-line arguments for direct startup, or MCP Roots protocol for dynamic client-managed access.
  • Strict validation: All paths resolve symlinks and normalize before storage to prevent directory traversal attacks.
  • Runtime flexibility: The Roots protocol supports live updates via roots/list_changed notifications without server restarts.
  • Security enforcement: Every operation passes through validatePath and isPathWithinAllowedDirectories in src/filesystem/lib.ts before execution.
  • Fatal initialization: The server exits immediately if no allowed directories are configured and no Roots capability is available.

Frequently Asked Questions

What happens if I don't configure any allowed directories?

The server aborts during initialization with an error message. According to the source code in src/filesystem/index.ts (around line 49), the server requires either command-line directories or a client with Roots capability to establish a security boundary.

Can I use relative paths when starting the server?

Yes, but they are immediately converted to absolute paths during initialization. The server calls normalizePath on all inputs in src/filesystem/index.ts (lines 45–66), so relative references like ./data resolve to their absolute equivalents before being stored in the whitelist.

Symlinks are resolved using fs.realpath during both initialization and path validation. This ensures that /tmp and /private/tmp (on macOS) are treated as the same location, preventing attackers from using symlink redirection to escape the allowed directory boundaries defined in src/filesystem/path-validation.ts.

Can I change allowed directories without restarting the server?

Yes, if your client supports the MCP Roots protocol. Send a roots/list_changed notification (handled at approximately line 176 in index.ts), and the server will call updateAllowedDirectoriesFromRoots to fetch the new list and update the global allowedDirectories array via setAllowedDirectories without dropping the connection.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →