{
  "markdown": "# Filesystem MCP Server\n\n[![License](https://img.shields.io/github/license/j0hanz/filesystem-mcp?style=for-the-badge)](https://github.com/j0hanz/filesystem-mcp/blob/main/LICENSE) [![npm version](https://img.shields.io/npm/v/%40j0hanz%2Ffilesystem-mcp?style=for-the-badge&logo=npm&logoColor=white)](https://www.npmjs.com/package/@j0hanz/filesystem-mcp) [![Build](https://img.shields.io/github/actions/workflow/status/j0hanz/filesystem-mcp/release.yml?style=for-the-badge&logo=githubactions&logoColor=white&label=build)](https://github.com/j0hanz/filesystem-mcp/actions) [![GitHub stars](https://img.shields.io/github/stars/j0hanz/filesystem-mcp?style=for-the-badge&logo=github)](https://github.com/j0hanz/filesystem-mcp/stargazers)\n\n[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect/mcp/install?name=filesystem&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Ffilesystem-mcp%40latest%22%5D%7D) [![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=filesystem&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Ffilesystem-mcp%40latest%22%5D%7D&quality=insiders) [![Install in Visual Studio](https://img.shields.io/badge/Visual_Studio-Install-C16FDE?logo=visualstudio&logoColor=white)](https://vs-open.link/mcp-install?%7B%22filesystem-mcp%22%3A%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Ffilesystem-mcp%40latest%22%5D%7D%7D) [![Install in Cursor](https://img.shields.io/badge/Cursor-Install-000000?style=flat-square&logo=cursor&logoColor=white)](cursor://anysphere.cursor-deeplink/mcp/install?name=filesystem&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBqMGhhbnovZmlsZXN5c3RlbS1tY3BAbGF0ZXN0Il19)\n\n## Overview\n\nFilesystem-MCP is a [Model Context Protocol](https://modelcontextprotocol.io) 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.\n\n| Aspect       | Details                                        |\n| :----------- | :--------------------------------------------- |\n| **Status**   | Active (see npm badge for the current version) |\n| **Language** | TypeScript (strict)                            |\n| **Runtime**  | Node.js >= 24                                  |\n| **Package**  | npm                                            |\n| **License**  | MIT                                            |\n\n## Features\n\n| Feature                | Description                                                                                                |\n| :--------------------- | :--------------------------------------------------------------------------------------------------------- |\n| **Path guarding**      | Every path is validated against allowed roots; `.env`, `*.pem`, `*id_rsa*` and similar patterns are denied |\n| **Filesystem tools**   | Navigate, inspect, read, and write across all major file operations                                        |\n| **Batch operations**   | Most tools accept `path`, `paths[]`, or `files[]` for parallel execution                                   |\n| **Dual transport**     | stdio by default; `--port` enables Streamable HTTP                                                         |\n| **File subscriptions** | Resource subscriptions push change notifications when watched files update                                 |\n| **Regex safety**       | RE2 in all search tools: linear-time matching, so no pattern can ReDoS the server                          |\n\n## Built with\n\n[![Node.js](https://img.shields.io/badge/node-%3E%3D24-339933?style=for-the-badge&logo=node.js&logoColor=white)](https://nodejs.org) [![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178C6?style=for-the-badge&logo=typescript&logoColor=white)](https://www.typescriptlang.org) [![Docker](https://img.shields.io/badge/Docker-ready-2496ED?style=for-the-badge&logo=docker&logoColor=white)](https://www.docker.com)\n\n| Layer     | Technology                                                             |\n| :-------- | :--------------------------------------------------------------------- |\n| Protocol  | MCP SDK v2 (`@modelcontextprotocol/server`)                            |\n| Runtime   | Node.js >= 24 · TypeScript 6 · ESM                                     |\n| Transport | stdio (default) · Streamable HTTP (`--port`)                           |\n| Regex     | RE2 (`re2-wasm`) — linear time, no lookahead/lookbehind/backreferences |\n| Container | Docker alpine · multi-stage build · non-root user                      |\n\n## Table of Contents\n\n- [Quick start](#quick-start)\n- [Usage](#usage)\n- [Project structure](#project-structure)\n- [Configuration](#configuration)\n- [Scripts](#scripts)\n- [Security](#security)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Quick start\n\n> [!NOTE]\n> Requires Node.js ≥ 24.\n\n### Prerequisites\n\n| Requirement | Version / Notes              |\n| :---------- | :--------------------------- |\n| Node.js     | ≥ 24                         |\n| npm         | Bundled with Node.js         |\n| Docker      | Optional — for container use |\n\n### Install via npx\n\n```bash\nnpx -y @j0hanz/filesystem-mcp /path/to/allowed/dir\n```\n\nOr install globally:\n\n```bash\nnpm install -g @j0hanz/filesystem-mcp\nfilesystem-mcp /path/to/allowed/dir\n```\n\n### Install via Docker\n\n```bash\ndocker run -i --rm \\\n  -v /path/to/project:/workspace:ro \\\n  ghcr.io/j0hanz/filesystem-mcp:latest \\\n  --read-only /workspace\n```\n\n### Configure in VS Code\n\nAdd to `.vscode/mcp.json`:\n\n```json\n{\n  \"servers\": {\n    \"filesystem\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@j0hanz/filesystem-mcp@latest\", \"/path/to/project\"]\n    }\n  }\n}\n```\n\nOr install via CLI:\n\n```sh\ncode --add-mcp '{\"name\":\"filesystem\",\"command\":\"npx\",\"args\":[\"-y\",\"@j0hanz/filesystem-mcp@latest\",\"/path/to/project\"]}'\n```\n\n### Configure in Visual Studio\n\nAdd to `.vs\\mcp.json` in your solution directory, or `%USERPROFILE%\\.mcp.json` for a global configuration:\n\n```json\n{\n  \"servers\": {\n    \"filesystem\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@j0hanz/filesystem-mcp@latest\", \"/path/to/project\"]\n    }\n  }\n}\n```\n\n### Configure in Claude Desktop\n\nAdd to your `claude_desktop_config.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"filesystem\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@j0hanz/filesystem-mcp@latest\", \"/path/to/project\"]\n    }\n  }\n}\n```\n\n### Install in Cursor\n\nAdd to `.cursor/mcp.json` in your project root (project-scoped), or `~/.cursor/mcp.json` for a global configuration:\n\n```json\n{\n  \"mcpServers\": {\n    \"filesystem\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@j0hanz/filesystem-mcp@latest\", \"/path/to/project\"]\n    }\n  }\n}\n```\n\n### Docker configuration\n\nVS Code (`.vscode/mcp.json`) and Visual Studio (`.vs\\mcp.json`):\n\n```json\n{\n  \"servers\": {\n    \"filesystem\": {\n      \"command\": \"docker\",\n      \"args\": [\n        \"run\",\n        \"-i\",\n        \"--rm\",\n        \"-v\",\n        \"/path/to/project:/workspace\",\n        \"ghcr.io/j0hanz/filesystem-mcp:latest\",\n        \"/workspace\"\n      ]\n    }\n  }\n}\n```\n\nClaude Desktop (`claude_desktop_config.json`) and Cursor (`mcp.json`):\n\n```json\n{\n  \"mcpServers\": {\n    \"filesystem\": {\n      \"command\": \"docker\",\n      \"args\": [\n        \"run\",\n        \"-i\",\n        \"--rm\",\n        \"-v\",\n        \"/path/to/project:/workspace\",\n        \"ghcr.io/j0hanz/filesystem-mcp:latest\",\n        \"/workspace\"\n      ]\n    }\n  }\n}\n```\n\n> [!NOTE]\n> For least privilege, use both controls: `:ro` makes the container mount\n> read-only at the operating-system boundary, while the server's `--read-only`\n> flag removes mutating tools (`create`, `edit`, `move`, `delete`, `patch`,\n> `replace_text`) from `tools/list`.\n\n## Usage\n\n### Tools\n\nAll tools are scoped to the configured roots. Call `list_roots` first to discover what is allowed.\n\n#### Navigate\n\n| Tool         | Description                                                                            |\n| :----------- | :------------------------------------------------------------------------------------- |\n| `list_roots` | List allowed workspace roots. Call this first — all other tools scope to these.        |\n| `list`       | List directory contents. Returns entries (dirs-first, alphabetical) and an ASCII tree. |\n| `find_files` | Find files by glob pattern (e.g. `**/*.ts`). Returns matching files with metadata.     |\n\n#### Inspect\n\n| Tool          | Description                                                                               |\n| :------------ | :---------------------------------------------------------------------------------------- |\n| `stat`        | Get file/directory metadata: size, modified time, permissions, MIME type, token estimate. |\n| `search_text` | Search file contents for text (grep-like). Returns matching lines with context.           |\n| `diff`        | Compare two files and return a unified diff with added/removed line counts.               |\n\n#### Read\n\n| Tool   | Description                                                                          |\n| :----- | :----------------------------------------------------------------------------------- |\n| `read` | Read a text file. Supports head/tail and line ranges. Accepts `paths[]` for batches. |\n\n#### Write\n\n| Tool           | Description                                                                                       |\n| :------------- | :------------------------------------------------------------------------------------------------ |\n| `create`       | Create one or more files, overwriting existing content and creating parent directories as needed. |\n| `edit`         | Apply sequential literal string replacements to one or more files (max 5 per call).               |\n| `move`         | Move, rename, or copy (`copy: true`) one or more files/directories to explicit destinations.      |\n| `delete`       | Permanently delete one or more files or directories. This action is irreversible.                 |\n| `replace_text` | Bulk search-and-replace across files matching a glob pattern.                                     |\n| `patch`        | Apply a single-file unified diff and write the result.                                            |\n\n### Resources\n\n| URI                             | Description                                                                           |\n| :------------------------------ | :------------------------------------------------------------------------------------ |\n| `internal://instructions`       | Server navigation guide — tools overview, constraints, and error recovery.            |\n| `filesystem-mcp://file/{+path}` | Read a workspace file. Subscribe to receive push notifications on change.             |\n| `filesystem-mcp://result/{id}`  | Ephemeral cached tool output. Expires after ~60 seconds, eviction, or server restart. |\n\n### Prompts\n\n| Prompt     | Description                                                           |\n| :--------- | :-------------------------------------------------------------------- |\n| `get-help` | Return usage instructions, optionally filtered to a specific section. |\n\n## Project structure\n\n```text\nfilesystem-mcp/\n├── __tests__/        Test suites\n├── scripts/          Build and task utilities\n├── src/\n│   ├── core/         Path guarding, filesystem abstraction, concurrency, observability\n│   ├── tools/        Tool definitions and registration\n│   ├── index.ts      Process entrypoint and transport selection\n│   ├── server.ts     Server factory and registrar composition\n│   ├── transport/    stdio and Streamable HTTP transport setup\n│   ├── prompts.ts    Prompt definitions and registration\n│   └── resources.ts  Resource definitions and registration\n└── Dockerfile        Multi-stage alpine build, non-root user\n```\n\nRuntime composition flows from `src/index.ts` to `src/transport.ts`, then to\n`src/server.ts`, the registrars, and finally `src/core/`. Each registrar owns\nthe narrow dependency contract it consumes.\n\n| Path                  | Purpose                                                        |\n| :-------------------- | :------------------------------------------------------------- |\n| `src/core/path.ts`    | `PathGuard` — validates every path against allowed roots       |\n| `src/core/fs.ts`      | `GuardedFileSystem` — guarded filesystem facade                |\n| `src/tools/define.ts` | Tool registration and execution framework                      |\n| `src/tools/batch.ts`  | Batch helpers (runOverPaths, normalizeBatchItems)              |\n| `src/server.ts`       | Builds shared dependencies and invokes the three registrars    |\n| `src/transport.ts`    | Owns stdio and Streamable HTTP setup around the server factory |\n\n## Configuration\n\nThe server starts with allowed directories from explicit startup configuration:\n\n1. **Positional directories** passed to `filesystem-mcp`.\n2. **Environment variable** `FS_ALLOWED_DIRS` (separated by `:` on POSIX or `;` on Windows).\n3. **Current working directory** when `--allow-cwd` is enabled.\n\nLegacy MCP connections may additionally seed roots through the deprecated\n`roots/list` flow. Modern 2026-07-28 connections do not automatically send\nworkspace roots. They can add access after startup by calling a tool with a\nconcrete path and approving the elicitation-backed grant. `list_roots` reports\nthe roots already configured or accepted; it cannot discover an unknown\nworkspace by itself.\n\n### Recommended global recipes\n\n#### VS Code / Cursor / Claude Code (primary recipe)\n\nConfigure the project directory explicitly:\n\nAdd to your global or project-scoped configuration:\n\n```json\n{\n  \"mcpServers\": {\n    \"filesystem\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@j0hanz/filesystem-mcp@latest\", \"/path/to/project\"]\n    }\n  }\n}\n```\n\n#### Claude Desktop (fallback recipe via environment variable)\n\nClaude Desktop and similar clients don't support the MCP Roots protocol. Use the `FS_ALLOWED_DIRS` environment variable to configure allowed folders.\n\nAdd to your `claude_desktop_config.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"filesystem\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@j0hanz/filesystem-mcp@latest\"],\n      \"env\": {\n        \"FS_ALLOWED_DIRS\": \"/path/to/project1:/path/to/project2\"\n      }\n    }\n  }\n}\n```\n\n_(On Windows, separate directories with a semicolon `;` instead of a colon `:`)._\n\n### Advanced / per-project positional arguments\n\nYou can also restrict access to specific directories by passing positional arguments directly:\n\n```bash\n# Start with explicit positional paths\nfilesystem-mcp /path/to/project1 /path/to/project2\n```\n\n---\n\n### Configuration reference\n\n#### CLI flags\n\n| Flag                      | Default | Purpose                                                                            |\n| :------------------------ | :------ | :--------------------------------------------------------------------------------- |\n| `[dirs...]`               | —       | One or more allowed root directories (positional)                                  |\n| `--allow-cwd`             | `false` | Also allow the current working directory as a root                                 |\n| `--walk-cwd`              | `false` | Walk up from CWD to find a project root; implies `--allow-cwd`                     |\n| `--allow-missing-roots`   | `false` | Start even if configured allowed directories do not exist                          |\n| `--port <n>`              | —       | Enable Streamable HTTP transport on the given port (env: `FS_PORT`)                |\n| `--http-host <host>`      | —       | HTTP server bind address (env: `FS_HTTP_HOST`)                                     |\n| `--api-key <key>`         | —       | Require this API key on HTTP requests (env: `FS_API_KEY`)                          |\n| `--read-only`             | `false` | Disable write tools: `create`, `edit`, `delete`, `move`, `patch`, `replace_text`   |\n| `--safe`                  | `false` | Alias for `--read-only`                                                            |\n| `--deny <pattern>`        | —       | Block paths matching this pattern; repeatable                                      |\n| `--allow-sensitive`       | `false` | Allow access to sensitive system paths (env: `FS_ALLOW_SENSITIVE`)                 |\n| `--root-boundary <path>`  | —       | Require all allowed roots to fall under this path (env: `FS_ROOT_BOUNDARY`)        |\n| `--max-file-size <bytes>` | —       | Maximum file size for reads in bytes (env: `FS_MAX_FILE_SIZE`)                     |\n| `--log-level <level>`     | `info`  | RFC 5424 log level, `debug` through `emergency` (env: `FS_LOG_LEVEL`)              |\n| `--print-config`          | `false` | Print the active configuration and exit (use `--json` for machine-readable output) |\n| `--json`                  | `false` | Output `--print-config` as JSON                                                    |\n\n#### Environment variables\n\nAll boolean variables accept `true` or `1` to enable and `false`, `0`, or\nunset to disable; any other value logs a warning and reads as disabled.\nFlags take precedence when both are set.\n\n| Variable                      | Purpose                                                                                                                                                                                |\n| :---------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `FS_ALLOWED_DIRS`             | Colon-separated (POSIX) or semicolon-separated (Windows) list of directories to allow.                                                                                                 |\n| `FS_ROOT_BOUNDARY`            | Path prefix all allowed roots must fall under (mirrors `--root-boundary`).                                                                                                             |\n| `FS_ALLOW_CWD_WALK`           | Walk up from CWD to find a project root (mirrors `--walk-cwd`).                                                                                                                        |\n| `FS_ALLOW_MISSING_ROOTS`      | Start even if configured directories do not exist (mirrors `--allow-missing-roots`).                                                                                                   |\n| `FS_ALLOW_SENSITIVE`          | Allow access to sensitive system paths (mirrors `--allow-sensitive`).                                                                                                                  |\n| `FS_DENYLIST`                 | Comma-separated list of paths or patterns to block (mirrors `--deny`).                                                                                                                 |\n| `FS_MAX_FILE_SIZE`            | Maximum file size for reads in bytes (mirrors `--max-file-size`).                                                                                                                      |\n| `FS_LOG_LEVEL`                | RFC 5424 log level: `debug`, `info`, `notice`, `warn`/`warning`, `error`, `critical`, `alert`, or `emergency` (mirrors `--log-level`).                                                 |\n| `FS_PORT`                     | Start the Streamable HTTP transport on this port; unset = stdio (mirrors `--port`).                                                                                                    |\n| `FS_HTTP_HOST`                | HTTP server bind address (mirrors `--http-host`).                                                                                                                                      |\n| `FS_API_KEY`                  | API key required on HTTP requests (mirrors `--api-key`).                                                                                                                               |\n| `FS_TRUST_PROXY`              | Express `trust proxy` setting: hop count or expression. Unset = do not trust `X-Forwarded-*`.                                                                                          |\n| `FS_ALLOWED_HOSTS`            | Comma-separated Host header values to accept (HTTP transport).                                                                                                                         |\n| `FS_ALLOWED_ORIGINS`          | Comma-separated origin hostnames for CORS.                                                                                                                                             |\n| `FS_ALLOW_UNRESTRICTED_HOSTS` | Bind a wildcard host with no Host validation (accepts the risk).                                                                                                                       |\n| `FS_PUBLIC_URL`               | Resource identifier URL for RFC 9728 discovery.                                                                                                                                        |\n| `FS_RATE_LIMIT_RPM`           | Per-client-IP requests/minute (default 120 with API-key authentication, 6,000 for keyless loopback; range 1–100000).                                                                   |\n| `FS_MAX_REQUEST_BYTES`        | Max HTTP request body bytes (default 4194304, 1024–268435456).                                                                                                                         |\n| `FS_KEEPALIVE_TIMEOUT_MS`     | HTTP keep-alive timeout in ms; set above any fronting proxy's idle timeout (default 5000, 1000–600000).                                                                                |\n| `FS_MAX_WATCHERS`             | Max concurrent file watchers (default 256, 1–4096).                                                                                                                                    |\n| `FS_MAX_INLINE_MATCHES`       | Deprecated and ignored; `maxResults` sets the `search_text` page size. Logs a warning when set; removed in the next major.                                                             |\n| `FS_MAX_READ_MANY_BYTES`      | Max total bytes across a batched `read` (default 524288, 10240–104857600).                                                                                                             |\n| `FS_SEARCH_TIMEOUT_MS`        | Search timeout in ms (default 5000, 100–60000).                                                                                                                                        |\n| `NO_COLOR`                    | Any value disables ANSI color output.                                                                                                                                                  |\n| `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. |\n\n### Examples\n\n```bash\n# Allow current working directory\nfilesystem-mcp --allow-cwd\n\n# HTTP transport on port 3000\nfilesystem-mcp --port 3000\n```\n\n## Scripts\n\n| Mode             | Command                          | Description                                          |\n| :--------------- | :------------------------------- | :--------------------------------------------------- |\n| Full check       | `node scripts/tasks.mjs`         | Run build, type check, lint, format, knip, and tests |\n| Auto-fix + check | `node scripts/tasks.mjs fix`     | Auto-fix formatting/linting and run the full check   |\n| Static only      | `node scripts/tasks.mjs --quick` | Run static analysis without tests                    |\n| Tests only       | `node scripts/tasks.mjs test`    | Run tests; accepts native `node --test` options      |\n\n## Security\n\n> [!IMPORTANT]\n> Report vulnerabilities privately via [GitHub Security Advisories](https://github.com/j0hanz/filesystem-mcp/security/advisories). Do not open public issues for security reports.\n\n| Topic           | Detail                                                                          |\n| :-------------- | :------------------------------------------------------------------------------ |\n| Path traversal  | Every path is resolved and validated against allowed roots before any operation |\n| Sensitive files | `.env`, `*.pem`, `*id_rsa*`, and similar patterns are denied by default         |\n| Regex safety    | RE2 cannot backtrack, so a hostile pattern cannot hang the server (ReDoS)       |\n| Container       | Runs as non-root `mcp` user; bind mounts control what is exposed                |\n\n## Contributing\n\n1. Fork the repository.\n2. Create a feature branch: `git checkout -b feat/your-feature`.\n3. Commit your changes with a clear message.\n4. Run `node scripts/tasks.mjs` to confirm tests, types, lint, formatting, and knip all pass.\n5. Open a pull request.\n\n[![Contributors](https://contrib.rocks/image?repo=j0hanz/filesystem-mcp)](https://github.com/j0hanz/filesystem-mcp/graphs/contributors)\n\n## License\n\nReleased under the MIT License. See [LICENSE](LICENSE) for details.\n",
  "bytes": 25487,
  "sha": "f074a2390811fbaf2b09e8b9cb29c6e18ad825a78b2f856087848f325148a7a5",
  "repo_slug": "j0hanz/filesystem-context-mcp-server",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_j0hanz_filesystem_context_55ca76fd/readme"
}