Making the Filesystem MCP Server Read-Only for Sensitive Directories
Do not rely on the Filesystem MCP server's allowed-directories list to make a directory read-only, because it controls where the server may operate, not whether it may write. Enforce read-only at the infrastructure layer with read-only mounts or a least-privilege service account, restrict or disable write-capable tools, enforce policy on tool calls, and keep evidence of every decision. Run a version at or above 0.6.4 or 2025.7.01.
- Confirm the server version is 0.6.4 or 2025.7.01 or later.
- From inside the container or as the service account, attempt to write, edit, move and create in each sensitive directory and confirm each fails.
- Create a symlink inside an allowed directory that points to a path outside it, then confirm reads and writes through it are refused or land only on read-only storage.
- Send path arguments containing relative segments and confirm they are denied after normalization.
- Confirm the service account cannot read credential stores or other files outside its scope.
- Confirm write-capable tools are absent or gated in read-only sessions, and that a changed tool definition triggers re-approval.
What the Filesystem MCP server does and does not enforce
The reference Filesystem MCP server gives a connected AI client read and write tools, including file writes, edits, moves and directory creation, across the directories it is allowed to access. The allowed-directories list defines scope. It is not a per-directory read/write permission model, so a directory that is in scope for reading is generally in scope for modification too.
The available native options are coarse and vary by server version and deployment method. Read-only mounts and file system permissions must be configured outside the server. That shapes the whole approach: the server cannot be the only control, and any read-only guarantee has to come from the layers around it.
Version matters as well. CVE-2025-53109 records that Filesystem server versions before 0.6.4 or 2025.7.01 could allow access to unintended files through symlinks within allowed directories. An allowed-directory list alone may therefore not confine access on affected versions. Upgrade first, then test symlink behavior rather than assuming it.
Comparing the four enforcement methods
Each method fails in a different way, which is why they are combined. Choose the starting layer by deployment model: mounts for containers and Kubernetes, OS accounts for host processes, and tool-level controls for every deployment.
- Read-only mounts: Strong against any write by the server process to the mounted path. Does not stop reads of secrets, and does not restrict other interfaces.
- OS permissions and a dedicated service account: Works for host processes and containers alike. Depends on correct ownership and group settings, and on the account not holding broader rights.
- Restricting or disabling write-capable tools: Removes the capability from the agent's view. Coverage depends on how your client or deployment filters tools, and it does not protect a directory if another path to the server exists.
- Policy enforcement on tool calls: Evaluates each call and its path arguments before execution, and can allow, block or escalate. Only as good as its path normalization and rule coverage.
Layer 1 and 2: mounts and least-privilege accounts
For containerized deployments, mount each sensitive directory read-only, using the :ro suffix or a mount definition with the readonly option, for example docker run --mount source=...,destination=...,readonly. Also run the container with --read-only so its root filesystem is immutable, and add --tmpfs only where the process genuinely needs temporary writes. In Kubernetes, the equivalent controls are the readOnlyRootFilesystem setting and read-only flags on volume mounts. NIST guidance recommends a read-only container filesystem by default, overridden only when the application must write to disk.
Run the process as a dedicated non-root account. NIST SP 800-123 advises that service processes have read-only access to the files the service needs and no access to anything else. For host processes this means file and directory permissions scoped to that account. For containers, make sure the account can still read the target files, for example through world-readable permissions (o=r on files, o=rx on directories) or an appropriate group, as NIST's Dioptra setup does when it mounts data read-only.
Two limits apply. A read-only mount does not prevent disclosure, so an agent can still read secrets in a readable directory. Keep credential stores out of the mounted tree entirely, and note that .gitignore does not stop AI tools from reading files. Mount flags also do not replace authorization at other interfaces: OWASP notes that mounting the Docker socket read-only does not make the Docker API read-only.
Layer 3 and 4: restrict write tools and enforce policy on calls
Where your client or deployment lets you filter the tool list, remove write-capable tools from any session that only needs to read. This reduces what a prompt-injected agent can attempt, and it is a useful second layer behind the mounts. Use an allowlist of tools and filesystem roots rather than a blocklist, and remove helpers the task does not need.
Do not base decisions on how a tool describes itself. OWASP advises treating tool annotations as untrusted unless they come from trusted servers, and notes that a read/write label alone may not establish risk. A policy should key on the tool name you have approved and on the resolved path argument, and should require re-approval when tool definitions change. An OWASP GenAI item describes an approved MCP server that later changed its tool metadata and used a connected agent to collect sensitive local information.
Path handling is where call-level rules most often fail. Normalize every path argument before matching, resolve symlinks to their real targets, and compare the result against the approved root. Treat relative segments and links that point outside the root as denied by default. For calls that touch sensitive paths with a write-capable tool, the choices are to block, or to escalate to a human approver for irreversible actions such as moves and deletions.
Evidence of what the agent was allowed to do, and where Trussed fits
Demonstrating least privilege requires more than configuration. Retain the mount and account definitions as versioned configuration, the results of the failed-write tests, and a record of each tool call: the tool, the resolved path, the decision, the identity of the session and the policy version in force. Without the call-level record, a team can show what the agent could do but not what it attempted.
Trussed enforces policy in the execution path of MCP tool calls, so decisions are enforced at runtime, not reviewed after the fact. For a filesystem tool call, policy can allow, redact or block, rate limit, or escalate for human approval, and that enforcement produces audit-ready evidence. This sits on top of the mount and account controls above. It does not replace them, because infrastructure-level read-only enforcement remains the layer that holds when everything else fails.
Layered read-only enforcement
Mount layer
Sensitive directories mounted read-only into the server process.
OS layer
Dedicated non-root account with read access to only the files needed.
Tool layer
Write-capable tools removed, restricted or gated.
Policy layer
Tool calls checked against path rules before they run.
Evidence layer
Allowed, blocked and escalated calls recorded with paths.
Enforce read-only access at the tool-call layer
See how policy enforcement in the execution path of MCP tool calls works alongside read-only mounts and least-privilege accounts, and what evidence it produces.
Explore Agent and Tool-Call EnforcementHow does your AI governance program compare?
See where your program has gaps in less than 2 minutes.