fileditor-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/LICENSE +21 -0
- package/README.md +128 -0
- package/docs/MCP-INTERFACE.cn.md +976 -0
- package/docs/MCP-INTERFACE.en.md +881 -0
- package/docs/README.cn.md +128 -0
- package/package.json +27 -0
- package/src/handlers/applyDiff.js +298 -0
- package/src/handlers/insertContent.js +179 -0
- package/src/handlers/listFiles.js +65 -0
- package/src/handlers/readFile.js +109 -0
- package/src/handlers/searchAndReplace.js +198 -0
- package/src/handlers/setWorkspace.js +26 -0
- package/src/handlers/writeFile.js +98 -0
- package/src/index.js +20 -0
- package/src/server.js +85 -0
- package/src/tools/toolDefinitions.js +291 -0
- package/src/utils/fileUtils.js +238 -0
- package/test/ApplyDiffHandler.test.js +754 -0
- package/test/InsertContentHandler.test.js +371 -0
- package/test/ListFilesHandler.test.js +302 -0
- package/test/ReadFileHandler.test.js +213 -0
- package/test/SearchAndReplaceHandler.test.js +505 -0
- package/test/SetWorkspaceHandler.test.js +290 -0
- package/test/WriteFileHandler.test.js +289 -0
- package/test/runAllTests.js +233 -0
|
@@ -0,0 +1,881 @@
|
|
|
1
|
+
# MCP File Operation Toolkit Documentation
|
|
2
|
+
|
|
3
|
+
## Tool Overview
|
|
4
|
+
|
|
5
|
+
This document describes a set of file operation tools compliant with the Model Context Protocol (MCP), including 7 core tools for workspace management and file reading, writing, modification, and search operations.
|
|
6
|
+
|
|
7
|
+
## 🔒 Security Features
|
|
8
|
+
|
|
9
|
+
- **Workspace Isolation**: You must call `set_workspace` to set the workspace root directory first
|
|
10
|
+
- **Path Security**: All file operations are strictly limited to the set workspace, preventing directory traversal attacks
|
|
11
|
+
- **Relative Path Support**: Relative paths are automatically resolved based on the workspace root directory
|
|
12
|
+
|
|
13
|
+
**⚠️ Important**: You must call the `set_workspace` tool to set the workspace root directory before performing any file operations, otherwise all operations will be rejected.
|
|
14
|
+
|
|
15
|
+
**Implementation Status**:
|
|
16
|
+
- ✅ `set_workspace` - Implemented (workspace setup)
|
|
17
|
+
- ✅ `read_files` - Implemented
|
|
18
|
+
- ✅ `write_files` - Implemented
|
|
19
|
+
- ✅ `list_files` - Implemented
|
|
20
|
+
- ✅ `insert_contents` - Implemented
|
|
21
|
+
- ✅ `apply_diffs` - Implemented
|
|
22
|
+
- ✅ `search_and_replace` - Implemented
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 0. `set_workspace` (Set Workspace)
|
|
27
|
+
|
|
28
|
+
**Description**: Set the workspace root directory. All subsequent file operations will be based on this directory. Relative paths will be automatically resolved within the workspace, and absolute paths must be within the workspace.
|
|
29
|
+
|
|
30
|
+
**MCP Call Format**:
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"name": "set_workspace",
|
|
34
|
+
"arguments": {
|
|
35
|
+
"path": "/absolute/path/to/workspace"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Return Example**:
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"content": [
|
|
44
|
+
{
|
|
45
|
+
"type": "text",
|
|
46
|
+
"text": "Successfully set workspace root to: /Users/username/projects/my-project"
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## 1. `read_files` (Read Files)
|
|
55
|
+
|
|
56
|
+
**Description**: Read the entire or partial content of the specified file(s). Supports reading single or multiple files at once. The returned content includes line numbers (format: `line | content`) for easy line reference in other tools.
|
|
57
|
+
|
|
58
|
+
**MCP Call Format**:
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"name": "read_files",
|
|
62
|
+
"arguments": {
|
|
63
|
+
"path": "file path or array of file paths",
|
|
64
|
+
"line_range": "start-end" // Optional, only for single file, e.g. "1-50"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Parameter Schema**:
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"type": "object",
|
|
73
|
+
"properties": {
|
|
74
|
+
"path": {
|
|
75
|
+
"oneOf": [
|
|
76
|
+
{ "type": "string", "description": "The path of the single file to read" },
|
|
77
|
+
{ "type": "array", "items": { "type": "string" }, "description": "An array of file paths to read" }
|
|
78
|
+
]
|
|
79
|
+
},
|
|
80
|
+
"line_range": {
|
|
81
|
+
"type": "string",
|
|
82
|
+
"description": "Optional line range, format 'start-end' (only for single file)",
|
|
83
|
+
"pattern": "^\\d+-\\d+$"
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"required": ["path"]
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Usage Example**:
|
|
91
|
+
|
|
92
|
+
*Single file:*
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"name": "read_files",
|
|
96
|
+
"arguments": {
|
|
97
|
+
"path": "src/main/java/com/example/lsmtree/MemTable.java"
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Return Example**:
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
"content": [
|
|
106
|
+
{
|
|
107
|
+
"type": "text",
|
|
108
|
+
"text": "1 | package com.example.lsmtree;\n2 | ..."
|
|
109
|
+
}
|
|
110
|
+
]
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
*Multiple files:*
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"name": "read_files",
|
|
118
|
+
"arguments": {
|
|
119
|
+
"path": ["package.json", "README.md"]
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Return Example**:
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"content": [
|
|
128
|
+
{
|
|
129
|
+
"type": "text",
|
|
130
|
+
"text": "Successfully read 2 file(s):\n\n=== package.json (25 lines) ===\n{...}\n\n=== README.md (15 lines) ===\n# FileEditor MCP\n..."
|
|
131
|
+
}
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
*Single file with line range:*
|
|
137
|
+
```json
|
|
138
|
+
{
|
|
139
|
+
"name": "read_files",
|
|
140
|
+
"arguments": {
|
|
141
|
+
"path": "config.properties",
|
|
142
|
+
"line_range": "1-10"
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Return Example**:
|
|
148
|
+
```json
|
|
149
|
+
{
|
|
150
|
+
"content": [
|
|
151
|
+
{
|
|
152
|
+
"type": "text",
|
|
153
|
+
"text": "# Configuration file\nserver.port=8080\ndb.url=localhost:3306\n..."
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 2. `write_files` (Write Files)
|
|
162
|
+
|
|
163
|
+
**Description**: Create new files or completely overwrite existing files. Supports single or multiple files at once.
|
|
164
|
+
|
|
165
|
+
**MCP Call Format**:
|
|
166
|
+
```json
|
|
167
|
+
{
|
|
168
|
+
"name": "write_files",
|
|
169
|
+
"arguments": {
|
|
170
|
+
"path": "file path" | ["path1", "path2", ...],
|
|
171
|
+
"content": "full file content" | ["content1", "content2", ...],
|
|
172
|
+
"line_count": total lines | [lines1, lines2, ...]
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**Parameter Schema**:
|
|
178
|
+
```json
|
|
179
|
+
{
|
|
180
|
+
"type": "object",
|
|
181
|
+
"properties": {
|
|
182
|
+
"path": {
|
|
183
|
+
"oneOf": [
|
|
184
|
+
{ "type": "string", "description": "The path of the single target file" },
|
|
185
|
+
{ "type": "array", "items": { "type": "string" }, "description": "An array of target file paths" }
|
|
186
|
+
]
|
|
187
|
+
},
|
|
188
|
+
"content": {
|
|
189
|
+
"oneOf": [
|
|
190
|
+
{ "type": "string", "description": "The full content to write, for single file or same content for all files" },
|
|
191
|
+
{ "type": "array", "items": { "type": "string" }, "description": "An array of content for each file, for different content per file" }
|
|
192
|
+
]
|
|
193
|
+
},
|
|
194
|
+
"line_count": {
|
|
195
|
+
"oneOf": [
|
|
196
|
+
{ "type": "integer", "description": "Total number of lines in the file, for single file or same for all files", "minimum": 0 },
|
|
197
|
+
{ "type": "array", "items": { "type": "integer", "minimum": 0 }, "description": "An array of line counts for each file, for different line counts per file" }
|
|
198
|
+
]
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
"required": ["path", "content", "line_count"]
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**Usage Example**:
|
|
206
|
+
|
|
207
|
+
*Single file:*
|
|
208
|
+
```json
|
|
209
|
+
{
|
|
210
|
+
"name": "write_files",
|
|
211
|
+
"arguments": {
|
|
212
|
+
"path": "config/database.js",
|
|
213
|
+
"content": "export const config = {\n host: 'localhost',\n port: 3306\n};",
|
|
214
|
+
"line_count": 4
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
*Multiple files, same content:*
|
|
220
|
+
```json
|
|
221
|
+
{
|
|
222
|
+
"name": "write_files",
|
|
223
|
+
"arguments": {
|
|
224
|
+
"path": ["config/dev.env", "config/test.env"],
|
|
225
|
+
"content": "NODE_ENV=development\nDEBUG=true",
|
|
226
|
+
"line_count": 2
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
*Multiple files, different content:*
|
|
232
|
+
```json
|
|
233
|
+
{
|
|
234
|
+
"name": "write_files",
|
|
235
|
+
"arguments": {
|
|
236
|
+
"path": ["package.json", "README.md", ".gitignore"],
|
|
237
|
+
"content": [
|
|
238
|
+
"{\n \"name\": \"my-project\",\n \"version\": \"1.0.0\"\n}",
|
|
239
|
+
"# My Project\n\nA sample project",
|
|
240
|
+
"node_modules/\n*.log\n.env"
|
|
241
|
+
],
|
|
242
|
+
"line_count": [4, 3, 3]
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
**Return Example**:
|
|
248
|
+
|
|
249
|
+
*Single file:*
|
|
250
|
+
```json
|
|
251
|
+
{
|
|
252
|
+
"content": [
|
|
253
|
+
{
|
|
254
|
+
"type": "text",
|
|
255
|
+
"text": "File written successfully: config/database.js (4 lines)"
|
|
256
|
+
}
|
|
257
|
+
]
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
*Multiple files:*
|
|
262
|
+
```json
|
|
263
|
+
{
|
|
264
|
+
"content": [
|
|
265
|
+
{
|
|
266
|
+
"type": "text",
|
|
267
|
+
"text": "Successfully wrote 3 files (10 total lines):\n - package.json (4 lines)\n - README.md (3 lines)\n - .gitignore (3 lines)"
|
|
268
|
+
}
|
|
269
|
+
]
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## 3. `apply_diffs` (Apply Diffs)
|
|
276
|
+
|
|
277
|
+
**Description**: Perform precise block-based search and replace operations on existing files. Supports single or multiple diff operations on a single file. When processing multiple diffs, the tool automatically handles line number offsets - all start_line values should be based on the original file structure. By default, operates in atomic mode for safe batch operations.
|
|
278
|
+
|
|
279
|
+
**MCP Call Format**:
|
|
280
|
+
```json
|
|
281
|
+
{
|
|
282
|
+
"name": "apply_diffs",
|
|
283
|
+
"arguments": {
|
|
284
|
+
"path": "file path",
|
|
285
|
+
"search_content": "original content to match" | ["content1", "content2", ...],
|
|
286
|
+
"replace_content": "new content to replace with" | ["content1", "content2", ...],
|
|
287
|
+
"start_line": starting line number | [line1, line2, ...],
|
|
288
|
+
"atomic": true/false, // Optional, default is true
|
|
289
|
+
"trim": true/false // Optional, default is false
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
**Parameter Schema**:
|
|
295
|
+
```json
|
|
296
|
+
{
|
|
297
|
+
"type": "object",
|
|
298
|
+
"properties": {
|
|
299
|
+
"path": { "type": "string", "description": "The path of the file to modify" },
|
|
300
|
+
"search_content": {
|
|
301
|
+
"oneOf": [
|
|
302
|
+
{
|
|
303
|
+
"type": "string",
|
|
304
|
+
"description": "The original content to match precisely (for single diff)"
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
"type": "array",
|
|
308
|
+
"items": {
|
|
309
|
+
"type": "string"
|
|
310
|
+
},
|
|
311
|
+
"description": "Array of original content to match precisely (for multiple diffs)"
|
|
312
|
+
}
|
|
313
|
+
]
|
|
314
|
+
},
|
|
315
|
+
"replace_content": {
|
|
316
|
+
"oneOf": [
|
|
317
|
+
{
|
|
318
|
+
"type": "string",
|
|
319
|
+
"description": "The new content to replace with (for single diff)"
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
"type": "array",
|
|
323
|
+
"items": {
|
|
324
|
+
"type": "string"
|
|
325
|
+
},
|
|
326
|
+
"description": "Array of new content to replace with (for multiple diffs)"
|
|
327
|
+
}
|
|
328
|
+
]
|
|
329
|
+
},
|
|
330
|
+
"start_line": {
|
|
331
|
+
"oneOf": [
|
|
332
|
+
{
|
|
333
|
+
"type": "integer",
|
|
334
|
+
"description": "The starting line number for searching content (for single diff, 1-based line number from original file)",
|
|
335
|
+
"minimum": 1
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
"type": "array",
|
|
339
|
+
"items": {
|
|
340
|
+
"type": "integer",
|
|
341
|
+
"minimum": 1
|
|
342
|
+
},
|
|
343
|
+
"description": "Array of starting line numbers for searching content (for multiple diffs, all 1-based line numbers from original file - tool automatically handles line offset adjustments during processing)"
|
|
344
|
+
}
|
|
345
|
+
]
|
|
346
|
+
},
|
|
347
|
+
"atomic": {
|
|
348
|
+
"type": "boolean",
|
|
349
|
+
"description": "Whether to use atomic mode (all-or-nothing). When true (default), validates all diffs before applying any. When false, applies diffs one by one, continuing on failures.",
|
|
350
|
+
"default": true
|
|
351
|
+
},
|
|
352
|
+
"trim": {
|
|
353
|
+
"type": "boolean",
|
|
354
|
+
"description": "Whether to trim whitespace from the beginning and end of each line when comparing search_content with file content. Only affects search and matching - replace_content is inserted exactly as provided. Default is false.",
|
|
355
|
+
"default": false
|
|
356
|
+
}
|
|
357
|
+
},
|
|
358
|
+
"required": ["path", "search_content", "replace_content", "start_line"]
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
**Usage Example**:
|
|
363
|
+
```json
|
|
364
|
+
{
|
|
365
|
+
"name": "apply_diffs",
|
|
366
|
+
"arguments": {
|
|
367
|
+
"path": "pom.xml",
|
|
368
|
+
"search_content": " <version>1.2.0</version>",
|
|
369
|
+
"replace_content": " <version>1.3.1</version>",
|
|
370
|
+
"start_line": 25
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
**Return Example**:
|
|
376
|
+
```json
|
|
377
|
+
{
|
|
378
|
+
"content": [
|
|
379
|
+
{
|
|
380
|
+
"type": "text",
|
|
381
|
+
"text": "Successfully applied diff to pom.xml: replaced 1 line(s) at line 25. File now has 45 lines."
|
|
382
|
+
}
|
|
383
|
+
]
|
|
384
|
+
}
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
*Multi-line replace:*
|
|
388
|
+
```json
|
|
389
|
+
{
|
|
390
|
+
"name": "apply_diffs",
|
|
391
|
+
"arguments": {
|
|
392
|
+
"path": "config.js",
|
|
393
|
+
"search_content": "const config = {\n port: 3000,\n host: 'localhost'\n};",
|
|
394
|
+
"replace_content": "const config = {\n port: process.env.PORT || 8080,\n host: process.env.HOST || '0.0.0.0',\n ssl: process.env.SSL || false\n};",
|
|
395
|
+
"start_line": 10
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
**Return Example**:
|
|
401
|
+
```json
|
|
402
|
+
{
|
|
403
|
+
"content": [
|
|
404
|
+
{
|
|
405
|
+
"type": "text",
|
|
406
|
+
"text": "Successfully applied diff to config.js: replaced 4 line(s) at line 10 (added 1 line(s)). File now has 26 lines."
|
|
407
|
+
}
|
|
408
|
+
]
|
|
409
|
+
}
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
*Using trim option for whitespace differences:*
|
|
413
|
+
```json
|
|
414
|
+
{
|
|
415
|
+
"name": "apply_diffs",
|
|
416
|
+
"arguments": {
|
|
417
|
+
"path": "config.js",
|
|
418
|
+
"search_content": "console.log('Hello World');",
|
|
419
|
+
"replace_content": " console.log('Hello Universe');",
|
|
420
|
+
"start_line": 5,
|
|
421
|
+
"trim": true
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
**Return Example**:
|
|
427
|
+
```json
|
|
428
|
+
{
|
|
429
|
+
"content": [
|
|
430
|
+
{
|
|
431
|
+
"type": "text",
|
|
432
|
+
"text": "Successfully applied diff to config.js: replaced 1 line(s) at line 5. File now has 25 lines."
|
|
433
|
+
}
|
|
434
|
+
]
|
|
435
|
+
}
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
*Batch operations (atomic mode):*
|
|
439
|
+
```json
|
|
440
|
+
{
|
|
441
|
+
"name": "apply_diffs",
|
|
442
|
+
"arguments": {
|
|
443
|
+
"path": "main.js",
|
|
444
|
+
"search_content": [
|
|
445
|
+
" console.log('start');",
|
|
446
|
+
" return false;",
|
|
447
|
+
" console.log('end');"
|
|
448
|
+
],
|
|
449
|
+
"replace_content": [
|
|
450
|
+
" console.log('application started');",
|
|
451
|
+
" return true;",
|
|
452
|
+
" console.log('application ended');"
|
|
453
|
+
],
|
|
454
|
+
"start_line": [2, 15, 28],
|
|
455
|
+
"atomic": true
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
**Return Example**:
|
|
461
|
+
```json
|
|
462
|
+
{
|
|
463
|
+
"content": [
|
|
464
|
+
{
|
|
465
|
+
"type": "text",
|
|
466
|
+
"text": "Batch diff operation (atomic) completed: 3/3 diffs applied successfully to main.js. File now has 30 lines.\n\nDetailed results:\n\nDiff 1:\n Status: success\n Start Line: 2\n Message: Replaced 1 line(s) at line 2\n\nDiff 2:\n Status: success\n Start Line: 15\n Message: Replaced 1 line(s) at line 15\n\nDiff 3:\n Status: success\n Start Line: 28\n Message: Replaced 1 line(s) at line 28"
|
|
467
|
+
}
|
|
468
|
+
]
|
|
469
|
+
}
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
---
|
|
473
|
+
|
|
474
|
+
## 4. `insert_contents` (Insert Contents)
|
|
475
|
+
|
|
476
|
+
**Description**: Insert new content at the specified position in the file. Supports editing single or multiple files at once. Negative line numbers are supported for insertion from the end (-1 means before the last line).
|
|
477
|
+
|
|
478
|
+
**MCP Call Format**:
|
|
479
|
+
```json
|
|
480
|
+
{
|
|
481
|
+
"name": "insert_contents",
|
|
482
|
+
"arguments": {
|
|
483
|
+
"path": "file path or array of file paths",
|
|
484
|
+
"line": "line number or array of line numbers",
|
|
485
|
+
"content": "content or array of content"
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
**Parameter Schema**:
|
|
491
|
+
```json
|
|
492
|
+
{
|
|
493
|
+
"type": "object",
|
|
494
|
+
"properties": {
|
|
495
|
+
"path": {
|
|
496
|
+
"oneOf": [
|
|
497
|
+
{ "type": "string", "description": "The path of the single target file" },
|
|
498
|
+
{ "type": "array", "items": { "type": "string" }, "description": "An array of target file paths" }
|
|
499
|
+
]
|
|
500
|
+
},
|
|
501
|
+
"line": {
|
|
502
|
+
"oneOf": [
|
|
503
|
+
{ "type": "integer", "description": "The line number to insert (positive: 1-based, 0: end of file, negative: from end, -1 before last line), for single file" },
|
|
504
|
+
{ "type": "array", "items": { "type": "integer" }, "description": "An array of line numbers for each file (positive: insert, 0: end, negative: from end), for multiple files" }
|
|
505
|
+
]
|
|
506
|
+
},
|
|
507
|
+
"content": {
|
|
508
|
+
"oneOf": [
|
|
509
|
+
{ "type": "string", "description": "The content to insert, for single file or same content for all files" },
|
|
510
|
+
{ "type": "array", "items": { "type": "string" }, "description": "An array of content for each file, for different content per file" }
|
|
511
|
+
]
|
|
512
|
+
}
|
|
513
|
+
},
|
|
514
|
+
"required": ["path", "line", "content"]
|
|
515
|
+
}
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
**Usage Example**:
|
|
519
|
+
|
|
520
|
+
*Single file:*
|
|
521
|
+
```json
|
|
522
|
+
{
|
|
523
|
+
"name": "insert_contents",
|
|
524
|
+
"arguments": {
|
|
525
|
+
"path": "src/main/java/com/example/App.java",
|
|
526
|
+
"line": 3,
|
|
527
|
+
"content": "import java.util.ArrayList;"
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
**Return Example**:
|
|
533
|
+
```json
|
|
534
|
+
{
|
|
535
|
+
"content": [
|
|
536
|
+
{
|
|
537
|
+
"type": "text",
|
|
538
|
+
"text": "Successfully inserted 1 line(s) at position 3 in src/main/java/com/example/App.java. File now has 25 lines."
|
|
539
|
+
}
|
|
540
|
+
]
|
|
541
|
+
}
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
*Multiple files, same position and content:*
|
|
545
|
+
```json
|
|
546
|
+
{
|
|
547
|
+
"name": "insert_contents",
|
|
548
|
+
"arguments": {
|
|
549
|
+
"path": ["file1.js", "file2.js", "file3.js"],
|
|
550
|
+
"line": 1,
|
|
551
|
+
"content": "// Added comment"
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
**Return Example**:
|
|
557
|
+
```json
|
|
558
|
+
{
|
|
559
|
+
"content": [
|
|
560
|
+
{
|
|
561
|
+
"type": "text",
|
|
562
|
+
"text": "Successfully processed 3 file(s):\n\n✅ file1.js: Successfully inserted 1 line(s) at position 1 in file1.js. File now has 15 lines.\n✅ file2.js: Successfully inserted 1 line(s) at position 1 in file2.js. File now has 22 lines.\n✅ file3.js: Successfully inserted 1 line(s) at position 1 in file3.js. File now has 8 lines."
|
|
563
|
+
}
|
|
564
|
+
]
|
|
565
|
+
}
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
*Multiple files, different positions and content:*
|
|
569
|
+
```json
|
|
570
|
+
{
|
|
571
|
+
"name": "insert_contents",
|
|
572
|
+
"arguments": {
|
|
573
|
+
"path": ["config.js", "utils.js", "main.js"],
|
|
574
|
+
"line": [1, 5, 0],
|
|
575
|
+
"content": [
|
|
576
|
+
"// Config file",
|
|
577
|
+
"// Utility functions",
|
|
578
|
+
"// Main entry point"
|
|
579
|
+
]
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
**Return Example**:
|
|
585
|
+
```json
|
|
586
|
+
{
|
|
587
|
+
"content": [
|
|
588
|
+
{
|
|
589
|
+
"type": "text",
|
|
590
|
+
"text": "Successfully processed 3 file(s):\n\n✅ config.js: Successfully inserted 1 line(s) at position 1 in config.js. File now has 20 lines.\n✅ utils.js: Successfully inserted 1 line(s) at position 5 in utils.js. File now has 35 lines.\n✅ main.js: Successfully inserted 1 line(s) at position end of file in main.js. File now has 45 lines."
|
|
591
|
+
}
|
|
592
|
+
]
|
|
593
|
+
}
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
---
|
|
597
|
+
|
|
598
|
+
## 5. `search_and_replace` (Search and Replace)
|
|
599
|
+
|
|
600
|
+
**Description**: Search and replace text or regular expressions in a single file.
|
|
601
|
+
|
|
602
|
+
**MCP Call Format**:
|
|
603
|
+
```json
|
|
604
|
+
{
|
|
605
|
+
"name": "search_and_replace",
|
|
606
|
+
"arguments": {
|
|
607
|
+
"path": "file path",
|
|
608
|
+
"search": "text or regex to search for",
|
|
609
|
+
"replace": "text to replace with",
|
|
610
|
+
"use_regex": true/false,
|
|
611
|
+
"ignore_case": true/false,
|
|
612
|
+
"start_line": start line,
|
|
613
|
+
"end_line": end line
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
**Parameter Schema**:
|
|
619
|
+
```json
|
|
620
|
+
{
|
|
621
|
+
"type": "object",
|
|
622
|
+
"properties": {
|
|
623
|
+
"path": { "type": "string", "description": "The target file path" },
|
|
624
|
+
"search": { "type": "string", "description": "The text or regular expression to search for" },
|
|
625
|
+
"replace": { "type": "string", "description": "The text to replace with" },
|
|
626
|
+
"use_regex": { "type": "boolean", "description": "Whether to use regular expressions for searching", "default": false },
|
|
627
|
+
"ignore_case": { "type": "boolean", "description": "Whether to ignore case when searching", "default": false },
|
|
628
|
+
"start_line": { "type": "integer", "description": "The starting line of the search range", "minimum": 1 },
|
|
629
|
+
"end_line": { "type": "integer", "description": "The ending line of the search range", "minimum": 1 }
|
|
630
|
+
},
|
|
631
|
+
"required": ["path", "search", "replace"]
|
|
632
|
+
}
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
**Usage Example**:
|
|
636
|
+
```json
|
|
637
|
+
{
|
|
638
|
+
"name": "search_and_replace",
|
|
639
|
+
"arguments": {
|
|
640
|
+
"path": "src/main/resources/application.properties",
|
|
641
|
+
"search": "app.name",
|
|
642
|
+
"replace": "spring.application.name",
|
|
643
|
+
"use_regex": false
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
**Return Example**:
|
|
649
|
+
```json
|
|
650
|
+
{
|
|
651
|
+
"content": [
|
|
652
|
+
{
|
|
653
|
+
"type": "text",
|
|
654
|
+
"text": "Successfully replaced 3 occurrence(s) in src/main/resources/application.properties"
|
|
655
|
+
}
|
|
656
|
+
]
|
|
657
|
+
}
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
*Using regex:*
|
|
661
|
+
```json
|
|
662
|
+
{
|
|
663
|
+
"name": "search_and_replace",
|
|
664
|
+
"arguments": {
|
|
665
|
+
"path": "config.js",
|
|
666
|
+
"search": "const\\s+(\\w+)\\s*=\\s*require\\(['\"]([^'\"]+)['\"]\)",
|
|
667
|
+
"replace": "import $1 from '$2'",
|
|
668
|
+
"use_regex": true
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
**Return Example**:
|
|
674
|
+
```json
|
|
675
|
+
{
|
|
676
|
+
"content": [
|
|
677
|
+
{
|
|
678
|
+
"type": "text",
|
|
679
|
+
"text": "Successfully replaced 5 occurrence(s) in config.js using regex pattern"
|
|
680
|
+
}
|
|
681
|
+
]
|
|
682
|
+
}
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
*Specify line range:*
|
|
686
|
+
```json
|
|
687
|
+
{
|
|
688
|
+
"name": "search_and_replace",
|
|
689
|
+
"arguments": {
|
|
690
|
+
"path": "package.json",
|
|
691
|
+
"search": "1.0.0",
|
|
692
|
+
"replace": "1.1.0",
|
|
693
|
+
"start_line": 1,
|
|
694
|
+
"end_line": 10
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
**Return Example**:
|
|
700
|
+
```json
|
|
701
|
+
{
|
|
702
|
+
"content": [
|
|
703
|
+
{
|
|
704
|
+
"type": "text",
|
|
705
|
+
"text": "Successfully replaced 1 occurrence(s) in package.json (lines 1-10)"
|
|
706
|
+
}
|
|
707
|
+
]
|
|
708
|
+
}
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
*Ignore case:*
|
|
712
|
+
```json
|
|
713
|
+
{
|
|
714
|
+
"name": "search_and_replace",
|
|
715
|
+
"arguments": {
|
|
716
|
+
"path": "README.md",
|
|
717
|
+
"search": "hello",
|
|
718
|
+
"replace": "Hi",
|
|
719
|
+
"ignore_case": true
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
**Return Example**:
|
|
725
|
+
```json
|
|
726
|
+
{
|
|
727
|
+
"content": [
|
|
728
|
+
{
|
|
729
|
+
"type": "text",
|
|
730
|
+
"text": "Successfully replaced 3 occurrence(s) in README.md (case-insensitive)"
|
|
731
|
+
}
|
|
732
|
+
]
|
|
733
|
+
}
|
|
734
|
+
```
|
|
735
|
+
|
|
736
|
+
---
|
|
737
|
+
|
|
738
|
+
## 6. `list_files` (List Files)
|
|
739
|
+
|
|
740
|
+
**Description**: List the files and subdirectories in the specified directory.
|
|
741
|
+
|
|
742
|
+
**MCP Call Format**:
|
|
743
|
+
```json
|
|
744
|
+
{
|
|
745
|
+
"name": "list_files",
|
|
746
|
+
"arguments": {
|
|
747
|
+
"path": "directory path",
|
|
748
|
+
"recursive": true/false
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
**Parameter Schema**:
|
|
754
|
+
```json
|
|
755
|
+
{
|
|
756
|
+
"type": "object",
|
|
757
|
+
"properties": {
|
|
758
|
+
"path": { "type": "string", "description": "The directory path to list contents of" },
|
|
759
|
+
"recursive": { "type": "boolean", "description": "Whether to recursively list subdirectory contents", "default": false }
|
|
760
|
+
},
|
|
761
|
+
"required": ["path"]
|
|
762
|
+
}
|
|
763
|
+
```
|
|
764
|
+
|
|
765
|
+
**Usage Example**:
|
|
766
|
+
```json
|
|
767
|
+
{
|
|
768
|
+
"name": "list_files",
|
|
769
|
+
"arguments": {
|
|
770
|
+
"path": "src/main",
|
|
771
|
+
"recursive": false
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
**Return Example**:
|
|
777
|
+
```json
|
|
778
|
+
{
|
|
779
|
+
"content": [
|
|
780
|
+
{
|
|
781
|
+
"type": "text",
|
|
782
|
+
"text": "directory: java\nfile: resources\nfile: webapp"
|
|
783
|
+
}
|
|
784
|
+
]
|
|
785
|
+
}
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
*Recursive list:*
|
|
789
|
+
```json
|
|
790
|
+
{
|
|
791
|
+
"name": "list_files",
|
|
792
|
+
"arguments": {
|
|
793
|
+
"path": "src",
|
|
794
|
+
"recursive": true
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
**Return Example**:
|
|
800
|
+
```json
|
|
801
|
+
{
|
|
802
|
+
"content": [
|
|
803
|
+
{
|
|
804
|
+
"type": "text",
|
|
805
|
+
"text": "directory: main\ndirectory: main/java\nfile: main/java/App.java\nfile: main/java/Utils.java\ndirectory: main/resources\nfile: main/resources/config.properties\ndirectory: test\nfile: test/AppTest.java"
|
|
806
|
+
}
|
|
807
|
+
]
|
|
808
|
+
}
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
---
|
|
812
|
+
|
|
813
|
+
## Return Value Format
|
|
814
|
+
|
|
815
|
+
All tool return values follow the MCP standard format:
|
|
816
|
+
|
|
817
|
+
**Success Response Format**:
|
|
818
|
+
```json
|
|
819
|
+
{
|
|
820
|
+
"content": [
|
|
821
|
+
{
|
|
822
|
+
"type": "text",
|
|
823
|
+
"text": "Result or file content"
|
|
824
|
+
}
|
|
825
|
+
]
|
|
826
|
+
}
|
|
827
|
+
```
|
|
828
|
+
|
|
829
|
+
**Error Response Format**:
|
|
830
|
+
```json
|
|
831
|
+
{
|
|
832
|
+
"isError": true,
|
|
833
|
+
"content": [
|
|
834
|
+
{
|
|
835
|
+
"type": "text",
|
|
836
|
+
"text": "Error: error message description"
|
|
837
|
+
}
|
|
838
|
+
]
|
|
839
|
+
}
|
|
840
|
+
```
|
|
841
|
+
|
|
842
|
+
**Common Error Examples**:
|
|
843
|
+
|
|
844
|
+
*File not found:*
|
|
845
|
+
```json
|
|
846
|
+
{
|
|
847
|
+
"isError": true,
|
|
848
|
+
"content": [
|
|
849
|
+
{
|
|
850
|
+
"type": "text",
|
|
851
|
+
"text": "Error: File not found: nonexistent_file.txt"
|
|
852
|
+
}
|
|
853
|
+
]
|
|
854
|
+
}
|
|
855
|
+
```
|
|
856
|
+
|
|
857
|
+
*Line number out of range:*
|
|
858
|
+
```json
|
|
859
|
+
{
|
|
860
|
+
"isError": true,
|
|
861
|
+
"content": [
|
|
862
|
+
{
|
|
863
|
+
"type": "text",
|
|
864
|
+
"text": "Error: Line number 50 exceeds file length (20 lines)"
|
|
865
|
+
}
|
|
866
|
+
]
|
|
867
|
+
}
|
|
868
|
+
```
|
|
869
|
+
|
|
870
|
+
*Directory not found:*
|
|
871
|
+
```json
|
|
872
|
+
{
|
|
873
|
+
"isError": true,
|
|
874
|
+
"content": [
|
|
875
|
+
{
|
|
876
|
+
"type": "text",
|
|
877
|
+
"text": "Error: Directory not found: /nonexistent/path"
|
|
878
|
+
}
|
|
879
|
+
]
|
|
880
|
+
}
|
|
881
|
+
```
|