We use cookies to enhance your experience on the site
CodeWorlds
Back to collections
Guide12 min read

Filesystem MCP, or an assistant reading and writing files

The MCP server giving an assistant file access. Allowed directories, escape protection, the risk of chaining with other tools, and safe configuration.

Filesystem MCP, or an assistant reading and writing files

This is the most frequently attached server in the whole protocol ecosystem and simultaneously the one with the highest stakes. An assistant with file access reads code, fixes it, creates new files, and moves things between directories.

The convenience is obvious, and the risk higher than with database or document access. Files are simultaneously source code, private keys, configuration files, and everything else sitting on a disk.

The good news is that the official server was designed with that risk in mind and carries sensible protections. The bad news is that the most serious threat lies outside it and follows from how the whole arrangement works. I return to that in its own section.

Allowed directories

The basic protection is a list of directories the server will not leave. You supply it at launch.

Code
JSON
{
  "mcpServers": {
    "files": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/anna/projects/shop"
      ]
    }
  }
}

That one directory is the entire world the assistant sees. An attempt to read anything outside it ends in refusal, regardless of how it is phrased.

The second route is passing a directory list from the client, through a mechanism the protocol provides. The client then states what you are currently working on and the server adjusts its scope. Note that a list supplied by the client replaces the one given at launch rather than adding to it.

A server launched with neither of those two will not start. That is a good design decision, since default access to a whole disk would be the worst possible initial setting.

A practical rule: name a specific project rather than a home directory. The difference is that a home directory holds keys, configuration files with passwords, and command history, while a project directory holds a project.

Protection against escaping the scope

A directory list alone does not suffice, since a path can be written in many ways. The server handles that at several levels.

Paths are resolved to canonical form before checking, so references stepping up a directory do not lead outside the permitted area. That is the simplest bypass route and simultaneously the best covered.

Symbolic links are checked for where they actually lead. A link sitting inside an allowed directory but pointing at a home directory gets rejected. Links leading nowhere are rejected too.

That solves a category of problems which in a hand written implementation is the most common source of mistakes, since checking a path before resolving a link looks correct and is not.

Understand the boundary of that protection, though. The safeguards concern where the assistant reaches rather than what it does inside the permitted directory. Within the named project it can overwrite any file, and that is intended behaviour.

The real risk

This section is the most important in the whole text, since it concerns a threat the protections above do not cover.

A model invokes tools based on what it read. If text phrased like an instruction appears in its context, the model may execute it, not distinguishing an instruction from data.

With one tool that is limited risk. The problem starts with several tools at once, and such an arrangement is typical. An assistant with access to files and to fetching web pages can read a page holding a hidden instruction and carry it out on your files.

The scenario is not hypothetical and has been described by security researchers. It suffices for the model to fetch external content in which somebody placed an instruction to read a particular file and send it somewhere. The read falls within the permitted directory, so none of the server's protections engage.

The same applies to content from closer sources: a user's ticket, a comment in code, a dependency file fetched from outside. Everything a model reads can influence what it does next.

Three things limit that risk genuinely. The first is a narrow directory, since it bounds the damage regardless of what the model gets persuaded to do. The second is approving write operations rather than permitting them unattended. The third is not placing inside the permitted directory anything you cannot afford to lose or reveal: keys, configuration files with passwords, and database dumps.

The fourth, most effective for serious work: separating tools. An assistant reading external content and an assistant with file access form a safer arrangement as two separate sessions than as one holding both.

What it can do

The tool set is predictable and deserves knowing, since it determines what to require at approval time.

Reading covers a single file and several files in one call, which is noticeably faster when reviewing a project. Directory listing and walking a directory tree are available too.

Writing covers creating files, overwriting them, and editing based on replacing fragments, with a preview of changes before execution. That last one is the safest form, since it changes a named fragment rather than overwriting the whole thing, so a mistake does not erase the rest of the file.

Moving, creating directories, and searching files by name are available as well, with a pattern matched against the whole path. Content search is not among the tools, so finding every place a name occurs means opening the files or reaching for a separate tool.

Note one thing about editing. Replacing a fragment does not check whether that fragment occurs only once. The first occurrence is replaced, without warning, and the operation fails only when nothing matches at all. Make the fragment long enough to be unambiguous and use the preview of changes before saving, since that is the only guard against a change landing in the wrong place.

Large files and context

A practical problem, less dangerous than the previous one and encountered daily: files that do not fit in a model's context.

A three thousand line file is tens of thousands of tokens. Loading three such files fills a large share of the available space, and the model must still accommodate the instruction, the conversation history, and an answer.

The symptoms mislead. The model answers from a fragment without signalling it did not see the rest, or correctly describes a file's beginning while omitting a function defined at the end. With editing it is worse: a change proposed from an incomplete picture can break something the model never saw.

Three habits limit that. The first is naming specific files rather than letting the assistant browse a whole tree. The second is reading a fragment rather than the whole thing where one function interests you. The third is working on smaller files, which is good practice for other reasons anyway.

On larger projects, remember too that locating the right files by name is cheaper than loading them one by one. Since the server does not look inside, run the hunt for the places a name occurs with a tool outside it, and hand the assistant only the files it turns up.

Working with a repository

A few things that turn a risky arrangement into a controlled one during code work.

Start from a clean state in version control. All your changes committed, the working directory unmodified. Every change appearing afterwards then comes from the assistant and is visible in a diff.

Review the diff rather than the summary. An assistant describes what it did, and that description is often correct and incomplete. A diff shows everything, including things it did not mention.

Commit in small portions. One instruction, one review, one commit. Three instructions in a row without review produce a change spanning twenty files, in which distinguishing what you wanted from what came along is hard.

Watch the files an assistant should not touch. Dependency lock files, build tool configuration, and generated files get modified in passing, and a change there can break the build in a way that is hard to trace.

Know this server's scope boundary as well. It sees files on disk rather than a repository: change history, issues, and pull requests are not readable from here, since those sit behind the API. The GitHub server covers them, splitting its tools into toolsets and carrying a separate read only mode. During code work both are often connected at once, and it then helps to remember that you review the diff locally rather than through the API.

One last thing: do not keep an environment file holding real keys in the project directory. Even excluded from version control, to an assistant it is an ordinary file in a permitted directory.

The filesystem server against the alternatives

OptionStrengthWeaknessPick it when
The official serverProven path protections, actively maintainedUnattended writes if the client does not require approvalWorking with project files
An editor assistantProject context, change review before savingWorks only inside that editorDaily work on code
Community serversMore operations, large file handlingSomebody else's code with disk accessUnusual requirements
A container with a mounted directoryIsolation from the rest of the systemMore configurationWorking with code from an unknown source

The second row gets skipped and for code work is usually the better choice. Tools like Cursor have file access built in, show changes before saving, and work within a project's context, so adding a separate server contributes little.

The last row deserves considering when working with code you do not know. Running an assistant in a container with one directory mounted means that even executing a malicious instruction stays confined to that directory, with no access to the rest of the system.

Safe configuration

A summary as a list, since this is the part worth returning to.

Name a specific project directory, never a home directory or a root directory. Check whether that directory holds a file with credentials, since that is the most common oversight.

Enable write approval in the client if it offers one. Reading can run unattended; writing rather not.

Do not combine file access with tools fetching external content in one session. That is the simplest way to limit the most serious risk and it costs nothing.

Keep the project in version control with changes committed before you start. Every change the assistant makes is then visible in a diff and reversible with one command.

Review changes before committing, even when the assistant claims it did exactly what you asked. That is the same principle as reviewing somebody else's code and for the same reason.

Common mistakes

The first is naming a home directory as permitted. It holds keys, configuration files with passwords, and command history, meaning exactly what an assistant should not see.

The second is combining file access with fetching external content in one session. That is the most frequently described route to executing somebody else's instruction on your files.

The third is permitting writes without confirmation. Reading is reversible; overwriting a file is not necessarily.

The fourth is working without version control. Without it a change made by the assistant is indistinguishable from yours and irreversible.

The fifth is assuming the server's protections cover everything. They concern where the assistant reaches rather than what it does inside the permitted directory.

The sixth is running a community server with disk access without reviewing the code. The principles from the piece on the server catalogue apply here doubly.

The seventh is keeping a file with real keys in the project directory. Excluding it from version control changes nothing, because to the assistant it is an ordinary file inside the permitted area.

FAQ

Can an assistant escape the named directory?

Not through a path. The server resolves paths to canonical form, blocks references stepping upward, and checks where symbolic links lead. It can do anything inside the permitted directory, though, and that is intended behaviour.

What is the biggest risk?

That a model executes instructions found in content it read. With simultaneous access to files and to fetching external pages, somebody can place an instruction in that content to read a file and send it onward, and the server has no reason to block it.

How do I protect against that?

A narrow directory, approving write operations, and keeping sensitive things out of the permitted area. The most effective measure, though, is separation: do not combine file access with tools reading external content in one session.

Is this better than an assistant built into an editor?

For code work usually not. Tools like Cursor have file access built in, show changes before saving, and understand project context. A separate filesystem server helps where you work outside an editor.

Is running it in a container worthwhile?

When working with code from an unknown source, decidedly yes. A container with one directory mounted means that even executing a malicious instruction stays confined to that directory, with no access to the rest of the system.

The code and documentation sit in the protocol's server repository, and the package in the npm registry.