The access model is the interesting part: directories come from the launch command, or from a client's roots, and roots win outright — so a host can widen or narrow what the agent can touch without restarting the server. On the editing side, edit_file returns a diff and takes a dryRun flag, which is the difference between an agent that proposes a change and one that has already made it.
A filesystem server fenced to a set of allowed directories. Inside them it reads and writes files, walks directory trees, searches by glob and reports metadata.
- Text files read whole, or just the first or last N lines with head and tail
- Several files read in one call, where a failure on one does not abandon the rest
- Images and audio read back as base64 content with their MIME type; other binaries come back as an embedded resource
- Whole-file writes, and line-based edits that return a git-style diff — dryRun previews the change before it lands
- Directory listings plain or with sizes, sorted by name or size, and a recursive JSON tree with exclude patterns
- Glob search across a directory, with patterns to exclude
- File metadata: size, creation, modification and access times, permissions and type
- Directory creation, including nested paths, plus move and rename in a single operation
- The current allow-list read back, so the agent can check where it may go before it tries
No account and no key. Published on npm as @modelcontextprotocol/server-filesystem and run through npx. It needs at least one allowed directory to operate: pass the paths on the command line, or let a client that supports MCP Roots supply them — roots replace the command-line list entirely and can change at runtime. A server started with no paths, talking to a client with no roots, fails at initialization.
One command — npx -y @modelcontextprotocol/server-filesystem
