Filesystem MCP MCP Server
io.github.j0hanz/filesystem-mcp
Secure filesystem MCP server with read, write, search, diff, and patch capabilities for AI assistants.
What is the Filesystem MCP MCP server?
Filesystem MCP is a Model Context Protocol server that enables AI assistants to safely read, write, and manipulate files within explicitly allowed directories. It provides comprehensive filesystem tools including search, diff, and patch operations, with built-in protection against sensitive file patterns like `.env` and private keys.
Filesystem MCP gives Claude, Cursor, and other AI assistants controlled access to your project files. It supports reading, writing, searching, comparing, and patching files across allowed directories while blocking sensitive patterns by default. Features include batch operations, file subscriptions for change notifications, regex-safe search using RE2, and both stdio and HTTP transport modes.
How to install Filesystem MCP
Copy-paste configuration for popular MCP clients.
FS_ALLOWED_DIRSAllowed directories; ':'-separated on Unix, ';'-separated on Windows. Alternative to positional arguments.
Tools & capabilities
Tools this server exposes to the agent.
list_roots— List allowed workspace roots that all other tools scope to.list— List directory contents with entries and ASCII tree representation.find_files— Find files by glob pattern with metadata.stat— Get file/directory metadata including size, modified time, permissions, MIME type, and token estimate.search_text— Search file contents for text using RE2 regex or literal matching with context.diff— Compare two files and return a unified diff with line counts.read— Read text files with support for head/tail and line ranges; accepts multiple paths for batch operations.create— Create one or more files with parent directory creation; supports overwrite and append modes.edit— Apply sequential literal string replacements to one or more files (up to 5 files, 100 edits per file).move— Move, rename, or copy one or more files/directories to explicit destinations.delete— Permanently delete one or more files or directories.replace_text— Bulk search-and-replace across files matching a glob pattern.patch— Apply a single-file unified diff and write the result.
Use cases
- Refactor code across multiple files with bulk search-and-replace or targeted edits
- Compare file versions and apply diffs to sync changes
- Search project files for specific text patterns with regex or literal matching
- Create and organize project files and directories programmatically
- Monitor file changes via resource subscriptions for real-time updates
Filesystem MCP MCP server FAQ
Filesystem MCP is a Model Context Protocol server that gives AI assistants like Claude and Cursor safe, controlled access to read and write files within allowed directories. It includes tools for searching, comparing, patching, and bulk editing files.
Yes, Filesystem MCP is open-source under the MIT license and free to use.
Add to `~/.cursor/mcp.json` or `.cursor/mcp.json` in your project: `{"mcpServers": {"filesystem": {"command": "npx", "args": ["-y", "@j0hanz/filesystem-mcp@latest", "/path/to/project"]}}}`
Download `filesystem-mcp.mcpb` from the latest release and open it with Claude Desktop, or manually add to `claude_desktop_config.json` with the npx command pointing to your project directory.
No authentication is required. The server uses path-based access control: you specify allowed directories when starting it, and it blocks sensitive file patterns (`.env`, `*.pem`, `*id_rsa*`) by default.
Node.js >= 24 is required. Docker is optional. The server runs on stdio by default or Streamable HTTP with the `--port` flag.
README (reference)
Source of truth, from the repository.
Filesystem MCP Server
Overview
Filesystem-MCP is a Model Context Protocol server that lets AI assistants read and write files within explicitly allowed directories. Sensitive file patterns (.env, *.pem, *id_rsa*) are blocked by default. It exposes filesystem tools, resources, and prompts over stdio or Streamable HTTP transport.
| Aspect | Details |
|---|---|
| Status | Active (see npm badge for the current version) |
| Language | TypeScript (strict) |
| Runtime | Node.js >= 24 |
| Package | npm |
| License | MIT |
Features
| Feature | Description |
|---|---|
| Path guarding | Every path is validated against allowed roots; .env, *.pem, *id_rsa* and similar patterns are denied |
| Filesystem tools | Navigate, inspect, read, and write across all major file operations |
| Batch operations | Most tools accept path, paths[], or files[] for parallel execution |
| Dual transport | stdio by default; --port enables Streamable HTTP for both 2025-era and 2026-07-28 clients |
| File subscriptions | Resource subscriptions push change notifications when watched files update |
| Regex safety | RE2 in all search tools: linear-time matching, so no pattern can ReDoS the server |
Compared with the reference server
How this server differs from @modelcontextprotocol/server-filesystem, checked against its README and source on 2026-09-24:
| Capability | filesystem-mcp | Reference server |
|---|---|---|
| Search inside files | search_text: RE2 regex or literal, linear time | None; search_files matches names only |
| Secret files | .env, *.pem, *id_rsa* denied by default | Not blocked |
| Read-only mode | --read-only removes every mutating tool | Docker ro mounts only |
| Apply a unified diff | patch | None |
| Compare two files | diff | None |
| Replace across many files | replace_text over a glob | None |
| Watch files | Resource subscriptions push change notifications | No resources |
| Transport | stdio, or Streamable HTTP with --port | stdio |
Built with
| Layer | Technology |
|---|---|
| Protocol | MCP SDK v2 (@modelcontextprotocol/server) |
| Runtime | Node.js >= 24 · TypeScript 6 · ESM |
| Transport | stdio (default) · Streamable HTTP (--port) |
| Regex | RE2 (re2-wasm) — linear time, no lookahead/lookbehind/backreferences |
| Container | Docker alpine · multi-stage build · non-root user |
Table of Contents
- Quick start
- Usage
- Project structure
- Configuration
- Scripts
- Security
- Contributing
- Privacy Policy
- License
Quick start
[!NOTE] Requires Node.js ≥ 24.
Prerequisites
| Requirement | Version / Notes |
|---|---|
| Node.js | ≥ 24 |
| npm | Bundled with Node.js |
| Docker | Optional — for container use |
Install via npx
npx -y @j0hanz/filesystem-mcp /path/to/allowed/dir
Or install globally:
npm install -g @j0hanz/filesystem-mcp
filesystem-mcp /path/to/allowed/dir
Install via Docker
docker run -i --rm \
-v /path/to/project:/workspace:ro \
ghcr.io/j0hanz/filesystem-mcp:latest \
--read-only /workspace
Configure in VS Code
Add to .vscode/mcp.json:
{
"servers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest", "/path/to/project"]
}
}
}
Or install via CLI:
code --add-mcp '{"name":"filesystem","command":"npx","args":["-y","@j0hanz/filesystem-mcp@latest","/path/to/project"]}'
Configure in Visual Studio
Add to .vs\mcp.json in your solution directory, or %USERPROFILE%\.mcp.json for a global configuration:
{
"servers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest", "/path/to/project"]
}
}
}
Configure in Claude Desktop
One click: download filesystem-mcp.mcpb, open it with Claude Desktop, and pick the directories to allow. Claude Desktop's built-in Node.js runs it.
Or configure it by hand. Add to your claude_desktop_config.json:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest", "/path/to/project"]
}
}
}
Install in Cursor
Add to .cursor/mcp.json in your project root (project-scoped), or ~/.cursor/mcp.json for a global configuration:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest", "/path/to/project"]
}
}
}
Install as a plugin
The filesystem-mcp plugin wires the server up with project-scoped defaults:
| Client | Install |
|---|---|
| Claude Code | /plugin marketplace add j0hanz/j0hanz-marketplace, then /plugin install filesystem-mcp@j0hanz-marketplace |
| Copilot CLI | copilot plugin marketplace add j0hanz/j0hanz-marketplace, then copilot plugin install filesystem-mcp@j0hanz-marketplace |
| Antigravity CLI | git clone https://github.com/j0hanz/j0hanz-marketplace, then agy plugin install ./j0hanz-marketplace/plugins/filesystem-mcp |
The plugin README covers the defaults and how each client picks the project directory.
Docker configuration
VS Code (.vscode/mcp.json) and Visual Studio (.vs\mcp.json):
{
"servers": {
"filesystem": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-v",
"/path/to/project:/workspace",
"ghcr.io/j0hanz/filesystem-mcp:latest",
"/workspace"
]
}
}
}
Claude Desktop (claude_desktop_config.json) and Cursor (mcp.json):
{
"mcpServers": {
"filesystem": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-v",
"/path/to/project:/workspace",
"ghcr.io/j0hanz/filesystem-mcp:latest",
"/workspace"
]
}
}
}
[!NOTE] For least privilege, use both controls:
:romakes the container mount read-only at the operating-system boundary, while the server's--read-onlyflag removes mutating tools (create,edit,move,delete,patch,replace_text) fromtools/list.
Usage
Tools
All tools are scoped to the configured roots. Call list_roots first to discover what is allowed.
Navigate
| Tool | Description |
|---|---|
list_roots | List allowed workspace roots. Call this first — all other tools scope to these. |
list | List directory contents. Returns entries (dirs-first, alphabetical) and an ASCII tree. |
find_files | Find files by glob pattern (e.g. **/*.ts). Returns matching files with metadata. |
Inspect
| Tool | Description |
|---|---|
stat | Get file/directory metadata: size, modified time, permissions, MIME type, token estimate. |
search_text | Search file contents for text (grep-like). Returns matching lines with context. |
diff | Compare two files and return a unified diff with added/removed line counts. |
Read
| Tool | Description |
|---|---|
read | Read a text file. Supports head/tail and line ranges. Accepts paths[] for batches. |
Write
| Tool | Description |
|---|---|
create | Create one or more files, creating parent directories as needed. An existing file prompts the user to confirm the overwrite; overwrite: true on an entry skips the prompt, append: true adds to the end instead. |
edit | Apply sequential literal string replacements to one or more files (up to 5 files per call, 100 edits per file). |
move | Move, rename, or copy (copy: true) one or more files/directories to explicit destinations. |
delete | Permanently delete one or more files or directories. This action is irreversible. |
replace_text | Bulk search-and-replace across files matching a glob pattern. |
patch | Apply a single-file unified diff and write the result. |
Resources
| URI | Description |
|---|---|
internal://instructions | Server navigation guide — tools overview, constraints, and error recovery. |
filesystem-mcp://file/{+path} | Read a workspace file. Subscribe to receive push notifications on change. |
filesystem-mcp://result/{id} | Ephemeral cached tool output. Expires after ~60 seconds, eviction, or server restart. |
Prompts
| Prompt | Description |
|---|---|
get-help | Return usage instructions, optionally filtered to a specific section. |
Project structure
filesystem-mcp/
├── __tests__/ Test suites (node --test) and shared helpers
├── docs/adr/ Architecture decision records
├── mcpb/manifest.json Claude Desktop extension manifest
├── scripts/ Release-path scripts (MCPB pack, Smithery publish)
├── src/
│ ├── core/ Path guarding, filesystem facade, search, stores, watchers
│ ├── tools/ One file per tool, plus define.ts (registration) and batch.ts
│ ├── transport/ stdio.ts, http.ts, http-policy.ts (auth, Origin, rate limit), shared.ts
│ ├── cli.ts Argument parsing and --print-config
│ ├── cli-help.ts --help / --version text
│ ├── index.ts Process entrypoint, shutdown, transport selection
│ ├── instructions.ts Server instructions sent to every client
│ ├── prompts.ts Prompt definitions and registration
│ ├── resources.ts Resource definitions, subscriptions, completion
│ ├── server.ts Server factory and registrar composition
│ └── transport.ts Facade re-exporting startServer / startHttpServer
└── Dockerfile Multi-stage alpine build, non-root user
Runtime composition flows from src/index.ts to src/transport/ (stdio or HTTP), then to
src/server.ts, the registrars, and finally src/core/. Each registrar owns
the narrow dependency contract it consumes.
Tools use Zod for runtime input validation and named TypeScript types for results;
output schemas are neither validated nor published. defineTool derives wire
annotations from each tool's required readOnlyHint. Every server supplies a
result store, while file-resource links point directly to guarded reads from disk.
| Path | Purpose |
|---|---|
src/core/path.ts | PathGuard — validates every path against allowed roots |
src/core/fs.ts | GuardedFileSystem — guarded filesystem facade |
src/tools/define.ts | Tool registration and execution framework |
src/tools/batch.ts | Batch helpers (runOverPaths, isTotalFailure) |
src/server.ts | Builds shared dependencies and invokes the three registrars |
src/transport/ | stdio (stdio.ts), Streamable HTTP (http.ts), HTTP policy (http-policy.ts) |
Configuration
The server starts with allowed directories from explicit startup configuration:
- Positional directories passed to
filesystem-mcp. - Environment variable
FS_ALLOWED_DIRS(separated by:on POSIX or;on Windows). - Current working directory when
--allow-cwdis enabled.
When --root-boundary / FS_ROOT_BOUNDARY is set, a configured root that
does not fall under it is skipped at startup with a warning; only roots under
the boundary (and later grants under it) are allowed.
Legacy MCP connections may additionally seed roots through the deprecated
roots/list flow. Modern 2026-07-28 connections do not automatically send
workspace roots. They can add access after startup by calling a tool with a
concrete path and approving the elicitation-backed grant. list_roots reports
the roots already configured or accepted; it cannot discover an unknown
workspace by itself.
Over HTTP, 2025-era clients are served statelessly: tools, resources and
prompts work. Confirmations (recursive delete, overwrite, access grants) need a
2026-07-28 client or stdio and answer with a tool error saying so; file
subscriptions are not advertised on that leg, and a resources/subscribe sent
anyway is refused with method-not-found.
Recommended global recipes
VS Code / Cursor / Claude Code (primary recipe)
Configure the project directory explicitly:
Add to your global or project-scoped configuration:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest", "/path/to/project"]
}
}
}
Claude Desktop (fallback recipe via environment variable)
Claude Desktop and similar clients don't support the MCP Roots protocol. Use the FS_ALLOWED_DIRS environment variable to configure allowed folders.
Add to your claude_desktop_config.json:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@j0hanz/filesystem-mcp@latest"],
"env": {
"FS_ALLOWED_DIRS": "/path/to/project1:/path/to/project2"
}
}
}
}
(On Windows, separate directories with a semicolon ; instead of a colon :).
Advanced / per-project positional arguments
You can also restrict access to specific directories by passing positional arguments directly:
# Start with explicit positional paths
filesystem-mcp /path/to/project1 /path/to/project2
Configuration reference
CLI flags
| Flag | Default | Purpose |
|---|---|---|
[dirs...] | — | One or more allowed root directories (positional). A whole argument ${NAME} is read from the environment and dropped when unset |
--allow-cwd | false | Also allow the current working directory as a root |
--walk-cwd | false | Walk up from CWD to find a project root; implies --allow-cwd |
--allow-missing-roots | false | Start even if configured allowed directories do not exist |
--port <n> | — | Enable Streamable HTTP transport on the given port (env: FS_PORT) |
--http-host <host> | — | HTTP server bind address (env: FS_HTTP_HOST) |
--api-key <key> | — | Require this API key on HTTP requests (env: FS_API_KEY) |
--read-only | false | Disable write tools: create, edit, delete, move, patch, replace_text |
--deny <pattern> | — | Block paths matching this pattern; repeatable |
--allow <pattern> | — | Exempt a pattern from the built-in sensitive denylist; repeatable (env: FS_ALLOWLIST). Does not lift --deny/FS_DENYLIST entries |
--allow-sensitive | false | Allow access to sensitive system paths (env: FS_ALLOW_SENSITIVE) |
--root-boundary <path> | — | Require all allowed roots to fall under this path (env: FS_ROOT_BOUNDARY) |
--max-file-size <bytes> | — | Maximum file size for reads and the combined content of one create call, in bytes (env: FS_MAX_FILE_SIZE). Each transport accepts one message of up to 3 × this + 1 MiB |
--log-level <level> | info | RFC 5424 log level, debug through emergency (env: FS_LOG_LEVEL) |
--print-config | false | Print the active configuration as JSON (roots, tools, limits, policy, supported protocol revisions, SDK pins) and exit |
--deny and --allow patterns support * (any run within a segment),
** (any run of segments), ?, [...] classes, and {a,b} alternation.
Dot-leading (hidden) names match like any other — secrets/** denies
secrets/.env, *id_rsa* denies .id_rsa.
Environment variables
All boolean variables accept true or 1 to enable and false, 0, or
unset to disable; any other value logs a warning and reads as disabled.
Flags take precedence when both are set.
| Variable | Purpose |
|---|---|
FS_ALLOWED_DIRS | Colon-separated (POSIX) or semicolon-separated (Windows) list of directories to allow. |
FS_ROOT_BOUNDARY | Path prefix all allowed roots must fall under (mirrors --root-boundary). |
FS_ALLOW_CWD_WALK | Walk up from CWD to find a project root (mirrors --walk-cwd). |
FS_ALLOW_MISSING_ROOTS | Start even if configured directories do not exist (mirrors --allow-missing-roots). |
FS_ALLOW_SENSITIVE | Allow access to sensitive system paths (mirrors --allow-sensitive). |
FS_DENYLIST | Comma-separated list of paths or patterns to block (mirrors --deny). |
FS_ALLOWLIST | Comma-separated patterns exempted from the built-in sensitive denylist (mirrors --allow). Never lifts FS_DENYLIST/--deny entries. |
FS_MAX_FILE_SIZE | Maximum file size for reads and for one create call's combined content, in bytes (mirrors --max-file-size). Also sizes the per-message wire limit: 3 × this + 1 MiB. |
FS_LOG_LEVEL | RFC 5424 log level: debug, info, notice, warn/warning, error, critical, alert, or emergency (mirrors --log-level). |
FS_PORT | Start the Streamable HTTP transport on this port; unset = stdio (mirrors --port). |
FS_HTTP_HOST | HTTP server bind address (mirrors --http-host). |
FS_API_KEY | API key required on HTTP requests (mirrors --api-key). |
FS_TRUST_PROXY | Express trust proxy setting: hop count or expression. Unset = do not trust X-Forwarded-*. |
FS_ALLOWED_HOSTS | Comma-separated Host header values to accept (HTTP transport). |
FS_ALLOWED_ORIGINS | Comma-separated origin hostnames allowed to call /mcp from a browser. Replaces the localhost default, so also list localhost, 127.0.0.1 or [::1] if local browser clients still need access. |
FS_ALLOW_UNRESTRICTED_HOSTS | Bind a wildcard host with no Host validation (accepts the risk). |
FS_PUBLIC_URL | Resource identifier URL for RFC 9728 discovery. |
FS_RATE_LIMIT_RPM | Per-client-IP requests/minute (default 120 with API-key authentication, 6,000 for keyless loopback; range 1–100000). |
FS_MAX_WATCHERS | Max concurrent file watchers (default 256, 1–4096). |
NO_COLOR | Any value disables ANSI color output. |
FS_REQUEST_STATE_KEY | HMAC key sealing input_required requestState across retry rounds. Optional (random per boot if unset); set it, at >=32 bytes UTF-8, to keep in-flight rounds alive across a restart. |
Examples
# Allow current working directory
filesystem-mcp --allow-cwd
# HTTP transport on port 3000
filesystem-mcp --port 3000
Scripts
| Mode | Command | Description |
|---|---|---|
| Full check | npm run check | Run build, type check, lint, format, knip, and tests |
| Auto-fix + check | npm run fix | Auto-fix formatting/linting and run the full check |
| Static only | npm run check:static | Run static analysis without tests |
| Tests only | npm test | Run tests; accepts native node --test options |
Security
[!IMPORTANT] Report vulnerabilities privately via GitHub Security Advisories. Do not open public issues for security reports.
| Topic | Detail |
|---|---|
| Path traversal | Every path is resolved and validated against allowed roots before any operation |
| Sensitive files | .env, *.pem, *id_rsa*, and similar patterns are denied by default |
| Regex safety | RE2 cannot backtrack, so a hostile pattern cannot hang the server (ReDoS) |
| Container | Runs as non-root mcp user; bind mounts control what is exposed |
Contributing
- Fork the repository.
- Create a feature branch:
git checkout -b feat/your-feature. - Commit your changes with a clear message.
- Run
npm run checkto confirm tests, types, lint, formatting, and knip all pass. - Open a pull request.
Privacy Policy
filesystem-mcp runs entirely on your machine. This policy covers the npm package, the Docker image, and the .mcpb desktop extension.
- Data collection: none. The server has no telemetry, analytics, or crash reporting, and makes no outbound network requests.
- Use and storage: files are read and written only inside the directories you allow, and only when your MCP client calls a tool. Tool results go to that client and nowhere else. Short-lived result caches live in memory and disappear when the server exits.
- Third-party sharing: none by this server. Your MCP client may send tool results to its model provider under that client's own privacy policy.
- Retention: nothing is kept after the process exits. Diagnostic logs go to stderr on your machine; your MCP client may save them in its own log files.
- Contact: open an issue at https://github.com/j0hanz/filesystem-mcp/issues, or report security problems privately through GitHub Security Advisories.
License
Released under the MIT License. See LICENSE for details.
Related MCP servers

Memory MCP Server
SQLite-backed MCP server for persistent memory, full-text retrieval, and graph traversal.

io.github.j0hanz/superfetch
Intelligent web content fetcher MCP server that converts HTML to clean, AI-readable JSONL format

MTG MCP Server
Magic: The Gathering card search, combos, draft analytics, and Commander tools for AI assistants.

io.github.j7an/nexus-mcp
Delegate tasks to coding agents (Claude, Codex) from any MCP client