@j0hanz/filesystem-context-mcp 1.0.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.
- package/README.md +369 -0
- package/dist/__tests__/errors.test.d.ts +2 -0
- package/dist/__tests__/errors.test.d.ts.map +1 -0
- package/dist/__tests__/errors.test.js +88 -0
- package/dist/__tests__/errors.test.js.map +1 -0
- package/dist/__tests__/file-operations.test.d.ts +2 -0
- package/dist/__tests__/file-operations.test.d.ts.map +1 -0
- package/dist/__tests__/file-operations.test.js +230 -0
- package/dist/__tests__/file-operations.test.js.map +1 -0
- package/dist/__tests__/lib/errors.test.d.ts +2 -0
- package/dist/__tests__/lib/errors.test.d.ts.map +1 -0
- package/dist/__tests__/lib/errors.test.js +156 -0
- package/dist/__tests__/lib/errors.test.js.map +1 -0
- package/dist/__tests__/lib/file-operations.test.d.ts +2 -0
- package/dist/__tests__/lib/file-operations.test.d.ts.map +1 -0
- package/dist/__tests__/lib/file-operations.test.js +417 -0
- package/dist/__tests__/lib/file-operations.test.js.map +1 -0
- package/dist/__tests__/lib/fs-helpers.test.d.ts +2 -0
- package/dist/__tests__/lib/fs-helpers.test.d.ts.map +1 -0
- package/dist/__tests__/lib/fs-helpers.test.js +183 -0
- package/dist/__tests__/lib/fs-helpers.test.js.map +1 -0
- package/dist/__tests__/lib/path-validation.test.d.ts +2 -0
- package/dist/__tests__/lib/path-validation.test.d.ts.map +1 -0
- package/dist/__tests__/lib/path-validation.test.js +103 -0
- package/dist/__tests__/lib/path-validation.test.js.map +1 -0
- package/dist/__tests__/path-validation.test.d.ts +2 -0
- package/dist/__tests__/path-validation.test.d.ts.map +1 -0
- package/dist/__tests__/path-validation.test.js +92 -0
- package/dist/__tests__/path-validation.test.js.map +1 -0
- package/dist/config/types.d.ts +222 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +23 -0
- package/dist/config/types.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +50 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/constants.d.ts +16 -0
- package/dist/lib/constants.d.ts.map +1 -0
- package/dist/lib/constants.js +335 -0
- package/dist/lib/constants.js.map +1 -0
- package/dist/lib/errors.d.ts +33 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +205 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/file-operations.d.ts +69 -0
- package/dist/lib/file-operations.d.ts.map +1 -0
- package/dist/lib/file-operations.js +1003 -0
- package/dist/lib/file-operations.js.map +1 -0
- package/dist/lib/formatters.d.ts +30 -0
- package/dist/lib/formatters.d.ts.map +1 -0
- package/dist/lib/formatters.js +204 -0
- package/dist/lib/formatters.js.map +1 -0
- package/dist/lib/fs-helpers.d.ts +29 -0
- package/dist/lib/fs-helpers.d.ts.map +1 -0
- package/dist/lib/fs-helpers.js +295 -0
- package/dist/lib/fs-helpers.js.map +1 -0
- package/dist/lib/path-utils.d.ts +12 -0
- package/dist/lib/path-utils.d.ts.map +1 -0
- package/dist/lib/path-utils.js +34 -0
- package/dist/lib/path-utils.js.map +1 -0
- package/dist/lib/path-validation.d.ts +31 -0
- package/dist/lib/path-validation.d.ts.map +1 -0
- package/dist/lib/path-validation.js +181 -0
- package/dist/lib/path-validation.js.map +1 -0
- package/dist/lib/roots-utils.d.ts +7 -0
- package/dist/lib/roots-utils.d.ts.map +1 -0
- package/dist/lib/roots-utils.js +39 -0
- package/dist/lib/roots-utils.js.map +1 -0
- package/dist/lib/types.d.ts +6 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +2 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/schemas/common.d.ts +41 -0
- package/dist/schemas/common.d.ts.map +1 -0
- package/dist/schemas/common.js +21 -0
- package/dist/schemas/common.js.map +1 -0
- package/dist/schemas/index.d.ts +3 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +5 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/inputs.d.ts +72 -0
- package/dist/schemas/inputs.d.ts.map +1 -0
- package/dist/schemas/inputs.js +326 -0
- package/dist/schemas/inputs.js.map +1 -0
- package/dist/schemas/outputs.d.ts +476 -0
- package/dist/schemas/outputs.d.ts.map +1 -0
- package/dist/schemas/outputs.js +181 -0
- package/dist/schemas/outputs.js.map +1 -0
- package/dist/server.d.ts +5 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +83 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/analyze-directory.d.ts +3 -0
- package/dist/tools/analyze-directory.d.ts.map +1 -0
- package/dist/tools/analyze-directory.js +57 -0
- package/dist/tools/analyze-directory.js.map +1 -0
- package/dist/tools/directory-tree.d.ts +3 -0
- package/dist/tools/directory-tree.d.ts.map +1 -0
- package/dist/tools/directory-tree.js +47 -0
- package/dist/tools/directory-tree.js.map +1 -0
- package/dist/tools/get-file-info.d.ts +3 -0
- package/dist/tools/get-file-info.d.ts.map +1 -0
- package/dist/tools/get-file-info.js +44 -0
- package/dist/tools/get-file-info.js.map +1 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +23 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/list-allowed-dirs.d.ts +3 -0
- package/dist/tools/list-allowed-dirs.d.ts.map +1 -0
- package/dist/tools/list-allowed-dirs.js +23 -0
- package/dist/tools/list-allowed-dirs.js.map +1 -0
- package/dist/tools/list-directory.d.ts +3 -0
- package/dist/tools/list-directory.d.ts.map +1 -0
- package/dist/tools/list-directory.js +60 -0
- package/dist/tools/list-directory.js.map +1 -0
- package/dist/tools/read-file.d.ts +3 -0
- package/dist/tools/read-file.d.ts.map +1 -0
- package/dist/tools/read-file.js +55 -0
- package/dist/tools/read-file.js.map +1 -0
- package/dist/tools/read-media-file.d.ts +3 -0
- package/dist/tools/read-media-file.d.ts.map +1 -0
- package/dist/tools/read-media-file.js +48 -0
- package/dist/tools/read-media-file.js.map +1 -0
- package/dist/tools/read-multiple-files.d.ts +3 -0
- package/dist/tools/read-multiple-files.d.ts.map +1 -0
- package/dist/tools/read-multiple-files.js +53 -0
- package/dist/tools/read-multiple-files.js.map +1 -0
- package/dist/tools/search-content.d.ts +3 -0
- package/dist/tools/search-content.d.ts.map +1 -0
- package/dist/tools/search-content.js +67 -0
- package/dist/tools/search-content.js.map +1 -0
- package/dist/tools/search-files.d.ts +3 -0
- package/dist/tools/search-files.d.ts.map +1 -0
- package/dist/tools/search-files.js +51 -0
- package/dist/tools/search-files.js.map +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/response-helpers.d.ts +22 -0
- package/dist/utils/response-helpers.d.ts.map +1 -0
- package/dist/utils/response-helpers.js +24 -0
- package/dist/utils/response-helpers.js.map +1 -0
- package/package.json +61 -0
package/README.md
ADDED
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
# Filesystem Context MCP Server
|
|
2
|
+
|
|
3
|
+
A secure Model Context Protocol (MCP) server for filesystem scanning, searching, and analysis. Built with TypeScript and the official MCP SDK.
|
|
4
|
+
|
|
5
|
+
## Security Features
|
|
6
|
+
|
|
7
|
+
- **Path Validation**: All file operations are restricted to explicitly allowed directories
|
|
8
|
+
- **Symlink Attack Prevention**: Symlinks are resolved before validation to prevent escaping allowed directories
|
|
9
|
+
- **Path Traversal Protection**: Attempts to access paths outside allowed directories are blocked
|
|
10
|
+
- **Read-Only Operations**: All tools are marked with `readOnlyHint` annotation
|
|
11
|
+
|
|
12
|
+
## Features
|
|
13
|
+
|
|
14
|
+
This server provides the following tools for filesystem operations:
|
|
15
|
+
|
|
16
|
+
| Tool | Description |
|
|
17
|
+
| -------------------------- | ------------------------------------------------------------ |
|
|
18
|
+
| `list_allowed_directories` | List directories this server is allowed to access |
|
|
19
|
+
| `list_directory` | List files and directories with optional recursive traversal |
|
|
20
|
+
| `search_files` | Search for files using glob patterns |
|
|
21
|
+
| `read_file` | Read file contents with optional line range |
|
|
22
|
+
| `read_multiple_files` | Read multiple files in parallel efficiently |
|
|
23
|
+
| `get_file_info` | Get detailed file/directory metadata |
|
|
24
|
+
| `search_content` | Search for text within files using regex patterns |
|
|
25
|
+
| `analyze_directory` | Analyze directory structure and get statistics |
|
|
26
|
+
| `directory_tree` | Get JSON tree structure of a directory |
|
|
27
|
+
| `read_media_file` | Read binary/media files as base64-encoded data |
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Clone the repository
|
|
33
|
+
git clone <repository-url>
|
|
34
|
+
cd filesystem-context-mcp
|
|
35
|
+
|
|
36
|
+
# Install dependencies
|
|
37
|
+
npm install
|
|
38
|
+
|
|
39
|
+
# Build the project
|
|
40
|
+
npm run build
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
### Running the Server
|
|
46
|
+
|
|
47
|
+
**Important**: You must specify at least one allowed directory when starting the server:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# Production mode - specify allowed directories
|
|
51
|
+
node dist/index.js /path/to/allowed/dir1 /path/to/allowed/dir2
|
|
52
|
+
|
|
53
|
+
# Development mode with tsx
|
|
54
|
+
npx tsx src/index.ts /path/to/allowed/dir
|
|
55
|
+
|
|
56
|
+
# Windows example
|
|
57
|
+
node dist/index.js C:\Users\Projects C:\Users\Documents
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Testing with MCP Inspector
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npm run inspector
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Then connect to the server via stdio, providing allowed directories as arguments.
|
|
67
|
+
|
|
68
|
+
### Configuration with MCP Clients
|
|
69
|
+
|
|
70
|
+
#### Claude Desktop
|
|
71
|
+
|
|
72
|
+
Add to your Claude Desktop config (`%APPDATA%\Claude\claude_desktop_config.json` on Windows):
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"mcpServers": {
|
|
77
|
+
"filesystem-context": {
|
|
78
|
+
"command": "node",
|
|
79
|
+
"args": [
|
|
80
|
+
"C:\\path\\to\\filesystem-context-mcp\\dist\\index.js",
|
|
81
|
+
"C:\\Users\\Projects",
|
|
82
|
+
"C:\\Users\\Documents"
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
#### VS Code with Copilot
|
|
90
|
+
|
|
91
|
+
Add to your VS Code settings or `.vscode/mcp.json`:
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"mcp": {
|
|
96
|
+
"servers": {
|
|
97
|
+
"filesystem-context": {
|
|
98
|
+
"command": "node",
|
|
99
|
+
"args": ["${workspaceFolder}/dist/index.js", "${workspaceFolder}"]
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Tool Documentation
|
|
107
|
+
|
|
108
|
+
All tools return both a human-readable `content` text block and a machine-friendly `structuredContent` payload (with `outputSchema` declared in the server).
|
|
109
|
+
|
|
110
|
+
### list_directory
|
|
111
|
+
|
|
112
|
+
List all files and directories in a given path.
|
|
113
|
+
|
|
114
|
+
**Parameters:**
|
|
115
|
+
|
|
116
|
+
- `path` (string, required): The directory path to list
|
|
117
|
+
- `recursive` (boolean, default: false): Whether to list recursively
|
|
118
|
+
- `includeHidden` (boolean, default: false): Include hidden files (dotfiles)
|
|
119
|
+
- `maxDepth` (number, default: 10): Maximum depth for recursive listing
|
|
120
|
+
- `maxEntries` (number, optional): Maximum number of entries to return (prevents huge responses)
|
|
121
|
+
|
|
122
|
+
**Example:**
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"path": "C:\\Users\\Projects",
|
|
127
|
+
"recursive": true,
|
|
128
|
+
"maxDepth": 2
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### search_files
|
|
133
|
+
|
|
134
|
+
Search for files and directories matching a glob pattern.
|
|
135
|
+
|
|
136
|
+
**Parameters:**
|
|
137
|
+
|
|
138
|
+
- `path` (string, required): Base directory to search from
|
|
139
|
+
- `pattern` (string, required): Glob pattern to match (e.g. `**/*.ts`)
|
|
140
|
+
- `excludePatterns` (string[], optional): Glob patterns to exclude
|
|
141
|
+
- `maxResults` (number, optional): Maximum number of matches to return (prevents huge responses)
|
|
142
|
+
|
|
143
|
+
**Example:**
|
|
144
|
+
|
|
145
|
+
```json
|
|
146
|
+
{
|
|
147
|
+
"path": "./src",
|
|
148
|
+
"pattern": "**/*.ts",
|
|
149
|
+
"excludePatterns": ["**/*.test.ts"]
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### read_file
|
|
154
|
+
|
|
155
|
+
Read the contents of a file (optionally a line range).
|
|
156
|
+
|
|
157
|
+
**Parameters:**
|
|
158
|
+
|
|
159
|
+
- `path` (string, required): Path to the file
|
|
160
|
+
- `encoding` (string, default: "utf-8"): File encoding
|
|
161
|
+
- `maxSize` (number, default: 10485760): Maximum file size in bytes (default 10MB)
|
|
162
|
+
- `lineStart` (number, optional): Start line (1-based)
|
|
163
|
+
- `lineEnd` (number, optional): End line (inclusive)
|
|
164
|
+
|
|
165
|
+
**Example:**
|
|
166
|
+
|
|
167
|
+
```json
|
|
168
|
+
{
|
|
169
|
+
"path": "./src/index.ts",
|
|
170
|
+
"lineStart": 1,
|
|
171
|
+
"lineEnd": 50
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### get_file_info
|
|
176
|
+
|
|
177
|
+
Get detailed information about a file or directory.
|
|
178
|
+
|
|
179
|
+
**Parameters:**
|
|
180
|
+
|
|
181
|
+
- `path` (string, required): Path to the file or directory
|
|
182
|
+
|
|
183
|
+
**Returns:** File metadata including size, timestamps, permissions, and type.
|
|
184
|
+
|
|
185
|
+
### search_content
|
|
186
|
+
|
|
187
|
+
Search for text content within files using a regular expression.
|
|
188
|
+
|
|
189
|
+
**Parameters:**
|
|
190
|
+
|
|
191
|
+
- `path` (string, required): Base directory to search in
|
|
192
|
+
- `pattern` (string, required): Regular expression pattern
|
|
193
|
+
- `filePattern` (string, default: "\*_/_"): Glob pattern to filter files
|
|
194
|
+
- `excludePatterns` (string[], optional): Glob patterns to exclude (e.g. `node_modules/**`)
|
|
195
|
+
- `caseSensitive` (boolean, default: false): Case-sensitive search
|
|
196
|
+
- `maxResults` (number, default: 100): Maximum number of matches to return
|
|
197
|
+
- `maxFileSize` (number, optional): Maximum file size in bytes to scan (default 1MB)
|
|
198
|
+
- `maxFilesScanned` (number, optional): Maximum number of files to scan before stopping
|
|
199
|
+
- `timeoutMs` (number, optional): Timeout in milliseconds for the search operation
|
|
200
|
+
- `skipBinary` (boolean, default: true): Skip likely-binary files
|
|
201
|
+
|
|
202
|
+
**Example:**
|
|
203
|
+
|
|
204
|
+
```json
|
|
205
|
+
{
|
|
206
|
+
"path": "./src",
|
|
207
|
+
"pattern": "TODO:",
|
|
208
|
+
"filePattern": "**/*.ts",
|
|
209
|
+
"maxResults": 50
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### analyze_directory
|
|
214
|
+
|
|
215
|
+
Analyze a directory structure and compute summary statistics.
|
|
216
|
+
|
|
217
|
+
**Parameters:**
|
|
218
|
+
|
|
219
|
+
- `path` (string, required): Directory path to analyze
|
|
220
|
+
- `maxDepth` (number, default: 10): Maximum depth to traverse
|
|
221
|
+
- `topN` (number, default: 10): Number of “top” items to return (largest/recent)
|
|
222
|
+
|
|
223
|
+
**Returns:** Statistics including file counts by extension, total size, largest files, and recently modified files.
|
|
224
|
+
|
|
225
|
+
### list_allowed_directories
|
|
226
|
+
|
|
227
|
+
List all directories that this server is allowed to access.
|
|
228
|
+
|
|
229
|
+
**Parameters:** None
|
|
230
|
+
|
|
231
|
+
**Returns:** Array of allowed directory paths. Use this to understand the scope of available file operations.
|
|
232
|
+
|
|
233
|
+
### read_multiple_files
|
|
234
|
+
|
|
235
|
+
Read the contents of multiple files in parallel. More efficient than reading files one by one.
|
|
236
|
+
|
|
237
|
+
**Parameters:**
|
|
238
|
+
|
|
239
|
+
- `paths` (string[], required): Array of file paths to read
|
|
240
|
+
- `encoding` (string, default: "utf-8"): File encoding
|
|
241
|
+
- `maxSize` (number, default: 10485760): Maximum file size in bytes per file (default 10MB)
|
|
242
|
+
|
|
243
|
+
**Example:**
|
|
244
|
+
|
|
245
|
+
```json
|
|
246
|
+
{
|
|
247
|
+
"paths": ["./src/index.ts", "./src/server.ts", "./package.json"],
|
|
248
|
+
"encoding": "utf-8"
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**Returns:** Array of results, each containing the file path and either its content or an error message. Individual file errors do not fail the entire operation.
|
|
253
|
+
|
|
254
|
+
### directory_tree
|
|
255
|
+
|
|
256
|
+
Get a JSON tree structure of a directory. More efficient for AI parsing than flat file lists.
|
|
257
|
+
|
|
258
|
+
**Parameters:**
|
|
259
|
+
|
|
260
|
+
- `path` (string, required): Directory path to build tree from
|
|
261
|
+
- `maxDepth` (number, default: 5): Maximum depth to traverse
|
|
262
|
+
- `excludePatterns` (string[], optional): Glob patterns to exclude (e.g., `node_modules`, `*.log`)
|
|
263
|
+
- `includeHidden` (boolean, default: false): Include hidden files and directories
|
|
264
|
+
- `includeSize` (boolean, default: false): Include file sizes in the tree
|
|
265
|
+
|
|
266
|
+
**Example:**
|
|
267
|
+
|
|
268
|
+
```json
|
|
269
|
+
{
|
|
270
|
+
"path": "./src",
|
|
271
|
+
"maxDepth": 3,
|
|
272
|
+
"excludePatterns": ["__tests__"],
|
|
273
|
+
"includeSize": true
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
**Returns:** Nested tree structure with files and directories, useful for understanding project structure.
|
|
278
|
+
|
|
279
|
+
### read_media_file
|
|
280
|
+
|
|
281
|
+
Read a binary/media file (image, audio, video, etc.) and return it as base64-encoded data.
|
|
282
|
+
|
|
283
|
+
**Parameters:**
|
|
284
|
+
|
|
285
|
+
- `path` (string, required): Path to the media file
|
|
286
|
+
- `maxSize` (number, default: 52428800): Maximum file size in bytes (default 50MB)
|
|
287
|
+
|
|
288
|
+
**Example:**
|
|
289
|
+
|
|
290
|
+
```json
|
|
291
|
+
{
|
|
292
|
+
"path": "./assets/logo.png"
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**Returns:** Object containing the file path, MIME type, size in bytes, and base64-encoded data.
|
|
297
|
+
|
|
298
|
+
## Development
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
# Run in development mode with hot reload
|
|
302
|
+
npm run dev
|
|
303
|
+
|
|
304
|
+
# Type checking
|
|
305
|
+
npm run type-check
|
|
306
|
+
|
|
307
|
+
# Linting
|
|
308
|
+
npm run lint
|
|
309
|
+
|
|
310
|
+
# Build for production
|
|
311
|
+
npm run build
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Architecture
|
|
315
|
+
|
|
316
|
+
```text
|
|
317
|
+
filesystem-context-mcp/
|
|
318
|
+
├── src/
|
|
319
|
+
│ ├── index.ts # Main server entry point
|
|
320
|
+
│ └── lib/
|
|
321
|
+
│ ├── types.ts # TypeScript interfaces
|
|
322
|
+
│ ├── path-utils.ts # Path normalization utilities
|
|
323
|
+
│ ├── path-validation.ts # Security validation
|
|
324
|
+
│ ├── file-operations.ts # Core file operations
|
|
325
|
+
│ └── formatters.ts # Output formatting
|
|
326
|
+
├── dist/ # Compiled JavaScript output
|
|
327
|
+
├── package.json # Project configuration
|
|
328
|
+
├── tsconfig.json # TypeScript configuration
|
|
329
|
+
└── README.md # This file
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
The server uses:
|
|
333
|
+
|
|
334
|
+
- **Transport**: StdioServerTransport for local MCP client integration
|
|
335
|
+
- **Schema Validation**: Zod for input/output validation
|
|
336
|
+
- **Glob Matching**: `fast-glob` for file pattern matching and `minimatch` for pattern testing
|
|
337
|
+
- **Security**: Path validation against allowed directories with symlink resolution
|
|
338
|
+
|
|
339
|
+
## Security Considerations
|
|
340
|
+
|
|
341
|
+
- **Required Configuration**: You must specify allowed directories via command line arguments
|
|
342
|
+
- **Path Validation**: All paths are validated against allowed directories before any operation
|
|
343
|
+
- **Symlink Protection**: Symlinks are resolved to their real paths before validation
|
|
344
|
+
- **Read-Only**: The server only performs read operations (no file modifications)
|
|
345
|
+
- **Annotations**: All tools are marked with `readOnlyHint: true` for MCP client awareness
|
|
346
|
+
|
|
347
|
+
## Troubleshooting
|
|
348
|
+
|
|
349
|
+
### Server not starting
|
|
350
|
+
|
|
351
|
+
1. Ensure Node.js >= 20.0.0 is installed
|
|
352
|
+
2. Run `npm install` to install dependencies
|
|
353
|
+
3. Run `npm run build` to compile TypeScript
|
|
354
|
+
|
|
355
|
+
### Connection issues with MCP clients
|
|
356
|
+
|
|
357
|
+
1. Check the path in your client configuration is correct
|
|
358
|
+
2. Ensure the server is built (`npm run build`)
|
|
359
|
+
3. Test with MCP Inspector first: `npx @modelcontextprotocol/inspector`
|
|
360
|
+
|
|
361
|
+
### File access errors
|
|
362
|
+
|
|
363
|
+
1. Verify the server process has read permissions
|
|
364
|
+
2. Check that file paths are absolute or relative to the working directory
|
|
365
|
+
3. Some files (binary, locked) may be skipped during search operations
|
|
366
|
+
|
|
367
|
+
## License
|
|
368
|
+
|
|
369
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/errors.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { classifyError, createDetailedError, ErrorCode, formatDetailedError, getSuggestion, } from '../lib/errors.js';
|
|
3
|
+
describe('Error Utilities', () => {
|
|
4
|
+
describe('classifyError', () => {
|
|
5
|
+
it('should classify access denied errors', () => {
|
|
6
|
+
const error = new Error('Path not within allowed directories');
|
|
7
|
+
expect(classifyError(error)).toBe(ErrorCode.E_ACCESS_DENIED);
|
|
8
|
+
});
|
|
9
|
+
it('should classify not found errors', () => {
|
|
10
|
+
const error = new Error('ENOENT: no such file or directory');
|
|
11
|
+
expect(classifyError(error)).toBe(ErrorCode.E_NOT_FOUND);
|
|
12
|
+
});
|
|
13
|
+
it('should classify not a file errors', () => {
|
|
14
|
+
const error = new Error('Not a file: /some/path');
|
|
15
|
+
expect(classifyError(error)).toBe(ErrorCode.E_NOT_FILE);
|
|
16
|
+
});
|
|
17
|
+
it('should classify file too large errors', () => {
|
|
18
|
+
const error = new Error('File too large: 100MB');
|
|
19
|
+
expect(classifyError(error)).toBe(ErrorCode.E_TOO_LARGE);
|
|
20
|
+
});
|
|
21
|
+
it('should classify permission errors', () => {
|
|
22
|
+
const error = new Error('EACCES: permission denied');
|
|
23
|
+
expect(classifyError(error)).toBe(ErrorCode.E_PERMISSION_DENIED);
|
|
24
|
+
});
|
|
25
|
+
it('should classify timeout errors', () => {
|
|
26
|
+
const error = new Error('Operation timeout');
|
|
27
|
+
expect(classifyError(error)).toBe(ErrorCode.E_TIMEOUT);
|
|
28
|
+
});
|
|
29
|
+
it('should return unknown for unrecognized errors', () => {
|
|
30
|
+
const error = new Error('Some random error');
|
|
31
|
+
expect(classifyError(error)).toBe(ErrorCode.E_UNKNOWN);
|
|
32
|
+
});
|
|
33
|
+
it('should handle non-Error objects', () => {
|
|
34
|
+
expect(classifyError('ENOENT error')).toBe(ErrorCode.E_NOT_FOUND);
|
|
35
|
+
expect(classifyError({ message: 'permission denied' })).toBe(ErrorCode.E_UNKNOWN);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
describe('createDetailedError', () => {
|
|
39
|
+
it('should create detailed error object', () => {
|
|
40
|
+
const error = new Error('File not found');
|
|
41
|
+
const detailed = createDetailedError(error, '/some/path');
|
|
42
|
+
expect(detailed.code).toBe(ErrorCode.E_NOT_FOUND);
|
|
43
|
+
expect(detailed.message).toBe('File not found');
|
|
44
|
+
expect(detailed.path).toBe('/some/path');
|
|
45
|
+
expect(detailed.suggestion).toBeTruthy();
|
|
46
|
+
});
|
|
47
|
+
it('should include additional details', () => {
|
|
48
|
+
const error = new Error('Error');
|
|
49
|
+
const detailed = createDetailedError(error, '/path', { extra: 'info' });
|
|
50
|
+
expect(detailed.details).toEqual({ extra: 'info' });
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
describe('formatDetailedError', () => {
|
|
54
|
+
it('should format error for display', () => {
|
|
55
|
+
const detailed = {
|
|
56
|
+
code: ErrorCode.E_NOT_FOUND,
|
|
57
|
+
message: 'File not found',
|
|
58
|
+
path: '/some/path',
|
|
59
|
+
suggestion: 'Check the path exists',
|
|
60
|
+
};
|
|
61
|
+
const formatted = formatDetailedError(detailed);
|
|
62
|
+
expect(formatted).toContain('E_NOT_FOUND');
|
|
63
|
+
expect(formatted).toContain('File not found');
|
|
64
|
+
expect(formatted).toContain('/some/path');
|
|
65
|
+
expect(formatted).toContain('Check the path exists');
|
|
66
|
+
});
|
|
67
|
+
it('should handle missing optional fields', () => {
|
|
68
|
+
const detailed = {
|
|
69
|
+
code: ErrorCode.E_UNKNOWN,
|
|
70
|
+
message: 'Unknown error',
|
|
71
|
+
};
|
|
72
|
+
const formatted = formatDetailedError(detailed);
|
|
73
|
+
expect(formatted).toContain('E_UNKNOWN');
|
|
74
|
+
expect(formatted).toContain('Unknown error');
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
describe('getSuggestion', () => {
|
|
78
|
+
it('should return suggestions for all error codes', () => {
|
|
79
|
+
const errorCodes = Object.values(ErrorCode);
|
|
80
|
+
for (const code of errorCodes) {
|
|
81
|
+
const suggestion = getSuggestion(code);
|
|
82
|
+
expect(suggestion).toBeTruthy();
|
|
83
|
+
expect(typeof suggestion).toBe('string');
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
//# sourceMappingURL=errors.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.test.js","sourceRoot":"","sources":["../../src/__tests__/errors.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-operations.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/file-operations.test.ts"],"names":[],"mappings":""}
|