@j0hanz/fs-context-mcp 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/README.md +171 -417
  2. package/dist/assets/logo.svg +3766 -0
  3. package/dist/config.d.ts +0 -1
  4. package/dist/config.js +0 -1
  5. package/dist/index.d.ts +0 -1
  6. package/dist/index.js +0 -1
  7. package/dist/lib/constants.d.ts +0 -1
  8. package/dist/lib/constants.js +0 -1
  9. package/dist/lib/errors.d.ts +0 -1
  10. package/dist/lib/errors.js +0 -1
  11. package/dist/lib/file-operations/file-info.d.ts +0 -1
  12. package/dist/lib/file-operations/file-info.js +0 -1
  13. package/dist/lib/file-operations/gitignore.d.ts +0 -1
  14. package/dist/lib/file-operations/gitignore.js +0 -1
  15. package/dist/lib/file-operations/glob-engine.d.ts +0 -1
  16. package/dist/lib/file-operations/glob-engine.js +101 -84
  17. package/dist/lib/file-operations/list-directory.d.ts +0 -1
  18. package/dist/lib/file-operations/list-directory.js +91 -62
  19. package/dist/lib/file-operations/read-multiple-files.d.ts +0 -1
  20. package/dist/lib/file-operations/read-multiple-files.js +0 -1
  21. package/dist/lib/file-operations/search-content.d.ts +0 -1
  22. package/dist/lib/file-operations/search-content.js +68 -21
  23. package/dist/lib/file-operations/search-files.d.ts +0 -1
  24. package/dist/lib/file-operations/search-files.js +21 -11
  25. package/dist/lib/file-operations/search-worker.d.ts +0 -1
  26. package/dist/lib/file-operations/search-worker.js +0 -1
  27. package/dist/lib/file-operations/tree.d.ts +0 -1
  28. package/dist/lib/file-operations/tree.js +18 -8
  29. package/dist/lib/fs-helpers.d.ts +0 -1
  30. package/dist/lib/fs-helpers.js +19 -25
  31. package/dist/lib/observability.d.ts +0 -1
  32. package/dist/lib/observability.js +49 -43
  33. package/dist/lib/path-policy.d.ts +0 -1
  34. package/dist/lib/path-policy.js +0 -1
  35. package/dist/lib/path-validation.d.ts +0 -1
  36. package/dist/lib/path-validation.js +54 -38
  37. package/dist/lib/resource-store.d.ts +0 -1
  38. package/dist/lib/resource-store.js +0 -1
  39. package/dist/resources.d.ts +2 -3
  40. package/dist/resources.js +16 -3
  41. package/dist/schemas.d.ts +0 -1
  42. package/dist/schemas.js +35 -51
  43. package/dist/server.d.ts +0 -1
  44. package/dist/server.js +42 -11
  45. package/dist/tools/list-directory.d.ts +0 -1
  46. package/dist/tools/list-directory.js +14 -2
  47. package/dist/tools/read-multiple.d.ts +0 -1
  48. package/dist/tools/read-multiple.js +14 -2
  49. package/dist/tools/read.d.ts +0 -1
  50. package/dist/tools/read.js +14 -2
  51. package/dist/tools/roots.d.ts +0 -1
  52. package/dist/tools/roots.js +14 -2
  53. package/dist/tools/search-content.d.ts +0 -1
  54. package/dist/tools/search-content.js +29 -14
  55. package/dist/tools/search-files.d.ts +0 -1
  56. package/dist/tools/search-files.js +14 -2
  57. package/dist/tools/shared.d.ts +7 -1
  58. package/dist/tools/shared.js +7 -4
  59. package/dist/tools/stat-many.d.ts +0 -1
  60. package/dist/tools/stat-many.js +14 -2
  61. package/dist/tools/stat.d.ts +0 -1
  62. package/dist/tools/stat.js +14 -2
  63. package/dist/tools/tree.d.ts +0 -1
  64. package/dist/tools/tree.js +14 -2
  65. package/dist/tools.d.ts +0 -1
  66. package/dist/tools.js +0 -1
  67. package/package.json +22 -19
  68. package/dist/config.d.ts.map +0 -1
  69. package/dist/config.js.map +0 -1
  70. package/dist/index.d.ts.map +0 -1
  71. package/dist/index.js.map +0 -1
  72. package/dist/lib/constants.d.ts.map +0 -1
  73. package/dist/lib/constants.js.map +0 -1
  74. package/dist/lib/errors.d.ts.map +0 -1
  75. package/dist/lib/errors.js.map +0 -1
  76. package/dist/lib/file-operations/file-info.d.ts.map +0 -1
  77. package/dist/lib/file-operations/file-info.js.map +0 -1
  78. package/dist/lib/file-operations/gitignore.d.ts.map +0 -1
  79. package/dist/lib/file-operations/gitignore.js.map +0 -1
  80. package/dist/lib/file-operations/glob-engine.d.ts.map +0 -1
  81. package/dist/lib/file-operations/glob-engine.js.map +0 -1
  82. package/dist/lib/file-operations/list-directory.d.ts.map +0 -1
  83. package/dist/lib/file-operations/list-directory.js.map +0 -1
  84. package/dist/lib/file-operations/read-multiple-files.d.ts.map +0 -1
  85. package/dist/lib/file-operations/read-multiple-files.js.map +0 -1
  86. package/dist/lib/file-operations/search-content.d.ts.map +0 -1
  87. package/dist/lib/file-operations/search-content.js.map +0 -1
  88. package/dist/lib/file-operations/search-files.d.ts.map +0 -1
  89. package/dist/lib/file-operations/search-files.js.map +0 -1
  90. package/dist/lib/file-operations/search-worker.d.ts.map +0 -1
  91. package/dist/lib/file-operations/search-worker.js.map +0 -1
  92. package/dist/lib/file-operations/tree.d.ts.map +0 -1
  93. package/dist/lib/file-operations/tree.js.map +0 -1
  94. package/dist/lib/fs-helpers.d.ts.map +0 -1
  95. package/dist/lib/fs-helpers.js.map +0 -1
  96. package/dist/lib/observability.d.ts.map +0 -1
  97. package/dist/lib/observability.js.map +0 -1
  98. package/dist/lib/path-policy.d.ts.map +0 -1
  99. package/dist/lib/path-policy.js.map +0 -1
  100. package/dist/lib/path-validation.d.ts.map +0 -1
  101. package/dist/lib/path-validation.js.map +0 -1
  102. package/dist/lib/resource-store.d.ts.map +0 -1
  103. package/dist/lib/resource-store.js.map +0 -1
  104. package/dist/resources.d.ts.map +0 -1
  105. package/dist/resources.js.map +0 -1
  106. package/dist/schemas.d.ts.map +0 -1
  107. package/dist/schemas.js.map +0 -1
  108. package/dist/server.d.ts.map +0 -1
  109. package/dist/server.js.map +0 -1
  110. package/dist/tools/list-directory.d.ts.map +0 -1
  111. package/dist/tools/list-directory.js.map +0 -1
  112. package/dist/tools/read-multiple.d.ts.map +0 -1
  113. package/dist/tools/read-multiple.js.map +0 -1
  114. package/dist/tools/read.d.ts.map +0 -1
  115. package/dist/tools/read.js.map +0 -1
  116. package/dist/tools/roots.d.ts.map +0 -1
  117. package/dist/tools/roots.js.map +0 -1
  118. package/dist/tools/search-content.d.ts.map +0 -1
  119. package/dist/tools/search-content.js.map +0 -1
  120. package/dist/tools/search-files.d.ts.map +0 -1
  121. package/dist/tools/search-files.js.map +0 -1
  122. package/dist/tools/shared.d.ts.map +0 -1
  123. package/dist/tools/shared.js.map +0 -1
  124. package/dist/tools/stat-many.d.ts.map +0 -1
  125. package/dist/tools/stat-many.js.map +0 -1
  126. package/dist/tools/stat.d.ts.map +0 -1
  127. package/dist/tools/stat.js.map +0 -1
  128. package/dist/tools/tree.d.ts.map +0 -1
  129. package/dist/tools/tree.js.map +0 -1
  130. package/dist/tools.d.ts.map +0 -1
  131. package/dist/tools.js.map +0 -1
package/README.md CHANGED
@@ -1,100 +1,66 @@
1
1
  # FS Context MCP Server
2
2
 
3
- <img src="docs/logo.png" alt="FS Context MCP Server Logo" width="125">
3
+ <img src="assets/logo.svg" alt="SuperFetch MCP Logo" width="300">
4
4
 
5
- A read-only MCP server that provides AI assistants with secure filesystem access for exploring, searching, and reading files within approved directories.
6
-
7
- [![npm version](https://img.shields.io/npm/v/@j0hanz/fs-context-mcp.svg)](https://www.npmjs.com/package/@j0hanz/fs-context-mcp)
8
- [![License](https://img.shields.io/npm/l/@j0hanz/fs-context-mcp)](LICENSE)
9
- [![Node.js](https://img.shields.io/badge/node-%3E%3D22.17.0-brightgreen)](https://nodejs.org)
10
- [![TypeScript](https://img.shields.io/badge/TypeScript-5.9.3-blue)](https://www.typescriptlang.org/)
11
- [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-1.25.2-purple)](https://modelcontextprotocol.io)
12
-
13
- ## One-Click Install
5
+ [![npm version](https://img.shields.io/npm/v/@j0hanz/fs-context-mcp.svg)](https://www.npmjs.com/package/@j0hanz/fs-context-mcp) [![License](https://img.shields.io/npm/l/@j0hanz/fs-context-mcp)](LICENSE) [![Node.js](https://img.shields.io/badge/node-%3E%3D22.19.8-brightgreen)](https://nodejs.org) [![TypeScript](https://img.shields.io/badge/TypeScript-5.9.3-blue)](https://www.typescriptlang.org/) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-1.25.3-purple)](https://modelcontextprotocol.io)
14
6
 
15
7
  [![Install with NPX in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=fs-context&inputs=%5B%5D&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Ffs-context-mcp%40latest%22%2C%22%24%7BworkspaceFolder%7D%22%5D%7D) [![Install with NPX 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=fs-context&inputs=%5B%5D&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Ffs-context-mcp%40latest%22%2C%22%24%7BworkspaceFolder%7D%22%5D%7D&quality=insiders)
16
8
 
17
- [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=fs-context&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBqMGhhbnovZnMtY29udGV4dC1tY3BAbGF0ZXN0IiwiJHt3b3Jrc3BhY2VGb2xkZXJ9Il19)
9
+ Read-only Model Context Protocol (MCP) server for secure filesystem exploration, searching, and analysis.
18
10
 
19
11
  ## Overview
20
12
 
21
- This server enables AI assistants to navigate your filesystem through a set of read-only tools:
22
-
23
- - Explore directory structures with `ls` and `tree`
24
- - Find files using glob patterns with `find`
25
- - Search file contents with `grep`
26
- - Read files with options for previews, line ranges, and batch operations
27
- - Access file metadata through `stat` and `stat_many`
28
-
29
- All operations are restricted to explicitly approved directories, with no write or modification capabilities.
30
-
31
- ## Features
32
-
33
- ### Directory Operations
13
+ This server enables AI assistants to navigate your filesystem through a set of read-only tools. It provides capabilities to explore directory structures, find files using glob patterns, search file contents with grep, read files (including batch operations), and access file metadata—all restricted to explicitly approved directories.
34
14
 
35
- - List directory contents with `ls`
36
- - Render directory trees with configurable depth using `tree`
37
- - Find files by glob patterns with `find`
15
+ ## Key Features
38
16
 
39
- ### File Operations
17
+ - **Read-Only Security**: No write, delete, or modify permissions.
18
+ - **Allowed Roots**: Access is strictly limited to configured directories.
19
+ - **Directory Exploration**: List contents (`ls`) and visualize structures (`tree`).
20
+ - **File Search**: Find files by name or pattern (`find`) and search content (`grep`).
21
+ - **File Reading**: Read single (`read`) or multiple (`read_many`) files with line-range support.
22
+ - **Metadata**: Retrieve file stats (`stat`, `stat_many`) including size and timestamps.
23
+ - **Large File Handling**: Automatic truncation and pagination for large outputs.
24
+ - **Ignore Support**: Respects `.gitignore` and common ignore patterns by default.
40
25
 
41
- - Read single files with optional line ranges or head preview
42
- - Batch read up to 100 files in a single operation
43
- - Get file metadata (size, timestamps, permissions) with `stat` and `stat_many`
26
+ ## Tech Stack
44
27
 
45
- ### Search
28
+ - **Runtime**: Node.js >= 22.19.8
29
+ - **Language**: TypeScript 5.9.3
30
+ - **MCP SDK**: @modelcontextprotocol/sdk 1.25.3
31
+ - **Libraries**: `zod` (validation), `re2` (safe regex), `ignore` (filtering)
46
32
 
47
- - Content search across files using `grep`
48
- - Respects root `.gitignore` patterns and common ignore directories
49
- - Configurable search timeout and worker threads
33
+ ## Repository Structure
50
34
 
51
- ### Security
52
-
53
- - Read-only operations only
54
- - Access restricted to explicitly approved directories
55
- - Path traversal protection (blocks `..` and symlink escapes)
56
- - RE2-based regex engine prevents ReDoS attacks
57
- - Sensitive files (e.g., `.env`, `.npmrc`) are blocked by default; override via env allowlist
58
-
59
- ## When to Use
35
+ ```text
36
+ src/
37
+ ├── tools/ # Tool implementations (read, find, grep, etc.)
38
+ ├── lib/ # Core logic (filesystem, validation, errors)
39
+ ├── index.ts # CLI entrypoint
40
+ ├── server.ts # MCP server setup and roots management
41
+ ├── tools.ts # Tool registration
42
+ ├── resources.ts # Resource registration
43
+ ├── schemas.ts # Zod schemas for inputs/outputs
44
+ └── config.ts # Shared configuration types
45
+ ```
60
46
 
61
- | Task | Tool |
62
- | ------------------------------- | ----------- |
63
- | Explore project structure | `ls` |
64
- | Render a directory tree | `tree` |
65
- | Find files | `find` |
66
- | Search for code patterns/text | `grep` |
67
- | Read source code | `read` |
68
- | Batch read multiple files | `read_many` |
69
- | Get file metadata (size, dates) | `stat` |
70
- | Batch get file metadata | `stat_many` |
71
- | Check available directories | `roots` |
47
+ ## Requirements
72
48
 
73
- ## Quick Start
49
+ - Node.js >= 22.19.8
74
50
 
75
- ### NPX (Recommended)
51
+ ## Quickstart
76
52
 
77
- **For current directory:**
53
+ Use `npx` to run the server directly.
78
54
 
79
55
  ```bash
80
56
  npx -y @j0hanz/fs-context-mcp@latest --allow-cwd
81
57
  ```
82
58
 
83
- **For specific projects:**
84
-
85
- ```bash
86
- npx -y @j0hanz/fs-context-mcp@latest /path/to/project /path/to/docs
87
- ```
88
-
89
- > **Note:** If your MCP client supports the Roots protocol, you can omit directory arguments—the client will provide them automatically.
90
-
91
- ### VS Code
92
-
93
- Add to `.vscode/mcp.json`:
59
+ ### VS Code Configuration
94
60
 
95
61
  ```json
96
62
  {
97
- "servers": {
63
+ "mcpServers": {
98
64
  "fs-context": {
99
65
  "command": "npx",
100
66
  "args": ["-y", "@j0hanz/fs-context-mcp@latest", "${workspaceFolder}"]
@@ -105,322 +71,181 @@ Add to `.vscode/mcp.json`:
105
71
 
106
72
  ## Installation
107
73
 
108
- ### NPX
109
-
110
- Run without installation:
74
+ ### NPX (Recommended)
111
75
 
112
76
  ```bash
113
- npx -y @j0hanz/fs-context-mcp@latest /path/to/dir1 /path/to/dir2
77
+ npx -y @j0hanz/fs-context-mcp@latest /path/to/directory
114
78
  ```
115
79
 
116
80
  ### Global Installation
117
81
 
118
- For permanent setup across all projects:
119
-
120
82
  ```bash
121
83
  npm install -g @j0hanz/fs-context-mcp
122
- fs-context-mcp /path/to/your/project
84
+ fs-context-mcp /path/to/directory
123
85
  ```
124
86
 
125
87
  ### From Source
126
88
 
127
- For contributors or custom builds:
128
-
129
- ```bash
130
- git clone https://github.com/j0hanz/fs-context-mcp-server.git
131
- cd fs-context-mcp-server
132
- npm install
133
- npm run build
134
- node dist/index.js /path/to/your/project
135
- ```
136
-
137
- ## Directory Access and Resolution
138
-
139
- Access is always restricted to explicitly allowed directories.
140
-
141
- 1. CLI directories are validated and added first (if provided).
142
- 2. `--allow-cwd` optionally adds the current working directory.
143
- 3. MCP Roots from the client are used next:
144
- - If CLI and/or `--allow-cwd` are provided, only roots inside those baseline directories are accepted.
145
- - If no baseline is provided, roots become the allowed directories.
146
- 4. If nothing is configured and the client provides no roots, the server starts with no accessible directories and logs a warning until roots are provided.
147
-
148
- Notes:
149
-
150
- - Windows drive-relative paths like `C:path` are rejected. Use `C:\path` or `C:/path`.
151
- - Reserved Windows device names (e.g., `CON`, `NUL`) are blocked.
152
- - If multiple roots are configured, tools require an explicit `path` to disambiguate.
153
- - When multiple roots are configured, relative paths are rejected; provide an absolute path within the desired root.
154
-
155
- ## Configuration
156
-
157
- All configuration is optional. Sizes in bytes, timeouts in milliseconds.
158
-
159
- ### Environment Variables
160
-
161
- | Variable | Default | Description |
162
- | ---------------------------- | ----------------- | ----------------------------------------------------------------- |
163
- | `MAX_FILE_SIZE` | 10MB | Max file size for read operations (range: 1MB-100MB) |
164
- | `MAX_READ_MANY_TOTAL_SIZE` | 512KB | Max combined size for `read_many` (range: 10KB-100MB) |
165
- | `MAX_SEARCH_SIZE` | 1MB | Max file size for content search (range: 100KB-10MB) |
166
- | `DEFAULT_SEARCH_TIMEOUT` | 30000 | Timeout for search/list operations (range: 100-3600000ms) |
167
- | `FS_CONTEXT_SEARCH_WORKERS` | min(cpu cores, 8) | Search worker threads (range: 0-16; 0 disables) |
168
- | `FS_CONTEXT_ALLOW_SENSITIVE` | false | Allow reading sensitive files (set to `true` to disable denylist) |
169
- | `FS_CONTEXT_DENYLIST` | (empty) | Additional denylist patterns (comma-separated globs) |
170
- | `FS_CONTEXT_ALLOWLIST` | (empty) | Allowlist patterns that override denylist (comma-separated globs) |
171
- | `FS_CONTEXT_TOOL_LOG_ERRORS` | false | Log tool failures to stderr with duration |
172
-
173
- See [CONFIGURATION.md](CONFIGURATION.md) for examples and CLI usage.
174
-
175
- ### Sensitive File Policy
176
-
177
- By default, reads and content searches are blocked for common secret filenames to reduce accidental leakage. The default denylist includes patterns like `.env`, `.npmrc`, `.aws/credentials`, `*.pem`, and `.mcpregistry_*_token`.
178
-
179
- You can customize with:
180
-
181
- - `FS_CONTEXT_ALLOW_SENSITIVE=true` to disable the default denylist.
182
- - `FS_CONTEXT_DENYLIST` to add extra deny patterns (comma-separated globs using `*`).
183
- - `FS_CONTEXT_ALLOWLIST` to allow specific paths even if they match the denylist.
184
-
185
- Sensitive denylist patterns also filter `ls`, `find`, `tree`, and `stat` results by default to avoid revealing secret filenames.
186
-
187
- ## Resources
188
-
189
- This server exposes standard MCP resources to provide static documentation and handle large content efficiently.
190
-
191
- | Resource URI | Description |
192
- | :------------------------- | :---------------------------------------------------------------------------------- |
193
- | `internal://instructions` | Returns the detailed usage instructions (Markdown) for this server. |
194
- | `fs-context://result/{id}` | Access to large file content or search results that were truncated in tool outputs. |
89
+ 1. Clone the repository:
195
90
 
196
- **Note on Large Outputs:**
197
- Tools like `read`, `read_many`, and `grep` automatically cache content exceeding value limits (default 20k chars). In these cases, the tool returns a preview and a `resource_link` (URI) that can be read by the client to retrieve the full content.
91
+ ```bash
92
+ git clone https://github.com/j0hanz/fs-context-mcp-server.git
93
+ cd fs-context-mcp-server
94
+ ```
198
95
 
199
- ## Tools
96
+ 2. Install dependencies:
200
97
 
201
- All tools return both human-readable text and structured JSON. Structured
202
- responses include `ok`, optional `error` (with `code`, `message`, `path`,
203
- `suggestion`), plus the tool-specific fields documented below.
98
+ ```bash
99
+ npm ci
100
+ ```
204
101
 
205
- ### `roots`
102
+ 3. Build the project:
206
103
 
207
- List all directories that this server can access.
104
+ ```bash
105
+ npm run build
106
+ ```
208
107
 
209
- | Parameter | Type | Required | Default | Description |
210
- | --------- | ---- | -------- | ------- | ----------- |
211
- | (none) | - | - | - | - |
108
+ 4. Run the server:
212
109
 
213
- Returns: Allowed directory paths. Structured output includes `ok` and
214
- `directories`.
110
+ ```bash
111
+ node dist/index.js /path/to/directory
112
+ ```
215
113
 
216
- ---
217
-
218
- ### `ls`
219
-
220
- List the immediate contents of a directory (non-recursive). Omit `path` to use
221
- the sole allowed root (when only one root is configured).
222
-
223
- | Parameter | Type | Required | Default | Description |
224
- | --------------- | ------- | -------- | ----------- | ------------------------------------------------------- |
225
- | `path` | string | No | `only root` | Directory path to list (omit when only one root exists) |
226
- | `includeHidden` | boolean | No | `false` | Include hidden files and directories |
227
-
228
- Returns: Entries with name, relativePath, type, size, and modified time.
229
- Structured output includes `ok`, `path`, `entries`, and `totalEntries`.
230
-
231
- ---
232
-
233
- ### `find`
234
-
235
- Search for files using glob patterns. Omit `path` to search from the sole
236
- allowed root (when only one root is configured). By default, `find` excludes common dependency/build directories
237
- (node_modules, dist, .git, etc.); set `includeIgnored: true` to include ignored
238
- directories and disable built-in excludes.
239
-
240
- | Parameter | Type | Required | Default | Description |
241
- | ---------------- | ------- | -------- | ----------- | -------------------------------------------------------------- |
242
- | `path` | string | No | `only root` | Base directory to search from (omit when only one root exists) |
243
- | `pattern` | string | Yes | - | Glob pattern (e.g., `**/*.ts`, `src/**/*.js`) |
244
- | `includeIgnored` | boolean | No | `false` | Include ignored dirs and disable built-in excludes |
245
- | `maxResults` | number | No | `100` | Maximum matches to return (1-10000) |
246
-
247
- Notes:
248
-
249
- - When `includeIgnored=false`, results also respect a root `.gitignore` file (if present under the base `path`).
250
- - Nested `.gitignore` files are not parsed.
251
-
252
- Returns: Matching paths (relative) with size and modified date. Structured
253
- output includes `ok`, `results`, `totalMatches`, and `truncated`.
254
-
255
- ---
256
-
257
- ### `tree`
258
-
259
- Render a directory tree (bounded recursion). Omit `path` to use the sole
260
- allowed root (when only one root is configured).
261
-
262
- - `path` (string, optional; default: `only root`): Base directory to render
263
- - `maxDepth` (number, optional; default: `5`): Maximum recursion depth (0 = just the root)
264
- - `maxEntries` (number, optional; default: `1000`): Maximum number of entries before truncating
265
- - `includeHidden` (boolean, optional; default: `false`): Include hidden files/directories
266
- - `includeIgnored` (boolean, optional; default: `false`): Include ignored dirs and disable built-in + `.gitignore` filtering
267
-
268
- Notes:
269
-
270
- - When `includeIgnored=false`, the tree respects both built-in ignore rules (e.g., `node_modules`, `dist`, `.git`) and a root `.gitignore` file (if present).
271
-
272
- Returns: ASCII tree output plus a structured JSON tree (`ok`, `root`, `tree`,
273
- `ascii`, `truncated`, `totalEntries`).
274
-
275
- ---
276
-
277
- ### `read`
278
-
279
- Read the contents of a text file.
280
-
281
- | Parameter | Type | Required | Default | Description |
282
- | ----------- | ------ | -------- | ------- | ------------------------------ |
283
- | `path` | string | Yes | - | File path to read |
284
- | `head` | number | No | - | Read only first N lines |
285
- | `startLine` | number | No | - | 1-based start line (inclusive) |
286
- | `endLine` | number | No | - | 1-based end line (inclusive) |
114
+ ## Configuration
287
115
 
288
- Notes:
116
+ ### Runtime Modes
289
117
 
290
- - Reads are UTF-8 text only; binary files are rejected.
291
- - Full reads are capped by `MAX_FILE_SIZE` (default 10MB). When `head` is set,
292
- output stops at the line limit or size budget, whichever comes first.
293
- - `head` cannot be combined with `startLine`/`endLine`.
294
- - If the content exceeds a size limit (default 20k chars), the tool returns a `resource_link` instead of inline content.
118
+ This server runs over **stdio** by default.
295
119
 
296
- Returns: File content plus structured metadata (`ok`, `path`, `content`,
297
- `truncated`, `totalLines`, and range metadata when applicable).
120
+ ### CLI Arguments
298
121
 
299
- ---
122
+ | Argument | Description |
123
+ | :------------ | :-------------------------------------------------- |
124
+ | `[paths...]` | List of allowed root directories. |
125
+ | `--allow-cwd` | Add the current working directory to allowed roots. |
300
126
 
301
- ### `read_many`
127
+ ### Environment Variables
302
128
 
303
- Read multiple files in parallel.
129
+ | Variable | Default | Description |
130
+ | :--------------------------- | :---------- | :------------------------------------------------- |
131
+ | `MAX_FILE_SIZE` | 10MB | Max file size for read operations. |
132
+ | `MAX_READ_MANY_TOTAL_SIZE` | 512KB | Max combined size for `read_many`. |
133
+ | `MAX_SEARCH_SIZE` | 1MB | Max file size for `grep`. |
134
+ | `DEFAULT_SEARCH_TIMEOUT` | 30000 | Timeout (ms) for search/list operations. |
135
+ | `FS_CONTEXT_SEARCH_WORKERS` | min(cpu, 8) | Number of worker threads for search. |
136
+ | `FS_CONTEXT_ALLOW_SENSITIVE` | false | Allow reading sensitive files (disables denylist). |
137
+ | `FS_CONTEXT_DENYLIST` | (empty) | Additional comma-separated glob patterns to block. |
138
+ | `FS_CONTEXT_ALLOWLIST` | (empty) | Comma-separated globs to allow despite denylist. |
139
+ | `FS_CONTEXT_TOOL_LOG_ERRORS` | false | Log tool failures to stderr. |
304
140
 
305
- | Parameter | Type | Required | Default | Description |
306
- | ----------- | -------- | -------- | ------- | --------------------------------------- |
307
- | `paths` | string[] | Yes | - | Array of file paths (max 100) |
308
- | `head` | number | No | - | Read only first N lines of each file |
309
- | `startLine` | number | No | - | 1-based start line (inclusive) per file |
310
- | `endLine` | number | No | - | 1-based end line (inclusive) per file |
141
+ ## MCP Surface
311
142
 
312
- Notes:
143
+ ### Tools
313
144
 
314
- - Reads files as UTF-8 text; binary files are not filtered. Max size per file
315
- is capped by `MAX_FILE_SIZE` (default 10MB).
316
- - Total read budget across all files is capped by `MAX_READ_MANY_TOTAL_SIZE`.
317
- - No binary detection is performed; use `read` for single-file safety checks.
318
- - `head` cannot be combined with `startLine`/`endLine`.
319
- - If any file content exceeds the inline limit, it is returned as a `resource_link`.
145
+ #### `roots`
320
146
 
321
- Returns: Per-file content or error, plus structured summary (`total`,
322
- `succeeded`, `failed`).
147
+ List the workspace roots this server can access.
323
148
 
324
- ---
149
+ - **Returns**: List of allowed directory paths.
325
150
 
326
- ### `stat`
151
+ #### `ls`
327
152
 
328
- Get detailed metadata about a file or directory.
153
+ List the immediate contents of a directory.
329
154
 
330
- | Parameter | Type | Required | Default | Description |
331
- | --------- | ------ | -------- | ------- | ------------------------- |
332
- | `path` | string | Yes | - | Path to file or directory |
155
+ | Parameter | Type | Required | Default | Description |
156
+ | :--------------- | :------ | :------- | :------ | :----------------------------------------------- |
157
+ | `path` | string | No | (root) | Directory path to list. |
158
+ | `includeHidden` | boolean | No | false | Include hidden files. |
159
+ | `includeIgnored` | boolean | No | false | Include ignored directories (node_modules, etc). |
333
160
 
334
- Returns: name, path, type, size, timestamps (created/modified/accessed),
335
- permissions, hidden status, MIME type (for files), and symlink target (if
336
- applicable). Structured results may include `tokenEstimate` (rule of thumb:
337
- ceil(size/4)).
161
+ #### `find`
338
162
 
339
- ---
163
+ Find files by glob pattern.
340
164
 
341
- ### `stat_many`
165
+ | Parameter | Type | Required | Default | Description |
166
+ | :--------------- | :------ | :------- | :------ | :------------------------------ |
167
+ | `pattern` | string | Yes | - | Glob pattern (e.g., `**/*.ts`). |
168
+ | `path` | string | No | (root) | Base directory to search from. |
169
+ | `includeIgnored` | boolean | No | false | Include ignored directories. |
170
+ | `maxResults` | number | No | 100 | Maximum matches to return. |
342
171
 
343
- Get metadata for multiple files/directories in parallel.
172
+ #### `tree`
344
173
 
345
- | Parameter | Type | Required | Default | Description |
346
- | --------- | -------- | -------- | ------- | --------------------------------- |
347
- | `paths` | string[] | Yes | - | Array of paths to query (max 100) |
174
+ Render a directory tree.
348
175
 
349
- Returns: Array of file info with individual success/error status, plus summary
350
- (total, succeeded, failed).
176
+ | Parameter | Type | Required | Default | Description |
177
+ | :--------------- | :------ | :------- | :------ | :----------------------------- |
178
+ | `path` | string | No | (root) | Base directory to render. |
179
+ | `maxDepth` | number | No | 5 | Maximum recursion depth. |
180
+ | `maxEntries` | number | No | 1000 | Max entries before truncating. |
181
+ | `includeHidden` | boolean | No | false | Include hidden files. |
182
+ | `includeIgnored` | boolean | No | false | Include ignored directories. |
351
183
 
352
- ---
184
+ #### `read`
353
185
 
354
- ### `grep`
186
+ Read the text contents of a file.
355
187
 
356
- Search for text content within files.
188
+ | Parameter | Type | Required | Default | Description |
189
+ | :---------- | :----- | :------- | :------ | :----------------------- |
190
+ | `path` | string | Yes | - | Path to the file. |
191
+ | `head` | number | No | - | Read only first N lines. |
192
+ | `startLine` | number | No | - | 1-based start line. |
193
+ | `endLine` | number | No | - | 1-based end line. |
357
194
 
358
- - Omit `path` to search from the first allowed root.
359
- - Pass a file path in `path` to search only that file.
195
+ #### `read_many`
360
196
 
361
- `pattern` is treated as a literal string and matched case-insensitively.
197
+ Read multiple text files in a single request.
362
198
 
363
- | Parameter | Type | Required | Default | Description |
364
- | --------------- | ------- | -------- | ----------- | ------------------------------------------------------------------------- |
365
- | `path` | string | No | `only root` | Base directory or file path to search in (omit when only one root exists) |
366
- | `pattern` | string | Yes | - | Text pattern to search for |
367
- | `includeHidden` | boolean | No | `false` | Include hidden files and directories |
199
+ | Parameter | Type | Required | Default | Description |
200
+ | :---------- | :------- | :------- | :------ | :------------------------------------- |
201
+ | `paths` | string[] | Yes | - | Array of file paths to read (max 100). |
202
+ | `head` | number | No | - | Read only first N lines of each file. |
203
+ | `startLine` | number | No | - | 1-based start line per file. |
204
+ | `endLine` | number | No | - | 1-based end line per file. |
368
205
 
369
- Example (search a single file):
206
+ #### `stat`
370
207
 
371
- ```json
372
- { "path": "src/transform.ts", "pattern": "TODO" }
373
- ```
208
+ Get metadata for a file or directory.
374
209
 
375
- Returns: Matching lines with file path, line number, content, and optional
376
- context.
210
+ | Parameter | Type | Required | Default | Description |
211
+ | :-------- | :----- | :------- | :------ | :------------------------- |
212
+ | `path` | string | Yes | - | Path to file or directory. |
377
213
 
378
- Notes:
214
+ #### `stat_many`
379
215
 
380
- - `grep` skips binary files by default.
381
- - Very large files are skipped based on `MAX_SEARCH_SIZE` (default 1MB).
382
- “No matches” is not proof the text is absent from skipped files.
216
+ Get metadata for multiple files/directories.
383
217
 
384
- Note: the `grep` tool currently exposes only `path`, `pattern`, and
385
- `includeHidden`. Context fields are omitted unless enabled internally.
218
+ | Parameter | Type | Required | Default | Description |
219
+ | :-------- | :------- | :------- | :------ | :----------------------- |
220
+ | `paths` | string[] | Yes | - | Array of paths to query. |
386
221
 
387
- Structured output includes `ok`, `matches`, `totalMatches`, and `truncated`.
388
- Matched line content is trimmed to 200 characters.
222
+ #### `grep`
389
223
 
390
- ---
224
+ Search for text within file contents.
391
225
 
392
- Built-in exclude list: `grep` skips common dependency/build/output directories
393
- and files: `node_modules`, `dist`, `build`, `coverage`, `.git`, `.vscode`,
394
- `.idea`, `.DS_Store`, `.next`, `.nuxt`, `.output`, `.svelte-kit`, `.cache`,
395
- `.yarn`, `jspm_packages`, `bower_components`, `out`, `tmp`, `.temp`,
396
- `npm-debug.log`, `yarn-debug.log`, `yarn-error.log`, `Thumbs.db`.
226
+ | Parameter | Type | Required | Default | Description |
227
+ | :-------------- | :------ | :------- | :------ | :-------------------------------- |
228
+ | `pattern` | string | Yes | - | Text pattern to search for. |
229
+ | `path` | string | No | (root) | Base directory or file to search. |
230
+ | `includeHidden` | boolean | No | false | Include hidden files. |
397
231
 
398
- ## Error Codes
232
+ ### Resources
399
233
 
400
- | Code | Meaning |
401
- | ----------------------- | ----------------------------- |
402
- | `E_ACCESS_DENIED` | Path outside allowed roots |
403
- | `E_NOT_FOUND` | Path does not exist |
404
- | `E_NOT_FILE` | Expected file, got directory |
405
- | `E_NOT_DIRECTORY` | Expected directory, got file |
406
- | `E_TOO_LARGE` | File exceeds size limits |
407
- | `E_TIMEOUT` | Operation timed out |
408
- | `E_INVALID_PATTERN` | Invalid glob/regex pattern |
409
- | `E_INVALID_INPUT` | Invalid argument(s) |
410
- | `E_PERMISSION_DENIED` | OS-level permission denied |
411
- | `E_SYMLINK_NOT_ALLOWED` | Symlink escapes allowed roots |
412
- | `E_UNKNOWN` | Unexpected error |
234
+ | Pattern | Description |
235
+ | :------------------------- | :-------------------------------------- |
236
+ | `internal://instructions` | Usage guidance and server instructions. |
237
+ | `fs-context://result/{id}` | Access to cached large tool outputs. |
413
238
 
414
- ## Client Configuration
239
+ ## Client Configuration Examples
415
240
 
416
241
  <details>
417
242
  <summary><b>VS Code</b></summary>
418
243
 
419
- Add to `.vscode/mcp.json` (recommended) or `.vscode/settings.json`:
244
+ Add to `.vscode/mcp.json`:
420
245
 
421
246
  ```json
422
247
  {
423
- "servers": {
248
+ "mcpServers": {
424
249
  "fs-context": {
425
250
  "command": "npx",
426
251
  "args": ["-y", "@j0hanz/fs-context-mcp@latest", "${workspaceFolder}"]
@@ -434,22 +259,23 @@ Add to `.vscode/mcp.json` (recommended) or `.vscode/settings.json`:
434
259
  <details>
435
260
  <summary><b>Claude Desktop</b></summary>
436
261
 
437
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
438
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
262
+ Add to `claude_desktop_config.json`:
439
263
 
440
264
  ```json
441
265
  {
442
266
  "mcpServers": {
443
267
  "fs-context": {
444
268
  "command": "npx",
445
- "args": ["-y", "@j0hanz/fs-context-mcp@latest", "C:\\path\\to\\project"]
269
+ "args": [
270
+ "-y",
271
+ "@j0hanz/fs-context-mcp@latest",
272
+ "/absolute/path/to/project"
273
+ ]
446
274
  }
447
275
  }
448
276
  }
449
277
  ```
450
278
 
451
- If your client supports MCP Roots, you can omit the path. Otherwise, pass a path or `--allow-cwd`.
452
-
453
279
  </details>
454
280
 
455
281
  <details>
@@ -470,21 +296,6 @@ Add to Cursor's MCP configuration:
470
296
 
471
297
  </details>
472
298
 
473
- <details>
474
- <summary><b>Codex</b></summary>
475
-
476
- Add to `~/.codex/config.toml`:
477
-
478
- ```toml
479
- [mcp_servers.fs-context]
480
- command = "npx"
481
- args = ["-y", "@j0hanz/fs-context-mcp@latest", "/path/to/your/project"]
482
- ```
483
-
484
- If your client supports MCP Roots, you can omit the path. Otherwise, pass a path or `--allow-cwd`.
485
-
486
- </details>
487
-
488
299
  <details>
489
300
  <summary><b>Windsurf</b></summary>
490
301
 
@@ -503,86 +314,29 @@ Add to Windsurf's MCP configuration:
503
314
 
504
315
  </details>
505
316
 
506
- ## Security Details
507
-
508
- This server implements multiple layers of security:
509
-
510
- | Protection | Description |
511
- | ------------------------- | ------------------------------------------------------------- |
512
- | Access control | Only explicitly allowed directories are accessible |
513
- | Path validation | All paths are validated before any filesystem operation |
514
- | Symlink protection | Symlinks that resolve outside allowed directories are blocked |
515
- | Path traversal prevention | Attempts to escape via `..` are detected and blocked |
516
- | Read-only operations | No writes, deletes, or modifications |
517
- | Safe regex | Regex validation with RE2 prevents ReDoS |
518
- | Size limits | Configurable limits prevent resource exhaustion |
519
-
520
- ## Development
521
-
522
- ### Prerequisites
317
+ ## Security
523
318
 
524
- - Node.js >= 20.0.0
525
- - npm
319
+ - **Read-Only**: This server is designed to be read-only. It provides no tools for writing or modifying files.
320
+ - **Path Validation**: All file access is validated against the allowed root directories.
321
+ - **Path Traversal**: Attempts to access files outside allowed roots using `..` are blocked.
322
+ - **Symlinks**: Symlinks resolving outside allowed roots are blocked.
323
+ - **Sensitive Files**: Common sensitive files (e.g., `.env`, `.ssh/id_rsa`) are denied by default unless explicitly allowed via configuration.
324
+ - **Stdio**: The server communicates via stdio. Ensure your client does not pipe untrusted data into the server's input.
526
325
 
527
- ### Scripts
326
+ ## Development Workflow
528
327
 
529
- | Command | Description |
530
- | ----------------------- | ------------------------------------------------------------------ |
531
- | `npm run build` | Compile TypeScript to JavaScript |
532
- | `npm run dev` | Watch mode with tsx |
533
- | `npm run start` | Run compiled server |
534
- | `npm run test` | Run tests (node --test with tsx/esm) |
535
- | `npm run test:watch` | Run tests in watch mode (node --test --watch) |
536
- | `npm run test:coverage` | Run tests with coverage (node --test --experimental-test-coverage) |
537
- | `npm run test:node` | Run node-tests (isolated checks) |
538
- | `npm run lint` | Run ESLint |
539
- | `npm run format` | Format code with Prettier |
540
- | `npm run type-check` | TypeScript type checking |
541
- | `npm run inspector` | Test with MCP Inspector |
328
+ 1. **Install dependencies**: `npm ci`
329
+ 2. **Run in dev mode**: `npm run dev` (watches for changes)
330
+ 3. **Build**: `npm run build`
331
+ 4. **Test**: `npm test`
332
+ 5. **Lint**: `npm run lint`
542
333
 
543
- ### Project Structure
334
+ ## Troubleshooting
544
335
 
545
- ```text
546
- src/
547
- index.ts # CLI entry point
548
- server.ts # MCP server wiring and roots handling
549
- tools.ts # MCP tool registration + response helpers
550
- schemas.ts # Zod input/output schemas
551
- config.ts # Shared types and formatting helpers
552
- instructions.md # Tool usage instructions (bundled in dist)
553
- lib/ # Core logic and filesystem operations
554
- __tests__/ # node:test + tsx tests
555
- node-tests/ # Additional Node.js checks
556
- docs/ # Static docs assets
557
- dist/ # Build output (generated)
558
- ```
336
+ - **Access Denied**: Ensure the directory is included in the CLI arguments or client roots configuration.
337
+ - **File Too Large**: Large files are truncated. Use the `head` parameter or `startLine`/`endLine` to read specific sections, or follow the resource URI provided in the tool output.
338
+ - **Timeout**: Complex searches (`grep` or `find`) may timeout on large codebases. Try narrowing the search path.
559
339
 
560
- ## Troubleshooting
340
+ ## License
561
341
 
562
- | Issue | Solution |
563
- | ------------------------ | ---------------------------------------------------------------------------- |
564
- | "Access denied" error | Ensure the path is within an allowed directory. Use `roots` to check. |
565
- | "Path does not exist" | Verify the path exists. Use `ls` to explore available files. |
566
- | "File too large" | Use `head` or increase `MAX_FILE_SIZE`. |
567
- | "Binary file" warning | `read` only supports UTF-8 text and rejects binary files. |
568
- | No directories available | Pass explicit paths, use `--allow-cwd`, or ensure the client provides Roots. |
569
- | Symlink blocked | Symlinks that resolve outside allowed directories are blocked. |
570
- | Invalid pattern | Simplify the pattern (note: `grep` treats `pattern` as literal text). |
571
-
572
- ## Contributing
573
-
574
- Contributions are welcome! Please follow these steps:
575
-
576
- 1. Fork the repository
577
- 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
578
- 3. Run format, lint, type-check, build, and tests (`npm run format && npm run lint && npm run type-check && npm run build && npm run test`)
579
- 4. Commit your changes (`git commit -m 'Add amazing feature'`)
580
- 5. Push to the branch (`git push origin feature/amazing-feature`)
581
- 6. Open a Pull Request
582
-
583
- ### Code Style
584
-
585
- - Use TypeScript with strict mode
586
- - Follow ESLint configuration
587
- - Use Prettier for formatting
588
- - Write tests for new features
342
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.