MCP Filesystem Server: Safe Read-Write Operations Setup Guide

Configure the MCP Filesystem Server for safe read-write operations. Lock down allowed directories, separate read-only from write paths, and connect to Claude Desktop in 15 min.

Problem: AI Agents Writing Files Outside Your Project Directory

You've connected an AI assistant to your filesystem via MCP and it writes a config file to ~/ instead of ./project. Or worse — it overwrites something in a directory you never intended to expose.

The MCP Filesystem Server has a solid sandbox model, but the default setup lets you shoot yourself in the foot if you don't pin the allowed directories correctly.

You'll learn:

  • How to restrict the server to specific allowed directories (read-write and read-only)
  • The difference between read_file, write_file, and destructive tools — and which to expose
  • How to wire it up in Claude Desktop, VS Code, and Docker with safe mounts

Time: 15 min | Difficulty: Intermediate


Why This Happens

The MCP Filesystem Server grants access to any directory you pass as a command-line argument. If you pass /Users/you instead of /Users/you/projects/myapp, the AI can touch your entire home directory — dotfiles, SSH keys, everything.

There's no write-permission flag per directory at the CLI level in the official Node.js server (@modelcontextprotocol/server-filesystem). Read-only enforcement requires either the Docker ro mount flag or a wrapper config.

Symptoms of a misconfigured setup:

  • AI creates files in ~ or /tmp instead of your project root
  • move_file silently succeeds on paths you didn't intend to expose
  • delete_file with recursive: true deletes a parent directory

How Directory Access Control Works

Before touching any config, understand the access flow:

Claude Desktop / VS Code
        │
        ▼
  MCP Client (roots protocol)
        │ roots/list_changed notification
        ▼
  Filesystem Server
        │ validates every path against allowedDirs
        ▼
  Allowed Directory (e.g. /projects/myapp)
        │
        ├── read_file        ← read-only, safe
        ├── list_directory   ← read-only, safe
        ├── write_file       ← destructive if path escapes
        ├── delete_file      ← destructive
        └── move_file        ← destructive

The server resolves symlinks and checks that the real path starts with an allowed directory prefix. Path traversal like ../../etc/passwd is caught here. But a too-broad allowed directory silently passes.


Solution

Step 1: Install the Official MCP Filesystem Server

# Verify Node.js >= 18
node --version

# Run directly via npx — no global install needed
npx -y @modelcontextprotocol/server-filesystem /path/to/your/project

Expected output:

MCP Filesystem Server running on stdio
Allowed directories: [ '/path/to/your/project' ]

If it fails:

  • Error: No allowed directories → You must pass at least one directory as an argument; the server will not start without one
  • Error: ENOENT → The path doesn't exist; create the directory first with mkdir -p

Step 2: Configure Claude Desktop with a Scoped Directory

Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/you/projects/myapp"
      ]
    }
  }
}

Restart Claude Desktop after saving. The server only sees /Users/you/projects/myapp and its subdirectories — nothing outside.

Multiple directories (e.g., project + a read-only docs folder):

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/you/projects/myapp",
        "/Users/you/docs"
      ]
    }
  }
}

Both paths are read-write at the server level. To enforce read-only on /docs, use Docker (Step 4).


Step 3: Configure VS Code (Workspace Method)

Create .vscode/mcp.json in your workspace root:

{
  "servers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "${workspaceFolder}"
      ]
    }
  }
}

${workspaceFolder} expands to the workspace root at runtime — no hardcoded paths. Commit this file to share the config with your team.

Open the Command Palette → MCP: List Servers to confirm the server is running.


Step 4: Enforce Read-Only Directories with Docker

The Docker image supports the ro mount flag to make specific directories genuinely read-only at the OS level — the server cannot write there even if the AI requests it.

docker run -i --rm \
  --mount type=bind,src=/Users/you/projects/myapp,dst=/projects/myapp \
  --mount type=bind,src=/Users/you/docs,dst=/projects/docs,ro \
  mcp/filesystem \
  /projects/myapp \
  /projects/docs

The ro flag on the docs mount means any write_file or delete_file call targeting /projects/docs will fail at the OS level with a permission error — not just a soft server refusal.

Claude Desktop config for the Docker version:

{
  "mcpServers": {
    "filesystem": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "--mount", "type=bind,src=/Users/you/projects/myapp,dst=/projects/myapp",
        "--mount", "type=bind,src=/Users/you/docs,dst=/projects/docs,ro",
        "mcp/filesystem",
        "/projects/myapp",
        "/projects/docs"
      ]
    }
  }
}

Step 5: Know Which Tools Are Destructive

The server exposes these tools. Understand what each can do before letting an agent loose:

ToolDestructive?Notes
read_fileNoSafe; errors on binary files
read_multiple_filesNoBatches reads
list_directoryNoMetadata only
directory_treeNoRecursive listing
get_file_infoNoSize, mtime, permissions
list_allowed_directoriesNoReturns the configured roots
search_filesNoGlob pattern match
write_fileYesOverwrites without warning
create_directoryLowCreates parent dirs
move_fileYesFails silently if dest exists
delete_fileYesrecursive: true is very destructive
edit_fileYesIn-place find-replace

For agents that only need to read project files, pass the directory as a ro Docker mount and rely on the fact that write tools will simply fail at the OS level.


Verification

Ask Claude Desktop (after restarting):

List the files in my project directory.

You should see a directory listing limited to the path you configured — not your entire home folder.

Then test the boundary:

Try to read /etc/passwd

You should see an error like Access denied - path outside allowed directories. If you see file contents, your allowed directory is set too broadly.

Check the server is using the right paths by asking:

What directories are you allowed to access?

The response comes from the list_allowed_directories tool and shows exactly what the server sees.


What You Learned

  • Pass the narrowest possible directory path — project root, not home directory
  • ro Docker mounts are the only way to enforce read-only at the OS level; the server's own tooling doesn't have a per-directory write flag
  • delete_file with recursive: true is the highest-risk tool — consider whether your agent actually needs it
  • VS Code's ${workspaceFolder} variable keeps configs portable across machines

Limitation: The official Node.js server has no built-in audit log. If you need a record of what the AI read or wrote, run it behind a proxy or use a fork with logging enabled (e.g., gabrielmaialva33/mcp-filesystem supports JSON config with log file and metrics).

Tested on @modelcontextprotocol/server-filesystem 2025.x, Node.js 22 LTS, Claude Desktop 0.9.x, macOS Sequoia and Ubuntu 24.04