@j0hanz/filesystem-mcp 1.13.1 → 1.14.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 +117 -100
- package/dist/completions.d.ts +0 -11
- package/dist/completions.js +1 -1
- package/dist/config.d.ts +0 -1
- package/dist/lib/constants.d.ts +0 -1
- package/dist/lib/constants.js +0 -1
- package/dist/lib/errors.d.ts +0 -1
- package/dist/lib/errors.js +5 -9
- package/dist/lib/file-operations/core.d.ts +3 -2
- package/dist/lib/file-operations/metadata.js +9 -3
- package/dist/lib/file-operations/search.d.ts +1 -59
- package/dist/lib/file-operations/search.js +9 -22
- package/dist/lib/file-operations/traversal.d.ts +2 -2
- package/dist/lib/fs-helpers.d.ts +1 -2
- package/dist/lib/fs-helpers.js +10 -12
- package/dist/lib/globs.d.ts +2 -0
- package/dist/lib/globs.js +19 -0
- package/dist/lib/paths.d.ts +0 -3
- package/dist/lib/paths.js +1 -4
- package/dist/lib/utils.d.ts +4 -4
- package/dist/lib/utils.js +1 -10
- package/dist/lib/zod-codecs.d.ts +2 -0
- package/dist/lib/zod-codecs.js +18 -0
- package/dist/pkg-info.d.ts +1 -0
- package/dist/pkg-info.js +2 -2
- package/dist/prompts.js +3 -3
- package/dist/resources/generated-instructions.js +3 -12
- package/dist/resources/tool-catalog.js +10 -41
- package/dist/resources/tool-info.d.ts +0 -1
- package/dist/resources/tool-info.js +24 -39
- package/dist/resources/workflows.js +8 -1
- package/dist/schemas.d.ts +179 -481
- package/dist/schemas.js +156 -169
- package/dist/server/bootstrap.d.ts +0 -10
- package/dist/server/bootstrap.js +3 -3
- package/dist/server/roots-manager.js +1 -1
- package/dist/tools/apply-patch.js +19 -8
- package/dist/tools/calculate-hash.js +3 -5
- package/dist/tools/create-directory.d.ts +1 -4
- package/dist/tools/create-directory.js +2 -2
- package/dist/tools/delete-file.js +2 -4
- package/dist/tools/diff-files.js +1 -3
- package/dist/tools/edit-file.d.ts +1 -7
- package/dist/tools/edit-file.js +6 -3
- package/dist/tools/list-directory.js +10 -15
- package/dist/tools/move-file.d.ts +1 -4
- package/dist/tools/move-file.js +15 -27
- package/dist/tools/read-multiple.js +12 -7
- package/dist/tools/read.js +1 -2
- package/dist/tools/replace-in-files.d.ts +1 -10
- package/dist/tools/replace-in-files.js +62 -97
- package/dist/tools/roots.js +2 -6
- package/dist/tools/search-content.js +152 -188
- package/dist/tools/search-files.js +10 -13
- package/dist/tools/shared.d.ts +10 -3
- package/dist/tools/shared.js +53 -12
- package/dist/tools/stat-many.js +6 -4
- package/dist/tools/stat.js +2 -2
- package/dist/tools/task-support.d.ts +0 -7
- package/dist/tools/task-support.js +7 -6
- package/dist/tools/tree.js +1 -1
- package/dist/tools/write-file.js +1 -5
- package/dist/tools.d.ts +0 -1
- package/dist/tools.js +0 -1
- package/package.json +5 -5
package/dist/schemas.js
CHANGED
|
@@ -1,26 +1,20 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { DEFAULT_LIST_MAX_ENTRIES, DEFAULT_SEARCH_CONTENT_RESULTS, DEFAULT_SEARCH_RESULTS, DEFAULT_TREE_DEPTH, DEFAULT_TREE_ENTRIES, MAX_LIST_ENTRIES, MAX_SEARCH_DEPTH, MAX_SEARCH_RESULTS, MAX_TREE_DEPTH, MAX_TREE_ENTRIES, } from './lib/constants.js';
|
|
3
3
|
import { ErrorCode } from './lib/errors.js';
|
|
4
|
-
|
|
5
|
-
if (value.length === 0)
|
|
6
|
-
return false;
|
|
7
|
-
if (value.includes('**/**/**'))
|
|
8
|
-
return false;
|
|
9
|
-
const absolutePattern = /^([/\\]|[A-Za-z]:[/\\]|\\\\)/u;
|
|
10
|
-
if (absolutePattern.test(value)) {
|
|
11
|
-
return false;
|
|
12
|
-
}
|
|
13
|
-
if (/[\\/]\.\.(?:[/\\]|$)/u.test(value) || value.startsWith('..')) {
|
|
14
|
-
return false;
|
|
15
|
-
}
|
|
16
|
-
return true;
|
|
17
|
-
}
|
|
4
|
+
import { isSafeGlobPattern } from './lib/globs.js';
|
|
18
5
|
const MAX_PATH_LENGTH = 4096;
|
|
19
6
|
const DESC_PATH_ROOT = 'Base directory (default: root). Absolute path required if multiple roots.';
|
|
20
7
|
const DESC_PATH_REQUIRED = 'Absolute path to file or directory.';
|
|
21
8
|
function defaultFalseBoolean(description) {
|
|
22
9
|
return z.boolean().optional().default(false).describe(description);
|
|
23
10
|
}
|
|
11
|
+
const SuccessFlagSchema = z.literal(true);
|
|
12
|
+
const NonNegativeIntegerSchema = z.int().min(0, 'Min: 0');
|
|
13
|
+
const PositiveIntegerSchema = z.int().min(1, 'Min: 1');
|
|
14
|
+
const IsoDateTimeSchema = z.iso.datetime();
|
|
15
|
+
const Sha256HexSchema = z
|
|
16
|
+
.string()
|
|
17
|
+
.regex(/^[a-f0-9]{64}$/u, 'Expected SHA-256 hex digest');
|
|
24
18
|
const PathSchemaBase = z
|
|
25
19
|
.string()
|
|
26
20
|
.max(MAX_PATH_LENGTH, `Path too long (max ${MAX_PATH_LENGTH} chars)`);
|
|
@@ -48,10 +42,6 @@ const ErrorSchema = z.strictObject({
|
|
|
48
42
|
path: z.string().optional().describe('Relevant path'),
|
|
49
43
|
suggestion: z.string().optional().describe('Fix suggestion'),
|
|
50
44
|
});
|
|
51
|
-
export const ToolErrorResponseSchema = z.strictObject({
|
|
52
|
-
ok: z.literal(false).describe('Operation failed'),
|
|
53
|
-
error: ErrorSchema.describe('Error details'),
|
|
54
|
-
});
|
|
55
45
|
const HeadLinesSchema = z
|
|
56
46
|
.int({ error: 'Must be integer' })
|
|
57
47
|
.min(1, 'Min: 1')
|
|
@@ -65,11 +55,12 @@ const TailLinesSchema = z
|
|
|
65
55
|
.optional()
|
|
66
56
|
.describe('Read last N lines');
|
|
67
57
|
const LineNumberSchema = z.int({ error: 'Must be integer' }).min(1, 'Min: 1');
|
|
68
|
-
function addReadRangeIssue(ctx, path, message) {
|
|
58
|
+
function addReadRangeIssue(ctx, input, path, message) {
|
|
69
59
|
ctx.addIssue({
|
|
70
60
|
code: 'custom',
|
|
71
61
|
path: [path],
|
|
72
62
|
message,
|
|
63
|
+
input,
|
|
73
64
|
});
|
|
74
65
|
}
|
|
75
66
|
const validateReadRange = (value, ctx) => {
|
|
@@ -78,18 +69,14 @@ const validateReadRange = (value, ctx) => {
|
|
|
78
69
|
const hasStart = value.startLine !== undefined;
|
|
79
70
|
const hasEnd = value.endLine !== undefined;
|
|
80
71
|
if (hasHead && (hasStart || hasEnd)) {
|
|
81
|
-
addReadRangeIssue(ctx, 'head', "Cannot use 'head' with 'startLine'/'endLine'");
|
|
72
|
+
addReadRangeIssue(ctx, value, 'head', "Cannot use 'head' with 'startLine'/'endLine'");
|
|
82
73
|
}
|
|
83
74
|
if (hasTail && (hasHead || hasStart || hasEnd)) {
|
|
84
|
-
addReadRangeIssue(ctx, 'tail', "Cannot use 'tail' with 'head'/'startLine'/'endLine'");
|
|
75
|
+
addReadRangeIssue(ctx, value, 'tail', "Cannot use 'tail' with 'head'/'startLine'/'endLine'");
|
|
85
76
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if (value.startLine !== undefined &&
|
|
90
|
-
value.endLine !== undefined &&
|
|
91
|
-
value.endLine < value.startLine) {
|
|
92
|
-
addReadRangeIssue(ctx, 'endLine', "'endLine' must be >= 'startLine'");
|
|
77
|
+
const effectiveStart = value.startLine ?? 1;
|
|
78
|
+
if (value.endLine !== undefined && value.endLine < effectiveStart) {
|
|
79
|
+
addReadRangeIssue(ctx, value, 'endLine', "'endLine' must be >= 'startLine'");
|
|
93
80
|
}
|
|
94
81
|
};
|
|
95
82
|
function createReadRangeInputFields(descriptions) {
|
|
@@ -104,20 +91,20 @@ const FileInfoSchema = z.strictObject({
|
|
|
104
91
|
name: z.string().describe('Name'),
|
|
105
92
|
path: z.string().describe('Absolute path'),
|
|
106
93
|
type: FileTypeSchema.describe('Type'),
|
|
107
|
-
size:
|
|
108
|
-
tokenEstimate:
|
|
109
|
-
created:
|
|
110
|
-
modified:
|
|
111
|
-
accessed:
|
|
94
|
+
size: NonNegativeIntegerSchema.describe('Size (bytes)'),
|
|
95
|
+
tokenEstimate: NonNegativeIntegerSchema.optional().describe('Est. tokens (size/4)'),
|
|
96
|
+
created: IsoDateTimeSchema.describe('Created'),
|
|
97
|
+
modified: IsoDateTimeSchema.describe('Modified'),
|
|
98
|
+
accessed: IsoDateTimeSchema.describe('Accessed'),
|
|
112
99
|
permissions: z.string().describe('Permissions'),
|
|
113
100
|
isHidden: z.boolean().describe('Hidden?'),
|
|
114
101
|
mimeType: z.string().optional().describe('MIME type'),
|
|
115
102
|
symlinkTarget: z.string().optional().describe('Target (symlink)'),
|
|
116
103
|
});
|
|
117
104
|
const OperationSummarySchema = z.strictObject({
|
|
118
|
-
total:
|
|
119
|
-
succeeded:
|
|
120
|
-
failed:
|
|
105
|
+
total: NonNegativeIntegerSchema.describe('Total'),
|
|
106
|
+
succeeded: NonNegativeIntegerSchema.describe('Succeeded'),
|
|
107
|
+
failed: NonNegativeIntegerSchema.describe('Failed'),
|
|
121
108
|
});
|
|
122
109
|
export const ListDirectoryInputSchema = z.strictObject({
|
|
123
110
|
path: OptionalPathSchema.describe(DESC_PATH_ROOT),
|
|
@@ -143,6 +130,9 @@ export const ListDirectoryInputSchema = z.strictObject({
|
|
|
143
130
|
.string()
|
|
144
131
|
.min(1, 'Pattern required')
|
|
145
132
|
.max(1000, 'Max 1000 chars')
|
|
133
|
+
.refine((val) => isSafeGlobPattern(val), {
|
|
134
|
+
error: 'Invalid glob or unsafe path (absolute/.. forbidden)',
|
|
135
|
+
})
|
|
146
136
|
.optional()
|
|
147
137
|
.describe('Optional glob pattern filter (e.g. "**/*.ts")'),
|
|
148
138
|
includeSymlinkTargets: defaultFalseBoolean('Resolve and include symlink targets in results'),
|
|
@@ -240,7 +230,6 @@ export const SearchContentInputSchema = z.strictObject({
|
|
|
240
230
|
.describe('Glob for candidate files (e.g. "**/*.ts")'),
|
|
241
231
|
includeHidden: defaultFalseBoolean('Include hidden items (starting with .)'),
|
|
242
232
|
includeIgnored: defaultFalseBoolean('Include ignored items (node_modules, etc).'),
|
|
243
|
-
multiline: defaultFalseBoolean('Multi-line mode. ^ and $ match line boundaries when isRegex=true.'),
|
|
244
233
|
});
|
|
245
234
|
export const ReadFileInputSchema = z
|
|
246
235
|
.strictObject({
|
|
@@ -248,13 +237,13 @@ export const ReadFileInputSchema = z
|
|
|
248
237
|
...createReadRangeInputFields({
|
|
249
238
|
head: 'Read first N lines (preview)',
|
|
250
239
|
tail: 'Read last N lines',
|
|
251
|
-
startLine: 'Start line (1-based, inclusive)',
|
|
252
|
-
endLine: 'End line (1-based, inclusive).
|
|
240
|
+
startLine: 'Start line (1-based, inclusive). Defaults to 1 when endLine is set.',
|
|
241
|
+
endLine: 'End line (1-based, inclusive). Defaults to last line when startLine is set.',
|
|
253
242
|
}),
|
|
254
243
|
includeHash: defaultFalseBoolean('Include SHA-256 hash of full file content'),
|
|
255
244
|
})
|
|
256
245
|
.superRefine(validateReadRange)
|
|
257
|
-
.describe("Use one read mode only: 'head', 'tail', or 'startLine'/'endLine'.
|
|
246
|
+
.describe("Use one read mode only: 'head', 'tail', or 'startLine'/'endLine'.");
|
|
258
247
|
export const ReadMultipleFilesInputSchema = z
|
|
259
248
|
.strictObject({
|
|
260
249
|
paths: z
|
|
@@ -265,12 +254,12 @@ export const ReadMultipleFilesInputSchema = z
|
|
|
265
254
|
...createReadRangeInputFields({
|
|
266
255
|
head: 'Read first N lines of each file',
|
|
267
256
|
tail: 'Read last N lines of each file',
|
|
268
|
-
startLine: 'Start line (1-based, inclusive) per file',
|
|
269
|
-
endLine: 'End line (1-based, inclusive) per file.
|
|
257
|
+
startLine: 'Start line (1-based, inclusive) per file. Defaults to 1 when endLine is set.',
|
|
258
|
+
endLine: 'End line (1-based, inclusive) per file. Defaults to last line when startLine is set.',
|
|
270
259
|
}),
|
|
271
260
|
})
|
|
272
261
|
.superRefine(validateReadRange)
|
|
273
|
-
.describe("Use one read mode only: 'head', 'tail', or 'startLine'/'endLine'.
|
|
262
|
+
.describe("Use one read mode only: 'head', 'tail', or 'startLine'/'endLine'.");
|
|
274
263
|
export const GetFileInfoInputSchema = z.strictObject({
|
|
275
264
|
path: RequiredPathSchema.describe(DESC_PATH_REQUIRED),
|
|
276
265
|
});
|
|
@@ -282,62 +271,49 @@ export const GetMultipleFileInfoInputSchema = z.strictObject({
|
|
|
282
271
|
.describe('File/directory paths. e.g. ["src", "lib"]'),
|
|
283
272
|
});
|
|
284
273
|
export const ListAllowedDirectoriesOutputSchema = z.strictObject({
|
|
285
|
-
ok:
|
|
274
|
+
ok: SuccessFlagSchema,
|
|
286
275
|
directories: z.array(z.string()).optional().describe('Allowed directories'),
|
|
287
|
-
rootsCount: z.number().optional().describe('Number of roots'),
|
|
288
|
-
hasMultipleRoots: z
|
|
289
|
-
.boolean()
|
|
290
|
-
.optional()
|
|
291
|
-
.describe('Multiple roots configured'),
|
|
292
|
-
error: ErrorSchema.optional(),
|
|
293
276
|
});
|
|
294
277
|
export const ListDirectoryOutputSchema = z.strictObject({
|
|
295
|
-
ok:
|
|
278
|
+
ok: SuccessFlagSchema,
|
|
296
279
|
path: z.string().optional(),
|
|
297
280
|
entries: z
|
|
298
281
|
.array(z.strictObject({
|
|
299
282
|
name: z.string().describe('Entry name'),
|
|
300
283
|
relativePath: z.string().optional(),
|
|
301
284
|
type: FileTypeSchema,
|
|
302
|
-
size:
|
|
303
|
-
modified:
|
|
285
|
+
size: NonNegativeIntegerSchema.optional(),
|
|
286
|
+
modified: IsoDateTimeSchema.optional(),
|
|
304
287
|
}))
|
|
305
288
|
.optional(),
|
|
306
|
-
totalEntries:
|
|
289
|
+
totalEntries: NonNegativeIntegerSchema.optional(),
|
|
307
290
|
truncated: z.boolean().optional(),
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
totalFiles: z.number().optional(),
|
|
311
|
-
totalDirectories: z.number().optional(),
|
|
312
|
-
maxDepthReached: z.number().optional(),
|
|
291
|
+
totalFiles: NonNegativeIntegerSchema.optional(),
|
|
292
|
+
totalDirectories: NonNegativeIntegerSchema.optional(),
|
|
313
293
|
stoppedReason: ListDirectoryStopReasonSchema.optional(),
|
|
314
|
-
skippedInaccessible:
|
|
315
|
-
symlinksNotFollowed: z.number().optional(),
|
|
294
|
+
skippedInaccessible: NonNegativeIntegerSchema.optional(),
|
|
316
295
|
nextCursor: z
|
|
317
296
|
.string()
|
|
318
297
|
.optional()
|
|
319
298
|
.describe('Cursor for the next page; absent on the final page'),
|
|
320
|
-
error: ErrorSchema.optional(),
|
|
321
299
|
});
|
|
322
300
|
const SearchSummarySchema = z.strictObject({
|
|
323
|
-
totalMatches:
|
|
301
|
+
totalMatches: NonNegativeIntegerSchema.optional().describe('Total matches found'),
|
|
324
302
|
truncated: z.boolean().optional().describe('Results truncated?'),
|
|
325
303
|
resourceUri: z.string().optional().describe('Full results URI'),
|
|
326
|
-
error: ErrorSchema.optional(),
|
|
327
304
|
});
|
|
328
305
|
export const SearchFilesOutputSchema = SearchSummarySchema.extend({
|
|
329
|
-
ok:
|
|
306
|
+
ok: SuccessFlagSchema,
|
|
330
307
|
root: z.string().optional().describe('Search root'),
|
|
331
|
-
pattern: z.string().optional().describe('Glob pattern used'),
|
|
332
308
|
results: z
|
|
333
309
|
.array(z.strictObject({
|
|
334
310
|
path: z.string().describe('Relative path'),
|
|
335
|
-
size:
|
|
336
|
-
modified:
|
|
311
|
+
size: NonNegativeIntegerSchema.optional(),
|
|
312
|
+
modified: IsoDateTimeSchema.optional(),
|
|
337
313
|
}))
|
|
338
314
|
.optional(),
|
|
339
|
-
filesScanned:
|
|
340
|
-
skippedInaccessible:
|
|
315
|
+
filesScanned: NonNegativeIntegerSchema.optional().describe('Files scanned'),
|
|
316
|
+
skippedInaccessible: NonNegativeIntegerSchema.optional().describe('Inaccessible files'),
|
|
341
317
|
stoppedReason: SearchStopReasonSchema.optional().describe('Why search stopped'),
|
|
342
318
|
nextCursor: z
|
|
343
319
|
.string()
|
|
@@ -345,70 +321,49 @@ export const SearchFilesOutputSchema = SearchSummarySchema.extend({
|
|
|
345
321
|
.describe('Cursor for the next page; absent on the final page'),
|
|
346
322
|
});
|
|
347
323
|
export const SearchContentOutputSchema = SearchSummarySchema.extend({
|
|
348
|
-
ok:
|
|
349
|
-
patternType: z
|
|
350
|
-
.enum(['literal', 'regex'])
|
|
351
|
-
.optional()
|
|
352
|
-
.describe('Pattern interpretation'),
|
|
353
|
-
caseSensitive: z.boolean().optional().describe('Case-sensitive matching'),
|
|
324
|
+
ok: SuccessFlagSchema,
|
|
354
325
|
matches: z
|
|
355
326
|
.array(z.strictObject({
|
|
356
327
|
file: z.string().describe('Relative path'),
|
|
357
|
-
line:
|
|
358
|
-
column:
|
|
359
|
-
.number()
|
|
360
|
-
.optional()
|
|
361
|
-
.describe('Column of first match (0-based)'),
|
|
328
|
+
line: PositiveIntegerSchema,
|
|
329
|
+
column: NonNegativeIntegerSchema.optional().describe('Column of first match (0-based)'),
|
|
362
330
|
content: z.string(),
|
|
363
|
-
matchCount:
|
|
331
|
+
matchCount: PositiveIntegerSchema,
|
|
364
332
|
contextBefore: z.array(z.string()).optional(),
|
|
365
333
|
contextAfter: z.array(z.string()).optional(),
|
|
366
334
|
}))
|
|
367
335
|
.optional(),
|
|
368
|
-
filesScanned:
|
|
369
|
-
filesMatched:
|
|
370
|
-
skippedTooLarge:
|
|
371
|
-
skippedBinary:
|
|
372
|
-
skippedInaccessible:
|
|
373
|
-
.number()
|
|
374
|
-
.optional()
|
|
375
|
-
.describe('Files skipped: inaccessible'),
|
|
376
|
-
linesSkippedDueToRegexTimeout: z
|
|
377
|
-
.number()
|
|
378
|
-
.optional()
|
|
379
|
-
.describe('Lines skipped due to regex timeout'),
|
|
336
|
+
filesScanned: NonNegativeIntegerSchema.optional().describe('Files scanned'),
|
|
337
|
+
filesMatched: NonNegativeIntegerSchema.optional().describe('Files with matches'),
|
|
338
|
+
skippedTooLarge: NonNegativeIntegerSchema.optional().describe('Files skipped: too large'),
|
|
339
|
+
skippedBinary: NonNegativeIntegerSchema.optional().describe('Files skipped: binary'),
|
|
340
|
+
skippedInaccessible: NonNegativeIntegerSchema.optional().describe('Files skipped: inaccessible'),
|
|
380
341
|
stoppedReason: SearchStopReasonSchema.optional().describe('Why search stopped'),
|
|
381
342
|
});
|
|
382
343
|
export const TreeOutputSchema = z.strictObject({
|
|
383
|
-
ok:
|
|
344
|
+
ok: SuccessFlagSchema,
|
|
384
345
|
root: z.string().optional(),
|
|
385
346
|
tree: TreeEntrySchema.optional(),
|
|
386
347
|
ascii: z.string().optional(),
|
|
387
348
|
truncated: z.boolean().optional(),
|
|
388
|
-
totalEntries:
|
|
389
|
-
error: ErrorSchema.optional(),
|
|
349
|
+
totalEntries: NonNegativeIntegerSchema.optional(),
|
|
390
350
|
});
|
|
391
351
|
const ReadResultSchema = z.strictObject({
|
|
392
352
|
content: z.string().optional().describe('Content'),
|
|
393
353
|
truncated: z.boolean().optional().describe('Truncated?'),
|
|
394
354
|
resourceUri: z.string().optional().describe('Full content URI'),
|
|
395
|
-
totalLines:
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
tail: z.number().optional().describe('Tail lines'),
|
|
402
|
-
startLine: z.number().optional().describe('Start line'),
|
|
403
|
-
endLine: z.number().optional().describe('End line'),
|
|
404
|
-
linesRead: z.number().optional().describe('Lines read'),
|
|
355
|
+
totalLines: NonNegativeIntegerSchema.optional().describe('Total lines'),
|
|
356
|
+
head: PositiveIntegerSchema.optional().describe('Head lines'),
|
|
357
|
+
tail: PositiveIntegerSchema.optional().describe('Tail lines'),
|
|
358
|
+
startLine: PositiveIntegerSchema.optional().describe('Start line'),
|
|
359
|
+
endLine: PositiveIntegerSchema.optional().describe('End line'),
|
|
360
|
+
linesRead: NonNegativeIntegerSchema.optional().describe('Lines read'),
|
|
405
361
|
hasMoreLines: z.boolean().optional().describe('More lines?'),
|
|
406
362
|
});
|
|
407
363
|
export const ReadFileOutputSchema = ReadResultSchema.extend({
|
|
408
|
-
ok:
|
|
364
|
+
ok: SuccessFlagSchema,
|
|
409
365
|
path: z.string().optional(),
|
|
410
|
-
contentHash:
|
|
411
|
-
error: ErrorSchema.optional(),
|
|
366
|
+
contentHash: Sha256HexSchema.optional().describe('SHA-256 of full file content'),
|
|
412
367
|
});
|
|
413
368
|
const ReadMultipleFileResultSchema = ReadResultSchema.extend({
|
|
414
369
|
path: z.string().describe('File path'),
|
|
@@ -416,60 +371,77 @@ const ReadMultipleFileResultSchema = ReadResultSchema.extend({
|
|
|
416
371
|
.enum(['head', 'tail', 'range', 'externalized'])
|
|
417
372
|
.optional()
|
|
418
373
|
.describe('Why content was truncated'),
|
|
419
|
-
|
|
420
|
-
error: z.string().optional().describe('Error message'),
|
|
374
|
+
error: ErrorSchema.optional().describe('Structured error details'),
|
|
421
375
|
});
|
|
422
376
|
export const ReadMultipleFilesOutputSchema = z.strictObject({
|
|
423
|
-
ok:
|
|
377
|
+
ok: SuccessFlagSchema,
|
|
424
378
|
results: z.array(ReadMultipleFileResultSchema).optional(),
|
|
425
379
|
summary: OperationSummarySchema.optional(),
|
|
426
|
-
error: ErrorSchema.optional(),
|
|
427
380
|
});
|
|
428
381
|
export const GetFileInfoOutputSchema = z.strictObject({
|
|
429
|
-
ok:
|
|
382
|
+
ok: SuccessFlagSchema,
|
|
430
383
|
info: FileInfoSchema.optional(),
|
|
431
|
-
error: ErrorSchema.optional(),
|
|
432
384
|
});
|
|
433
385
|
export const GetMultipleFileInfoOutputSchema = z.strictObject({
|
|
434
|
-
ok:
|
|
386
|
+
ok: SuccessFlagSchema,
|
|
435
387
|
results: z
|
|
436
388
|
.array(z.strictObject({
|
|
437
389
|
path: z.string(),
|
|
438
390
|
info: FileInfoSchema.optional(),
|
|
439
|
-
error:
|
|
391
|
+
error: ErrorSchema.optional(),
|
|
440
392
|
}))
|
|
441
393
|
.optional(),
|
|
442
394
|
summary: OperationSummarySchema.optional(),
|
|
443
|
-
error: ErrorSchema.optional(),
|
|
444
395
|
});
|
|
445
396
|
export const CreateDirectoryInputSchema = z
|
|
446
397
|
.strictObject({
|
|
447
398
|
path: RequiredPathSchema.optional().describe(DESC_PATH_REQUIRED),
|
|
448
399
|
paths: z
|
|
449
400
|
.array(RequiredPathSchema)
|
|
401
|
+
.min(1, 'Min 1 path required')
|
|
450
402
|
.optional()
|
|
451
403
|
.describe('Absolute paths to directories to create'),
|
|
452
404
|
})
|
|
453
|
-
.
|
|
454
|
-
|
|
455
|
-
|
|
405
|
+
.superRefine((data, ctx) => {
|
|
406
|
+
const hasPath = data.path !== undefined;
|
|
407
|
+
const hasPaths = data.paths !== undefined;
|
|
408
|
+
if (!hasPath && !hasPaths) {
|
|
409
|
+
ctx.addIssue({
|
|
410
|
+
code: 'custom',
|
|
411
|
+
path: ['path'],
|
|
412
|
+
message: "Either 'path' or 'paths' must be provided",
|
|
413
|
+
input: data,
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
if (hasPath && hasPaths) {
|
|
417
|
+
ctx.addIssue({
|
|
418
|
+
code: 'custom',
|
|
419
|
+
path: ['path'],
|
|
420
|
+
message: "Provide either 'path' or 'paths', not both",
|
|
421
|
+
input: data,
|
|
422
|
+
});
|
|
423
|
+
ctx.addIssue({
|
|
424
|
+
code: 'custom',
|
|
425
|
+
path: ['paths'],
|
|
426
|
+
message: "Provide either 'path' or 'paths', not both",
|
|
427
|
+
input: data,
|
|
428
|
+
});
|
|
429
|
+
}
|
|
456
430
|
})
|
|
457
431
|
.describe("Provide either 'path' or 'paths'.");
|
|
458
432
|
export const CreateDirectoryOutputSchema = z.strictObject({
|
|
459
|
-
ok:
|
|
433
|
+
ok: SuccessFlagSchema,
|
|
460
434
|
path: z.string().optional(),
|
|
461
435
|
paths: z.array(z.string()).optional(),
|
|
462
|
-
error: ErrorSchema.optional(),
|
|
463
436
|
});
|
|
464
437
|
export const WriteFileInputSchema = z.strictObject({
|
|
465
438
|
path: RequiredPathSchema.describe(DESC_PATH_REQUIRED),
|
|
466
439
|
content: z.string().describe('Content to write'),
|
|
467
440
|
});
|
|
468
441
|
export const WriteFileOutputSchema = z.strictObject({
|
|
469
|
-
ok:
|
|
442
|
+
ok: SuccessFlagSchema,
|
|
470
443
|
path: z.string().optional(),
|
|
471
|
-
bytesWritten:
|
|
472
|
-
error: ErrorSchema.optional(),
|
|
444
|
+
bytesWritten: NonNegativeIntegerSchema.optional(),
|
|
473
445
|
});
|
|
474
446
|
export const EditFileInputSchema = z.strictObject({
|
|
475
447
|
path: RequiredPathSchema.describe(DESC_PATH_REQUIRED),
|
|
@@ -490,11 +462,11 @@ export const EditFileInputSchema = z.strictObject({
|
|
|
490
462
|
export const EditFileOutputSchema = z.strictObject({
|
|
491
463
|
ok: z.boolean(),
|
|
492
464
|
path: z.string().optional(),
|
|
493
|
-
appliedEdits:
|
|
494
|
-
linesAdded:
|
|
495
|
-
linesRemoved:
|
|
465
|
+
appliedEdits: NonNegativeIntegerSchema.optional(),
|
|
466
|
+
linesAdded: NonNegativeIntegerSchema.optional().describe('Lines added'),
|
|
467
|
+
linesRemoved: NonNegativeIntegerSchema.optional().describe('Lines removed'),
|
|
496
468
|
lineRange: z
|
|
497
|
-
.tuple([
|
|
469
|
+
.tuple([PositiveIntegerSchema, PositiveIntegerSchema])
|
|
498
470
|
.optional()
|
|
499
471
|
.describe('Line range modified [start, end] (1-based)'),
|
|
500
472
|
unmatchedEdits: z
|
|
@@ -502,17 +474,42 @@ export const EditFileOutputSchema = z.strictObject({
|
|
|
502
474
|
.optional()
|
|
503
475
|
.describe('Edits that could not be applied'),
|
|
504
476
|
diff: z.string().optional().describe('Unified diff of changes (dryRun)'),
|
|
505
|
-
error: ErrorSchema.optional(),
|
|
506
477
|
});
|
|
507
478
|
export const MoveFileInputSchema = z
|
|
508
479
|
.strictObject({
|
|
509
480
|
source: RequiredPathSchema.optional().describe('Path to move (deprecated: use sources)'),
|
|
510
|
-
sources: z
|
|
481
|
+
sources: z
|
|
482
|
+
.array(RequiredPathSchema)
|
|
483
|
+
.min(1, 'Min 1 source required')
|
|
484
|
+
.optional()
|
|
485
|
+
.describe('Paths to move'),
|
|
511
486
|
destination: RequiredPathSchema.describe('New path'),
|
|
512
487
|
})
|
|
513
|
-
.
|
|
514
|
-
|
|
515
|
-
|
|
488
|
+
.superRefine((data, ctx) => {
|
|
489
|
+
const hasSource = data.source !== undefined;
|
|
490
|
+
const hasSources = data.sources !== undefined;
|
|
491
|
+
if (!hasSource && !hasSources) {
|
|
492
|
+
ctx.addIssue({
|
|
493
|
+
code: 'custom',
|
|
494
|
+
path: ['source'],
|
|
495
|
+
message: "Either 'source' or 'sources' must be provided",
|
|
496
|
+
input: data,
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
if (hasSource && hasSources) {
|
|
500
|
+
ctx.addIssue({
|
|
501
|
+
code: 'custom',
|
|
502
|
+
path: ['source'],
|
|
503
|
+
message: "Provide either 'source' or 'sources', not both",
|
|
504
|
+
input: data,
|
|
505
|
+
});
|
|
506
|
+
ctx.addIssue({
|
|
507
|
+
code: 'custom',
|
|
508
|
+
path: ['sources'],
|
|
509
|
+
message: "Provide either 'source' or 'sources', not both",
|
|
510
|
+
input: data,
|
|
511
|
+
});
|
|
512
|
+
}
|
|
516
513
|
})
|
|
517
514
|
.describe("Provide either 'source' or 'sources'.");
|
|
518
515
|
export const MoveFileOutputSchema = z.strictObject({
|
|
@@ -523,11 +520,10 @@ export const MoveFileOutputSchema = z.strictObject({
|
|
|
523
520
|
failed: z
|
|
524
521
|
.array(z.strictObject({
|
|
525
522
|
source: z.string().describe('Source path'),
|
|
526
|
-
error:
|
|
523
|
+
error: ErrorSchema.describe('Structured error details'),
|
|
527
524
|
}))
|
|
528
525
|
.optional()
|
|
529
526
|
.describe('List of files that failed to move'),
|
|
530
|
-
error: ErrorSchema.optional(),
|
|
531
527
|
});
|
|
532
528
|
export const DeleteFileInputSchema = z.strictObject({
|
|
533
529
|
path: RequiredPathSchema.describe(DESC_PATH_REQUIRED),
|
|
@@ -535,23 +531,18 @@ export const DeleteFileInputSchema = z.strictObject({
|
|
|
535
531
|
ignoreIfNotExists: defaultFalseBoolean('No error if missing'),
|
|
536
532
|
});
|
|
537
533
|
export const DeleteFileOutputSchema = z.strictObject({
|
|
538
|
-
ok:
|
|
534
|
+
ok: SuccessFlagSchema,
|
|
539
535
|
path: z.string().optional(),
|
|
540
|
-
error: ErrorSchema.optional(),
|
|
541
536
|
});
|
|
542
537
|
export const CalculateHashInputSchema = z.strictObject({
|
|
543
538
|
path: RequiredPathSchema.describe(DESC_PATH_REQUIRED),
|
|
544
539
|
});
|
|
545
540
|
export const CalculateHashOutputSchema = z.strictObject({
|
|
546
|
-
ok:
|
|
541
|
+
ok: SuccessFlagSchema,
|
|
547
542
|
path: z.string().optional(),
|
|
548
|
-
hash:
|
|
543
|
+
hash: Sha256HexSchema.optional().describe('SHA-256 hash'),
|
|
549
544
|
isDirectory: z.boolean().optional().describe('True if path is a directory'),
|
|
550
|
-
fileCount:
|
|
551
|
-
.number()
|
|
552
|
-
.optional()
|
|
553
|
-
.describe('Number of files hashed (directories only)'),
|
|
554
|
-
error: ErrorSchema.optional(),
|
|
545
|
+
fileCount: NonNegativeIntegerSchema.optional().describe('Number of files hashed (directories only)'),
|
|
555
546
|
});
|
|
556
547
|
export const DiffFilesInputSchema = z.strictObject({
|
|
557
548
|
original: RequiredPathSchema.describe('Path to original file'),
|
|
@@ -574,15 +565,14 @@ export const DiffFilesInputSchema = z.strictObject({
|
|
|
574
565
|
.describe('Strip trailing carriage returns before diffing'),
|
|
575
566
|
});
|
|
576
567
|
export const DiffFilesOutputSchema = z.strictObject({
|
|
577
|
-
ok:
|
|
568
|
+
ok: SuccessFlagSchema,
|
|
578
569
|
diff: z.string().optional().describe('Unified diff content'),
|
|
579
570
|
isIdentical: z.boolean().optional().describe('True if files are identical'),
|
|
580
|
-
linesAdded:
|
|
581
|
-
linesRemoved:
|
|
582
|
-
hunksCount:
|
|
571
|
+
linesAdded: NonNegativeIntegerSchema.optional().describe('Lines added'),
|
|
572
|
+
linesRemoved: NonNegativeIntegerSchema.optional().describe('Lines removed'),
|
|
573
|
+
hunksCount: NonNegativeIntegerSchema.optional().describe('Number of diff hunks'),
|
|
583
574
|
truncated: z.boolean().optional().describe('Diff content truncated?'),
|
|
584
575
|
resourceUri: z.string().optional().describe('Full diff content URI'),
|
|
585
|
-
error: ErrorSchema.optional(),
|
|
586
576
|
});
|
|
587
577
|
export const ApplyPatchInputSchema = z.strictObject({
|
|
588
578
|
path: RequiredPathSchema.describe('Path to file to patch'),
|
|
@@ -614,21 +604,20 @@ export const ApplyPatchOutputSchema = z.strictObject({
|
|
|
614
604
|
ok: z.boolean(),
|
|
615
605
|
path: z.string().optional(),
|
|
616
606
|
applied: z.boolean().optional(),
|
|
617
|
-
hunksApplied:
|
|
618
|
-
linesAdded:
|
|
619
|
-
linesRemoved:
|
|
607
|
+
hunksApplied: NonNegativeIntegerSchema.optional().describe('Hunks applied'),
|
|
608
|
+
linesAdded: NonNegativeIntegerSchema.optional().describe('Lines added'),
|
|
609
|
+
linesRemoved: NonNegativeIntegerSchema.optional().describe('Lines removed'),
|
|
620
610
|
results: z
|
|
621
611
|
.array(z.strictObject({
|
|
622
612
|
path: z.string().describe('File path'),
|
|
623
613
|
applied: z.boolean().describe('Patch applied successfully'),
|
|
624
|
-
hunksApplied:
|
|
625
|
-
linesAdded:
|
|
626
|
-
linesRemoved:
|
|
627
|
-
error:
|
|
614
|
+
hunksApplied: NonNegativeIntegerSchema.optional().describe('Hunks applied'),
|
|
615
|
+
linesAdded: NonNegativeIntegerSchema.optional().describe('Lines added'),
|
|
616
|
+
linesRemoved: NonNegativeIntegerSchema.optional().describe('Lines removed'),
|
|
617
|
+
error: ErrorSchema.optional().describe('Structured error details'),
|
|
628
618
|
}))
|
|
629
619
|
.optional()
|
|
630
620
|
.describe('Per-file results for multi-file patches'),
|
|
631
|
-
error: ErrorSchema.optional(),
|
|
632
621
|
});
|
|
633
622
|
export const SearchAndReplaceInputSchema = z.strictObject({
|
|
634
623
|
path: OptionalPathSchema.describe(DESC_PATH_ROOT),
|
|
@@ -675,22 +664,22 @@ export const SearchAndReplaceInputSchema = z.strictObject({
|
|
|
675
664
|
.describe('Max files to process before stopping'),
|
|
676
665
|
});
|
|
677
666
|
export const SearchAndReplaceOutputSchema = z.strictObject({
|
|
678
|
-
ok:
|
|
679
|
-
matches:
|
|
680
|
-
filesChanged:
|
|
681
|
-
processedFiles:
|
|
682
|
-
failedFiles:
|
|
667
|
+
ok: SuccessFlagSchema,
|
|
668
|
+
matches: NonNegativeIntegerSchema.optional().describe('Total matches found'),
|
|
669
|
+
filesChanged: NonNegativeIntegerSchema.optional().describe('Files modified'),
|
|
670
|
+
processedFiles: NonNegativeIntegerSchema.optional().describe('Files processed'),
|
|
671
|
+
failedFiles: NonNegativeIntegerSchema.optional().describe('Files skipped due to errors'),
|
|
683
672
|
failures: z
|
|
684
673
|
.array(z.strictObject({
|
|
685
674
|
path: z.string().describe('File path'),
|
|
686
|
-
error:
|
|
675
|
+
error: ErrorSchema.describe('Structured error details'),
|
|
687
676
|
}))
|
|
688
677
|
.optional()
|
|
689
678
|
.describe('Sample of per-file errors'),
|
|
690
679
|
changedFiles: z
|
|
691
680
|
.array(z.strictObject({
|
|
692
681
|
path: z.string().describe('File path'),
|
|
693
|
-
matches:
|
|
682
|
+
matches: PositiveIntegerSchema.describe('Matches in file'),
|
|
694
683
|
}))
|
|
695
684
|
.optional()
|
|
696
685
|
.describe('Sample of changed files'),
|
|
@@ -707,6 +696,4 @@ export const SearchAndReplaceOutputSchema = z.strictObject({
|
|
|
707
696
|
.enum(['maxFiles'])
|
|
708
697
|
.optional()
|
|
709
698
|
.describe('Why processing stopped early'),
|
|
710
|
-
dryRun: z.boolean().optional(),
|
|
711
|
-
error: ErrorSchema.optional(),
|
|
712
699
|
});
|
|
@@ -5,20 +5,10 @@ export interface ServerOptions {
|
|
|
5
5
|
allowCwd?: boolean;
|
|
6
6
|
cliAllowedDirs?: string[];
|
|
7
7
|
}
|
|
8
|
-
interface CapabilityOptions {
|
|
9
|
-
enablePromptListChanged?: boolean;
|
|
10
|
-
enableTaskToolRequests?: boolean;
|
|
11
|
-
}
|
|
12
|
-
type ServerCapabilities = NonNullable<ConstructorParameters<typeof McpServer>[1]>['capabilities'];
|
|
13
|
-
type NonOptionalServerCapabilities = NonNullable<ServerCapabilities>;
|
|
14
|
-
export declare function buildServerCapabilities(options?: CapabilityOptions): NonOptionalServerCapabilities;
|
|
15
|
-
export declare function supportsTaskToolRequests(): boolean;
|
|
16
8
|
export interface LoggingState {
|
|
17
9
|
minimumLevel: LoggingLevel;
|
|
18
10
|
}
|
|
19
|
-
export declare function createLoggingState(minimumLevel?: LoggingLevel): LoggingState;
|
|
20
11
|
export declare function logToMcp(server: McpServer | undefined, level: LoggingLevel, data: string, minLevel?: LoggingLevel): void;
|
|
21
12
|
export declare function createServer(options?: ServerOptions): Promise<McpServer>;
|
|
22
13
|
export declare function startServer(server: McpServer): Promise<void>;
|
|
23
14
|
export declare function startHttpServer(port: number, options: ServerOptions): Promise<http.Server>;
|
|
24
|
-
export {};
|
package/dist/server/bootstrap.js
CHANGED
|
@@ -41,7 +41,7 @@ function detectTaskToolSupport() {
|
|
|
41
41
|
}
|
|
42
42
|
return cachedTaskToolSupport;
|
|
43
43
|
}
|
|
44
|
-
|
|
44
|
+
function buildServerCapabilities(options = {}) {
|
|
45
45
|
const capabilities = {
|
|
46
46
|
logging: {},
|
|
47
47
|
resources: {},
|
|
@@ -61,7 +61,7 @@ export function buildServerCapabilities(options = {}) {
|
|
|
61
61
|
}
|
|
62
62
|
return capabilities;
|
|
63
63
|
}
|
|
64
|
-
|
|
64
|
+
function supportsTaskToolRequests() {
|
|
65
65
|
return detectTaskToolSupport();
|
|
66
66
|
}
|
|
67
67
|
const MCP_LOGGER_NAME = 'filesystem-mcp';
|
|
@@ -75,7 +75,7 @@ const LOG_LEVEL_ORDER = {
|
|
|
75
75
|
alert: 6,
|
|
76
76
|
emergency: 7,
|
|
77
77
|
};
|
|
78
|
-
|
|
78
|
+
function createLoggingState(minimumLevel = 'debug') {
|
|
79
79
|
return { minimumLevel };
|
|
80
80
|
}
|
|
81
81
|
function canSendMcpLogs(server) {
|