@j0hanz/filesystem-mcp 1.3.2 → 1.4.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/dist/completions.js +12 -0
- package/dist/lib/resource-store.d.ts +1 -0
- package/dist/lib/resource-store.js +4 -1
- package/dist/tools/contract.d.ts +4 -0
- package/dist/tools/read-multiple.js +1 -0
- package/dist/tools/replace-in-files.js +1 -0
- package/dist/tools/search-content.js +1 -0
- package/dist/tools/search-files.js +1 -0
- package/dist/tools/shared.js +57 -35
- package/dist/tools/stat-many.js +1 -0
- package/dist/tools/task-support.js +6 -1
- package/dist/tools/tree.js +1 -0
- package/package.json +1 -1
package/dist/completions.js
CHANGED
|
@@ -7,6 +7,7 @@ import { isRecord } from './lib/type-guards.js';
|
|
|
7
7
|
const MAX_COMPLETION_ITEMS = 100;
|
|
8
8
|
const COMPLETION_RATE_LIMIT_MS = 100;
|
|
9
9
|
const completionLastCallMs = new Map();
|
|
10
|
+
const completionLastResult = new Map();
|
|
10
11
|
function extractTopicCompletions(instructions) {
|
|
11
12
|
const headers = [];
|
|
12
13
|
for (const line of instructions.split('\n')) {
|
|
@@ -394,6 +395,16 @@ export function registerCompletions(server, instructions = '') {
|
|
|
394
395
|
const now = Date.now();
|
|
395
396
|
const lastCallMs = completionLastCallMs.get(argName) ?? 0;
|
|
396
397
|
if (now - lastCallMs < COMPLETION_RATE_LIMIT_MS) {
|
|
398
|
+
const lastResult = completionLastResult.get(argName);
|
|
399
|
+
if (lastResult) {
|
|
400
|
+
return {
|
|
401
|
+
completion: {
|
|
402
|
+
values: lastResult.values,
|
|
403
|
+
total: lastResult.total,
|
|
404
|
+
hasMore: lastResult.hasMore,
|
|
405
|
+
},
|
|
406
|
+
};
|
|
407
|
+
}
|
|
397
408
|
return { completion: { values: [], total: 0, hasMore: false } };
|
|
398
409
|
}
|
|
399
410
|
completionLastCallMs.set(argName, now);
|
|
@@ -403,6 +414,7 @@ export function registerCompletions(server, instructions = '') {
|
|
|
403
414
|
argumentName: argName,
|
|
404
415
|
...(contextArguments ? { contextArguments } : {}),
|
|
405
416
|
});
|
|
417
|
+
completionLastResult.set(argName, completions);
|
|
406
418
|
return {
|
|
407
419
|
completion: {
|
|
408
420
|
values: completions.values,
|
|
@@ -147,5 +147,8 @@ export function createInMemoryResourceStore(options = {}) {
|
|
|
147
147
|
bytes: bytesBeforeClear,
|
|
148
148
|
});
|
|
149
149
|
}
|
|
150
|
-
|
|
150
|
+
function keys() {
|
|
151
|
+
return Array.from(byUri.keys());
|
|
152
|
+
}
|
|
153
|
+
return { putText, getText, clear, keys };
|
|
151
154
|
}
|
package/dist/tools/contract.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export const READ_MULTIPLE_FILES_TOOL = {
|
|
|
14
14
|
inputSchema: ReadMultipleFilesInputSchema,
|
|
15
15
|
outputSchema: ReadMultipleFilesOutputSchema,
|
|
16
16
|
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
17
|
+
taskSupport: 'required',
|
|
17
18
|
nuances: ['Total read budget is capped by `MAX_READ_MANY_TOTAL_SIZE`.'],
|
|
18
19
|
gotchas: [
|
|
19
20
|
'Per-file `truncationReason` can be `head`, `range`, or `externalized`.',
|
|
@@ -23,6 +23,7 @@ export const SEARCH_AND_REPLACE_TOOL = {
|
|
|
23
23
|
inputSchema: SearchAndReplaceInputSchema,
|
|
24
24
|
outputSchema: SearchAndReplaceOutputSchema,
|
|
25
25
|
annotations: DESTRUCTIVE_WRITE_TOOL_ANNOTATIONS,
|
|
26
|
+
taskSupport: 'required',
|
|
26
27
|
gotchas: [
|
|
27
28
|
'Literal mode is default; `isRegex=true` enables RE2 + capture replacements (`$1`, `$2`).',
|
|
28
29
|
],
|
|
@@ -38,6 +38,7 @@ export const SEARCH_FILES_TOOL = {
|
|
|
38
38
|
'Respects `.gitignore` unless `includeIgnored=true`.',
|
|
39
39
|
'Returns relative paths plus metadata; may truncate.',
|
|
40
40
|
],
|
|
41
|
+
taskSupport: 'required',
|
|
41
42
|
};
|
|
42
43
|
async function handleSearchFiles(args, signal, onProgress) {
|
|
43
44
|
const basePath = resolvePathOrRoot(args.path);
|
package/dist/tools/shared.js
CHANGED
|
@@ -125,6 +125,11 @@ function canSendProgress(extra) {
|
|
|
125
125
|
return (extra._meta?.progressToken !== undefined &&
|
|
126
126
|
extra.sendNotification !== undefined);
|
|
127
127
|
}
|
|
128
|
+
function canReportProgress(extra) {
|
|
129
|
+
const taskExtra = extra;
|
|
130
|
+
const hasTask = taskExtra.taskId !== undefined && taskExtra.taskStore !== undefined;
|
|
131
|
+
return canSendProgress(extra) || hasTask;
|
|
132
|
+
}
|
|
128
133
|
export function withDefaultIcons(tool, iconInfo) {
|
|
129
134
|
if (!iconInfo) {
|
|
130
135
|
return maybeStripOutputSchema(tool);
|
|
@@ -216,25 +221,53 @@ export function buildToolErrorResponse(error, defaultCode, path) {
|
|
|
216
221
|
function buildNotInitializedResult() {
|
|
217
222
|
return buildToolErrorResponse(NOT_INITIALIZED_ERROR, ErrorCode.E_INVALID_INPUT);
|
|
218
223
|
}
|
|
219
|
-
async function
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
224
|
+
async function reportProgress(extra, progress) {
|
|
225
|
+
const taskExtra = extra;
|
|
226
|
+
if (typeof taskExtra.taskId === 'string' &&
|
|
227
|
+
taskExtra.taskStore !== undefined &&
|
|
228
|
+
taskExtra.taskStore !== null) {
|
|
229
|
+
const store = taskExtra.taskStore;
|
|
230
|
+
if (typeof store.updateTaskStatus === 'function') {
|
|
231
|
+
try {
|
|
232
|
+
let statusMessage = progress.message;
|
|
233
|
+
if (progress.total !== undefined) {
|
|
234
|
+
statusMessage = statusMessage
|
|
235
|
+
? `${statusMessage} (${progress.current}/${progress.total})`
|
|
236
|
+
: `${progress.current}/${progress.total}`;
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
statusMessage ??= `${progress.current}`;
|
|
240
|
+
}
|
|
241
|
+
await store.updateTaskStatus(taskExtra.taskId, 'working', statusMessage);
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
console.error('Failed to update task status message:', error);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
227
247
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
248
|
+
if (canSendProgress(extra)) {
|
|
249
|
+
try {
|
|
250
|
+
await extra.sendNotification({
|
|
251
|
+
method: 'notifications/progress',
|
|
252
|
+
params: {
|
|
253
|
+
progressToken: extra._meta.progressToken,
|
|
254
|
+
progress: progress.current,
|
|
255
|
+
...(progress.total !== undefined ? { total: progress.total } : {}),
|
|
256
|
+
...(progress.message !== undefined
|
|
257
|
+
? { message: progress.message }
|
|
258
|
+
: {}),
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
console.error('Failed to send progress notification:', error);
|
|
264
|
+
}
|
|
231
265
|
}
|
|
232
266
|
}
|
|
233
267
|
export function createProgressReporter(extra) {
|
|
234
|
-
if (!
|
|
268
|
+
if (!canReportProgress(extra)) {
|
|
235
269
|
return () => { };
|
|
236
270
|
}
|
|
237
|
-
const token = extra._meta.progressToken;
|
|
238
271
|
// State for monotonic enforcement and rate-limiting.
|
|
239
272
|
let lastProgress = -1;
|
|
240
273
|
let lastSentMs = 0;
|
|
@@ -251,52 +284,41 @@ export function createProgressReporter(extra) {
|
|
|
251
284
|
return;
|
|
252
285
|
lastProgress = current;
|
|
253
286
|
lastSentMs = now;
|
|
254
|
-
void
|
|
255
|
-
|
|
256
|
-
progress: current,
|
|
287
|
+
void reportProgress(extra, {
|
|
288
|
+
current,
|
|
257
289
|
...(total !== undefined ? { total } : {}),
|
|
258
290
|
...(message !== undefined ? { message } : {}),
|
|
259
291
|
});
|
|
260
292
|
};
|
|
261
293
|
}
|
|
262
294
|
export function notifyProgress(extra, progress) {
|
|
263
|
-
if (!
|
|
295
|
+
if (!canReportProgress(extra))
|
|
264
296
|
return;
|
|
265
|
-
|
|
266
|
-
void sendProgressNotification(extra, {
|
|
267
|
-
progressToken: token,
|
|
268
|
-
progress: progress.current,
|
|
269
|
-
...(progress.total !== undefined ? { total: progress.total } : {}),
|
|
270
|
-
...(progress.message !== undefined ? { message: progress.message } : {}),
|
|
271
|
-
});
|
|
297
|
+
void reportProgress(extra, progress);
|
|
272
298
|
}
|
|
273
299
|
async function withProgress(message, extra, run, getCompletionMessage) {
|
|
274
|
-
if (!
|
|
300
|
+
if (!canReportProgress(extra)) {
|
|
275
301
|
return run();
|
|
276
302
|
}
|
|
277
|
-
const token = extra._meta.progressToken;
|
|
278
303
|
const total = 1;
|
|
279
|
-
await
|
|
280
|
-
|
|
281
|
-
progress: 0,
|
|
304
|
+
await reportProgress(extra, {
|
|
305
|
+
current: 0,
|
|
282
306
|
total,
|
|
283
307
|
message,
|
|
284
308
|
});
|
|
285
309
|
try {
|
|
286
310
|
const result = await run();
|
|
287
311
|
const endMessage = getCompletionMessage?.(result) ?? message;
|
|
288
|
-
await
|
|
289
|
-
|
|
290
|
-
progress: total,
|
|
312
|
+
await reportProgress(extra, {
|
|
313
|
+
current: total,
|
|
291
314
|
total,
|
|
292
315
|
message: endMessage,
|
|
293
316
|
});
|
|
294
317
|
return result;
|
|
295
318
|
}
|
|
296
319
|
catch (error) {
|
|
297
|
-
void
|
|
298
|
-
|
|
299
|
-
progress: total,
|
|
320
|
+
void reportProgress(extra, {
|
|
321
|
+
current: total,
|
|
300
322
|
total,
|
|
301
323
|
message: `${message} • failed`,
|
|
302
324
|
});
|
package/dist/tools/stat-many.js
CHANGED
|
@@ -13,6 +13,7 @@ export const GET_MULTIPLE_FILE_INFO_TOOL = {
|
|
|
13
13
|
inputSchema: GetMultipleFileInfoInputSchema,
|
|
14
14
|
outputSchema: GetMultipleFileInfoOutputSchema,
|
|
15
15
|
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
16
|
+
taskSupport: 'required',
|
|
16
17
|
nuances: ['Use before read/search when file size/type uncertainty exists.'],
|
|
17
18
|
};
|
|
18
19
|
function formatFileInfoDetail(info) {
|
|
@@ -304,7 +304,12 @@ export function tryRegisterToolTask(server, toolName, toolDef, taskHandler, icon
|
|
|
304
304
|
const tasks = getExperimentalTaskRegistration(server);
|
|
305
305
|
if (!tasks?.registerToolTask)
|
|
306
306
|
return false;
|
|
307
|
-
|
|
307
|
+
const def = toolDef;
|
|
308
|
+
const existingExecution = def.execution ?? {};
|
|
309
|
+
const taskSupport = def.taskSupport ??
|
|
310
|
+
existingExecution.taskSupport ??
|
|
311
|
+
'optional';
|
|
312
|
+
tasks.registerToolTask(toolName, withDefaultIcons({ ...toolDef, execution: { ...existingExecution, taskSupport } }, iconInfo), taskHandler);
|
|
308
313
|
return true;
|
|
309
314
|
}
|
|
310
315
|
export function registerToolTaskIfAvailable(server, toolName, toolDef, run, iconInfo, guard) {
|
package/dist/tools/tree.js
CHANGED
|
@@ -14,6 +14,7 @@ export const TREE_TOOL = {
|
|
|
14
14
|
inputSchema: TreeInputSchema,
|
|
15
15
|
outputSchema: TreeOutputSchema,
|
|
16
16
|
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
17
|
+
taskSupport: 'required',
|
|
17
18
|
gotchas: ['`maxDepth=0` returns only the root node.'],
|
|
18
19
|
};
|
|
19
20
|
async function handleTree(args, signal, onProgress) {
|