@j0hanz/filesystem-mcp 1.17.1 → 1.19.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/lib/constants.d.ts +3 -1
- package/dist/lib/constants.js +3 -1
- package/dist/lib/errors.d.ts +1 -0
- package/dist/lib/errors.js +1 -1
- package/dist/prompts.js +20 -0
- package/dist/resources.js +4 -5
- package/dist/server/bootstrap.js +11 -37
- package/dist/server/event-store.d.ts +18 -0
- package/dist/server/event-store.js +71 -0
- package/dist/server/task-store.d.ts +1 -0
- package/dist/server/task-store.js +23 -5
- package/dist/tools/apply-patch.js +7 -5
- package/dist/tools/calculate-hash.js +5 -5
- package/dist/tools/create-directory.js +5 -6
- package/dist/tools/delete-file.js +3 -3
- package/dist/tools/diff-files.js +5 -5
- package/dist/tools/edit-file.js +5 -5
- package/dist/tools/list-directory.js +3 -3
- package/dist/tools/move-file.js +5 -6
- package/dist/tools/read-multiple.js +14 -7
- package/dist/tools/read.js +2 -2
- package/dist/tools/replace-in-files.js +5 -5
- package/dist/tools/roots.js +3 -3
- package/dist/tools/search-content.js +5 -4
- package/dist/tools/search-files.js +5 -5
- package/dist/tools/shared.d.ts +15 -18
- package/dist/tools/shared.js +5 -17
- package/dist/tools/stat-many.js +7 -6
- package/dist/tools/stat.js +4 -4
- package/dist/tools/task-support.d.ts +5 -0
- package/dist/tools/task-support.js +57 -107
- package/dist/tools/tree.js +5 -5
- package/dist/tools/write-file.js +3 -3
- package/package.json +1 -1
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { basename } from 'node:path';
|
|
2
2
|
import { DEFAULT_SEARCH_TIMEOUT_MS } from '../lib/constants.js';
|
|
3
|
-
import { ErrorCode } from '../lib/errors.js';
|
|
3
|
+
import { classifyError, ErrorCode } from '../lib/errors.js';
|
|
4
4
|
import { readMultipleFiles } from '../lib/file-operations/metadata.js';
|
|
5
5
|
import { ReadMultipleFilesInputSchema, ReadMultipleFilesOutputSchema, } from '../schemas.js';
|
|
6
6
|
import { FILE_READ_ICONS } from './icons.js';
|
|
7
|
-
import {
|
|
8
|
-
import { registerStandardTool } from './task-support.js';
|
|
7
|
+
import { buildBatchPathContext, buildResourceLink, buildStructuredError, buildToolErrorResponse, buildToolResponse, createBatchProgressCallbacks, executeToolWithDiagnostics, maybeExternalizeTextContent, READ_ONLY_TOOL_ANNOTATIONS, resolveFinalProgressCurrent, } from './shared.js';
|
|
8
|
+
import { registerStandardTool, reportTaskStatus } from './task-support.js';
|
|
9
9
|
const READ_MANY_TOOL_NAME = 'read_many';
|
|
10
|
-
const READ_MANY_TOOL_LABEL = '🕮 read_many';
|
|
11
10
|
const FULL_FILE_CONTENTS_DESCRIPTION = 'Full file contents';
|
|
12
11
|
export const READ_MANY_TOOL = {
|
|
13
12
|
name: READ_MANY_TOOL_NAME,
|
|
@@ -20,6 +19,7 @@ export const READ_MANY_TOOL = {
|
|
|
20
19
|
icons: FILE_READ_ICONS,
|
|
21
20
|
taskSupport: 'optional',
|
|
22
21
|
};
|
|
22
|
+
const READ_MANY_TOOL_LABEL = READ_MANY_TOOL.title;
|
|
23
23
|
function buildReadManyResourceName(filePath) {
|
|
24
24
|
return `read:${basename(filePath)}`;
|
|
25
25
|
}
|
|
@@ -173,23 +173,30 @@ export function registerReadMultipleFilesTool(server, options = {}) {
|
|
|
173
173
|
context: { path: primaryPath },
|
|
174
174
|
run: async (signal) => {
|
|
175
175
|
const context = buildBatchPathContext(args.paths, 'files');
|
|
176
|
-
const { progress, onItemComplete } = createBatchProgressCallbacks(ctx, {
|
|
176
|
+
const { progress, onItemComplete: rawOnItemComplete } = createBatchProgressCallbacks(ctx, {
|
|
177
177
|
toolLabel: READ_MANY_TOOL_LABEL,
|
|
178
178
|
context,
|
|
179
179
|
totalItems: args.paths.length,
|
|
180
180
|
itemVerb: 'read',
|
|
181
181
|
});
|
|
182
|
+
let itemsDone = 0;
|
|
183
|
+
const onItemComplete = () => {
|
|
184
|
+
rawOnItemComplete();
|
|
185
|
+
itemsDone++;
|
|
186
|
+
void reportTaskStatus(`${READ_MANY_TOOL_LABEL}: ${context} [${itemsDone}/${args.paths.length} read]`);
|
|
187
|
+
};
|
|
182
188
|
try {
|
|
183
189
|
const result = await handleReadMultipleFiles(args, signal, options.resourceStore, onItemComplete);
|
|
184
190
|
const sc = result.structuredContent;
|
|
185
|
-
const suffix = buildBatchCompletionSuffix(sc.summary, 'files read', 'file read');
|
|
186
191
|
const total = sc.summary?.total ?? 0;
|
|
192
|
+
const failed = sc.summary?.failed ?? 0;
|
|
193
|
+
const suffix = failed ? `${failed} failed` : 'done';
|
|
187
194
|
const finalCurrent = resolveFinalProgressCurrent(progress, total);
|
|
188
195
|
progress.complete(`${READ_MANY_TOOL_LABEL}: ${context} • ${suffix}`, finalCurrent);
|
|
189
196
|
return result;
|
|
190
197
|
}
|
|
191
198
|
catch (error) {
|
|
192
|
-
progress.fail(`${READ_MANY_TOOL_LABEL}: ${context} •
|
|
199
|
+
progress.fail(`${READ_MANY_TOOL_LABEL}: ${context} • ${classifyError(error)}`);
|
|
193
200
|
throw error;
|
|
194
201
|
}
|
|
195
202
|
},
|
package/dist/tools/read.js
CHANGED
|
@@ -22,7 +22,7 @@ export const READ_FILE_TOOL = {
|
|
|
22
22
|
taskSupport: 'forbidden',
|
|
23
23
|
};
|
|
24
24
|
const READ_TOOL_NAME = 'read';
|
|
25
|
-
const READ_TOOL_LABEL =
|
|
25
|
+
const READ_TOOL_LABEL = READ_FILE_TOOL.title;
|
|
26
26
|
const FULL_FILE_CONTENTS_DESCRIPTION = 'Full file contents';
|
|
27
27
|
function buildReadResourceName(filePath) {
|
|
28
28
|
return `read:${basename(filePath)}`;
|
|
@@ -114,7 +114,7 @@ function buildReadProgressMessage(args) {
|
|
|
114
114
|
function buildReadCompletionMessage(args, result) {
|
|
115
115
|
const name = basename(args.path);
|
|
116
116
|
if (result.isError)
|
|
117
|
-
return `${READ_TOOL_LABEL}: ${name} •
|
|
117
|
+
return `${READ_TOOL_LABEL}: ${name} • ${result.errorCode}`;
|
|
118
118
|
const structured = result.structuredContent;
|
|
119
119
|
const lines = structured.linesRead ?? structured.totalLines;
|
|
120
120
|
if (structured.startLine !== undefined) {
|
|
@@ -4,7 +4,7 @@ import { basename, relative } from 'node:path';
|
|
|
4
4
|
import { createTwoFilesPatch } from 'diff';
|
|
5
5
|
import RE2 from 're2';
|
|
6
6
|
import { DEFAULT_EXCLUDE_PATTERNS, MAX_TEXT_FILE_SIZE, PARALLEL_CONCURRENCY, } from '../lib/constants.js';
|
|
7
|
-
import { ErrorCode, formatUnknownErrorMessage, McpError, } from '../lib/errors.js';
|
|
7
|
+
import { classifyError, ErrorCode, formatUnknownErrorMessage, McpError, } from '../lib/errors.js';
|
|
8
8
|
import { globEntries } from '../lib/file-operations/traversal.js';
|
|
9
9
|
import { atomicWriteFile } from '../lib/fs-helpers.js';
|
|
10
10
|
import { Logger } from '../lib/logger.js';
|
|
@@ -340,12 +340,12 @@ export function registerSearchAndReplaceTool(server, options = {}) {
|
|
|
340
340
|
const dryLabel = args.dryRun ? ' [dry run]' : '';
|
|
341
341
|
const truncatedPattern = truncateProgressPattern(args.searchPattern);
|
|
342
342
|
const context = `"${truncatedPattern}" in ${args.filePattern}${dryLabel}`;
|
|
343
|
-
const progress = createToolProgressSession(ctx,
|
|
343
|
+
const progress = createToolProgressSession(ctx, `${SEARCH_AND_REPLACE_TOOL.title}: ${context}`);
|
|
344
344
|
const progressWithMessage = ({ current, total, }) => {
|
|
345
345
|
progress.update({
|
|
346
346
|
current,
|
|
347
347
|
...(total !== undefined ? { total } : {}),
|
|
348
|
-
message:
|
|
348
|
+
message: `${SEARCH_AND_REPLACE_TOOL.title}: ${truncatedPattern} [${current} files]`,
|
|
349
349
|
});
|
|
350
350
|
};
|
|
351
351
|
try {
|
|
@@ -357,14 +357,14 @@ export function registerSearchAndReplaceTool(server, options = {}) {
|
|
|
357
357
|
let endSuffix = `${sc.matches ?? 0} ${matchWord} in ${sc.filesChanged ?? 0} ${fileWord}`;
|
|
358
358
|
if (sc.failedFiles)
|
|
359
359
|
endSuffix += `, ${sc.failedFiles} failed`;
|
|
360
|
-
progress.complete(
|
|
360
|
+
progress.complete(`${SEARCH_AND_REPLACE_TOOL.title}: ${context} • ${endSuffix}`, finalCurrent);
|
|
361
361
|
if (!args.dryRun) {
|
|
362
362
|
void ctx.log?.('info', `search_and_replace: ${String(sc.matches ?? 0)} matches in ${String(sc.filesChanged ?? 0)} files`);
|
|
363
363
|
}
|
|
364
364
|
return result;
|
|
365
365
|
}
|
|
366
366
|
catch (error) {
|
|
367
|
-
progress.fail(
|
|
367
|
+
progress.fail(`${SEARCH_AND_REPLACE_TOOL.title}: ${context} • ${classifyError(error)}`);
|
|
368
368
|
throw error;
|
|
369
369
|
}
|
|
370
370
|
},
|
package/dist/tools/roots.js
CHANGED
|
@@ -41,13 +41,13 @@ export function registerListAllowedDirectoriesTool(server, options = {}) {
|
|
|
41
41
|
onError: (error) => buildToolErrorResponse(error, ErrorCode.UNKNOWN),
|
|
42
42
|
});
|
|
43
43
|
registerStandardTool(server, LIST_ALLOWED_DIRECTORIES_TOOL, handler, options, {
|
|
44
|
-
progressMessage: () =>
|
|
44
|
+
progressMessage: () => LIST_ALLOWED_DIRECTORIES_TOOL.title,
|
|
45
45
|
completionMessage: (_args, result) => {
|
|
46
46
|
if (result.isError)
|
|
47
|
-
return
|
|
47
|
+
return `${LIST_ALLOWED_DIRECTORIES_TOOL.title} • ${result.errorCode}`;
|
|
48
48
|
const sc = result.structuredContent;
|
|
49
49
|
const count = sc.directories?.length ?? 0;
|
|
50
|
-
return
|
|
50
|
+
return `${LIST_ALLOWED_DIRECTORIES_TOOL.title} • ${count} ${count === 1 ? 'root' : 'roots'}`;
|
|
51
51
|
},
|
|
52
52
|
});
|
|
53
53
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { relative } from 'node:path';
|
|
2
2
|
import RE2 from 're2';
|
|
3
3
|
import { DEFAULT_EXCLUDE_PATTERNS } from '../lib/constants.js';
|
|
4
|
-
import { ErrorCode, formatUnknownErrorMessage, McpError, } from '../lib/errors.js';
|
|
4
|
+
import { classifyError, ErrorCode, formatUnknownErrorMessage, McpError, } from '../lib/errors.js';
|
|
5
5
|
import { searchContent, } from '../lib/file-operations/search.js';
|
|
6
6
|
import { formatOperationSummary } from '../config.js';
|
|
7
7
|
import { SearchContentInputSchema, SearchContentOutputSchema, } from '../schemas.js';
|
|
8
8
|
import { SEARCH_ICONS } from './icons.js';
|
|
9
9
|
import { buildResourceLink, buildToolErrorResponse, buildToolResponse, createToolProgressSession, executeToolWithDiagnostics, READ_ONLY_TOOL_ANNOTATIONS, resolveFinalProgressCurrent, resolvePathOrRoot, truncateProgressPattern, } from './shared.js';
|
|
10
|
-
import { registerStandardTool } from './task-support.js';
|
|
10
|
+
import { registerStandardTool, reportTaskStatus } from './task-support.js';
|
|
11
11
|
/**
|
|
12
12
|
* Configuration constants for the Search Content tool.
|
|
13
13
|
*/
|
|
@@ -268,7 +268,7 @@ export function registerSearchContentTool(server, options = {}) {
|
|
|
268
268
|
context: { path: args.path ?? '.' },
|
|
269
269
|
run: async (signal) => {
|
|
270
270
|
const { pattern, filePattern: scope } = args;
|
|
271
|
-
const progressLabel =
|
|
271
|
+
const progressLabel = `${SEARCH_CONTENT_TOOL.title}: ${truncateProgressPattern(pattern)}`;
|
|
272
272
|
const progress = createToolProgressSession(ctx, progressLabel);
|
|
273
273
|
const progressWithMessage = ({ current, total, }) => {
|
|
274
274
|
progress.update({
|
|
@@ -276,6 +276,7 @@ export function registerSearchContentTool(server, options = {}) {
|
|
|
276
276
|
...(total !== undefined ? { total } : {}),
|
|
277
277
|
message: `${progressLabel} [${current} files]`,
|
|
278
278
|
});
|
|
279
|
+
void reportTaskStatus(`${progressLabel} ${current} files`);
|
|
279
280
|
};
|
|
280
281
|
try {
|
|
281
282
|
const result = await handleSearchContent(args, signal, options.resourceStore, progressWithMessage);
|
|
@@ -287,7 +288,7 @@ export function registerSearchContentTool(server, options = {}) {
|
|
|
287
288
|
return result;
|
|
288
289
|
}
|
|
289
290
|
catch (error) {
|
|
290
|
-
progress.fail(`${progressLabel} •
|
|
291
|
+
progress.fail(`${progressLabel} • ${classifyError(error)}`);
|
|
291
292
|
throw error;
|
|
292
293
|
}
|
|
293
294
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { basename, relative } from 'node:path';
|
|
2
2
|
import { DEFAULT_EXCLUDE_PATTERNS, DEFAULT_SEARCH_TIMEOUT_MS, } from '../lib/constants.js';
|
|
3
|
-
import { ErrorCode } from '../lib/errors.js';
|
|
3
|
+
import { classifyError, ErrorCode } from '../lib/errors.js';
|
|
4
4
|
import { searchFiles } from '../lib/file-operations/search.js';
|
|
5
5
|
import { formatOperationSummary, joinLines } from '../config.js';
|
|
6
6
|
import { SearchFilesInputSchema, SearchFilesOutputSchema } from '../schemas.js';
|
|
@@ -126,7 +126,7 @@ export function registerSearchFilesTool(server, options = {}) {
|
|
|
126
126
|
let progressCursor = 0;
|
|
127
127
|
notifyProgress(ctx, {
|
|
128
128
|
current: 0,
|
|
129
|
-
message:
|
|
129
|
+
message: `${SEARCH_FILES_TOOL.title}: ${truncatedPattern}`,
|
|
130
130
|
});
|
|
131
131
|
const baseReporter = createProgressReporter(ctx);
|
|
132
132
|
const progressWithMessage = ({ current, total, }) => {
|
|
@@ -135,7 +135,7 @@ export function registerSearchFilesTool(server, options = {}) {
|
|
|
135
135
|
baseReporter({
|
|
136
136
|
current,
|
|
137
137
|
...(total !== undefined ? { total } : {}),
|
|
138
|
-
message:
|
|
138
|
+
message: `${SEARCH_FILES_TOOL.title}: ${truncatedPattern} [${current} files]`,
|
|
139
139
|
});
|
|
140
140
|
};
|
|
141
141
|
try {
|
|
@@ -162,7 +162,7 @@ export function registerSearchFilesTool(server, options = {}) {
|
|
|
162
162
|
notifyProgress(ctx, {
|
|
163
163
|
current: finalCurrent,
|
|
164
164
|
total: finalCurrent,
|
|
165
|
-
message:
|
|
165
|
+
message: `${SEARCH_FILES_TOOL.title}: ${context} • ${suffix}`,
|
|
166
166
|
});
|
|
167
167
|
return result;
|
|
168
168
|
}
|
|
@@ -171,7 +171,7 @@ export function registerSearchFilesTool(server, options = {}) {
|
|
|
171
171
|
notifyProgress(ctx, {
|
|
172
172
|
current: finalCurrent,
|
|
173
173
|
total: finalCurrent,
|
|
174
|
-
message:
|
|
174
|
+
message: `${SEARCH_FILES_TOOL.title}: ${context} • ${classifyError(error)}`,
|
|
175
175
|
});
|
|
176
176
|
throw error;
|
|
177
177
|
}
|
package/dist/tools/shared.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ContentBlock, Icon, LoggingLevel,
|
|
1
|
+
import type { ContentBlock, Icon, LoggingLevel, Notification, RequestMeta, ServerContext } from '@modelcontextprotocol/server';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { ErrorCode } from '../lib/errors.js';
|
|
4
4
|
import type { ResourceStore } from '../lib/resource-store.js';
|
|
@@ -56,25 +56,27 @@ export type ToolResponse<T> = ReturnType<typeof buildToolResponse<T>> & {
|
|
|
56
56
|
interface ToolErrorResponse extends Record<string, unknown> {
|
|
57
57
|
content: ContentBlock[];
|
|
58
58
|
isError: true;
|
|
59
|
-
errorCode
|
|
59
|
+
errorCode: ErrorCode;
|
|
60
60
|
}
|
|
61
61
|
export type ToolResult<T> = ToolResponse<T> | ToolErrorResponse;
|
|
62
62
|
export declare function withValidatedArgs<Args, Result>(schema: z.ZodType<Args>, handler: (args: Args, ctx: ToolContext) => Promise<ToolResult<Result>>): (args: unknown, ctx: ToolContext | ServerContext) => Promise<ToolResult<Result>>;
|
|
63
|
-
|
|
63
|
+
/**
|
|
64
|
+
* App-level tracing metadata passed through {@linkcode RequestMeta}.
|
|
65
|
+
* These fields are preserved by the SDK's loose `RequestMeta` type.
|
|
66
|
+
*/
|
|
67
|
+
interface TracingMeta {
|
|
68
|
+
traceparent?: string | undefined;
|
|
69
|
+
tracestate?: string | undefined;
|
|
70
|
+
baggage?: string | undefined;
|
|
71
|
+
}
|
|
64
72
|
export interface ToolContext {
|
|
65
73
|
signal?: AbortSignal;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
tracestate?: string | undefined;
|
|
70
|
-
baggage?: string | undefined;
|
|
71
|
-
} | undefined;
|
|
72
|
-
sendNotification?: (notification: {
|
|
73
|
-
method: 'notifications/progress';
|
|
74
|
-
params: ProgressNotificationParams;
|
|
75
|
-
}) => Promise<void>;
|
|
74
|
+
sessionId?: string;
|
|
75
|
+
_meta?: (RequestMeta & TracingMeta) | undefined;
|
|
76
|
+
sendNotification?: (notification: Notification) => Promise<void>;
|
|
76
77
|
log?: (level: LoggingLevel, data: unknown, logger?: string) => Promise<void>;
|
|
77
78
|
}
|
|
79
|
+
export declare function toToolContext(ctx?: ToolContext | ServerContext): ToolContext;
|
|
78
80
|
export interface IconInfo {
|
|
79
81
|
src: string;
|
|
80
82
|
mimeType: string;
|
|
@@ -168,8 +170,3 @@ export declare function encodeOffsetCursor(offset: number): string;
|
|
|
168
170
|
export declare function decodeOffsetCursor(cursor: string): number;
|
|
169
171
|
export declare function buildBatchPathContext(paths: readonly string[], unitLabel?: string): string;
|
|
170
172
|
export declare function truncateProgressPattern(pattern: string, maxLength?: number): string;
|
|
171
|
-
export declare function buildBatchCompletionSuffix(summary: {
|
|
172
|
-
total?: number;
|
|
173
|
-
failed?: number;
|
|
174
|
-
succeeded?: number;
|
|
175
|
-
} | undefined, successWord: string, singularWord?: string): string;
|
package/dist/tools/shared.js
CHANGED
|
@@ -3,7 +3,7 @@ import { basename } from 'node:path';
|
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { createTimedAbortSignal } from '../lib/abort.js';
|
|
5
5
|
import { parseTrueEnvFlag } from '../lib/constants.js';
|
|
6
|
-
import { createDetailedError, ErrorCode, formatDetailedError, getSuggestion, McpError, } from '../lib/errors.js';
|
|
6
|
+
import { classifyError, createDetailedError, ErrorCode, formatDetailedError, getSuggestion, McpError, } from '../lib/errors.js';
|
|
7
7
|
import { Logger } from '../lib/logger.js';
|
|
8
8
|
import { withToolDiagnostics, } from '../lib/observability.js';
|
|
9
9
|
import { getAllowedDirectories } from '../lib/paths.js';
|
|
@@ -223,20 +223,18 @@ export function withValidatedArgs(schema, handler) {
|
|
|
223
223
|
}
|
|
224
224
|
};
|
|
225
225
|
}
|
|
226
|
-
function toToolContext(ctx) {
|
|
226
|
+
export function toToolContext(ctx) {
|
|
227
227
|
if (!ctx)
|
|
228
228
|
return {};
|
|
229
229
|
if ('mcpReq' in ctx) {
|
|
230
230
|
return {
|
|
231
231
|
signal: ctx.mcpReq.signal,
|
|
232
|
+
...(ctx.sessionId ? { sessionId: ctx.sessionId } : {}),
|
|
232
233
|
...(ctx.mcpReq._meta
|
|
233
234
|
? { _meta: ctx.mcpReq._meta }
|
|
234
235
|
: {}),
|
|
235
236
|
sendNotification: async (notification) => ctx.mcpReq.notify(notification),
|
|
236
|
-
log: async (level, data, logger) => ctx.mcpReq.
|
|
237
|
-
method: 'notifications/message',
|
|
238
|
-
params: { level, data, ...(logger ? { logger } : {}) },
|
|
239
|
-
}),
|
|
237
|
+
log: async (level, data, logger) => ctx.mcpReq.log(level, data, logger),
|
|
240
238
|
};
|
|
241
239
|
}
|
|
242
240
|
return ctx;
|
|
@@ -509,7 +507,7 @@ async function withProgress(message, ctx, run, getCompletionMessage) {
|
|
|
509
507
|
void reportProgress(ctx, {
|
|
510
508
|
current: total,
|
|
511
509
|
total,
|
|
512
|
-
message: `${message} •
|
|
510
|
+
message: `${message} • ${classifyError(error)}`,
|
|
513
511
|
});
|
|
514
512
|
throw error;
|
|
515
513
|
}
|
|
@@ -599,13 +597,3 @@ export function truncateProgressPattern(pattern, maxLength = 40) {
|
|
|
599
597
|
}
|
|
600
598
|
return `${pattern.slice(0, maxLength)}…`;
|
|
601
599
|
}
|
|
602
|
-
export function buildBatchCompletionSuffix(summary, successWord, singularWord) {
|
|
603
|
-
const total = summary?.total ?? 0;
|
|
604
|
-
const failed = summary?.failed ?? 0;
|
|
605
|
-
const succeeded = summary?.succeeded ?? 0;
|
|
606
|
-
if (failed) {
|
|
607
|
-
return `${succeeded}/${total} ${successWord}, ${failed} failed`;
|
|
608
|
-
}
|
|
609
|
-
const word = total === 1 && singularWord ? singularWord : successWord;
|
|
610
|
-
return `${total} ${word}`;
|
|
611
|
-
}
|
package/dist/tools/stat-many.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { DEFAULT_SEARCH_TIMEOUT_MS } from '../lib/constants.js';
|
|
2
|
-
import { ErrorCode } from '../lib/errors.js';
|
|
2
|
+
import { classifyError, ErrorCode } from '../lib/errors.js';
|
|
3
3
|
import { getMultipleFileInfo } from '../lib/file-operations/metadata.js';
|
|
4
4
|
import { formatBytes, joinLines } from '../config.js';
|
|
5
5
|
import { GetMultipleFileInfoInputSchema, GetMultipleFileInfoOutputSchema, } from '../schemas.js';
|
|
6
6
|
import { FILE_READ_ICONS } from './icons.js';
|
|
7
|
-
import {
|
|
7
|
+
import { buildBatchPathContext, buildFileInfoPayload, buildStructuredError, buildToolErrorResponse, buildToolResponse, createBatchProgressCallbacks, executeToolWithDiagnostics, READ_ONLY_TOOL_ANNOTATIONS, resolveFinalProgressCurrent, } from './shared.js';
|
|
8
8
|
import { registerStandardTool } from './task-support.js';
|
|
9
9
|
export const GET_MULTIPLE_FILE_INFO_TOOL = {
|
|
10
10
|
name: 'stat_many',
|
|
@@ -77,7 +77,7 @@ export function registerGetMultipleFileInfoTool(server, options = {}) {
|
|
|
77
77
|
run: async (signal) => {
|
|
78
78
|
const context = buildBatchPathContext(args.paths);
|
|
79
79
|
const { progress, onItemComplete } = createBatchProgressCallbacks(ctx, {
|
|
80
|
-
toolLabel:
|
|
80
|
+
toolLabel: GET_MULTIPLE_FILE_INFO_TOOL.title,
|
|
81
81
|
context,
|
|
82
82
|
totalItems: args.paths.length,
|
|
83
83
|
itemVerb: 'done',
|
|
@@ -85,14 +85,15 @@ export function registerGetMultipleFileInfoTool(server, options = {}) {
|
|
|
85
85
|
try {
|
|
86
86
|
const result = await handleGetMultipleFileInfo(args, signal, onItemComplete);
|
|
87
87
|
const sc = result.structuredContent;
|
|
88
|
-
const suffix = buildBatchCompletionSuffix(sc.summary, 'OK');
|
|
89
88
|
const total = sc.summary?.total ?? 0;
|
|
89
|
+
const failed = sc.summary?.failed ?? 0;
|
|
90
|
+
const suffix = failed ? `${failed} failed` : 'done';
|
|
90
91
|
const finalCurrent = resolveFinalProgressCurrent(progress, total);
|
|
91
|
-
progress.complete(
|
|
92
|
+
progress.complete(`${GET_MULTIPLE_FILE_INFO_TOOL.title}: ${context} • ${suffix}`, finalCurrent);
|
|
92
93
|
return result;
|
|
93
94
|
}
|
|
94
95
|
catch (error) {
|
|
95
|
-
progress.fail(
|
|
96
|
+
progress.fail(`${GET_MULTIPLE_FILE_INFO_TOOL.title}: ${context} • ${classifyError(error)}`);
|
|
96
97
|
throw error;
|
|
97
98
|
}
|
|
98
99
|
},
|
package/dist/tools/stat.js
CHANGED
|
@@ -53,15 +53,15 @@ export function registerGetFileInfoTool(server, options = {}) {
|
|
|
53
53
|
onError: (error) => buildToolErrorResponse(error, ErrorCode.NOT_FOUND, args.path),
|
|
54
54
|
});
|
|
55
55
|
registerStandardTool(server, GET_FILE_INFO_TOOL, handler, options, {
|
|
56
|
-
progressMessage: (args) =>
|
|
56
|
+
progressMessage: (args) => `${GET_FILE_INFO_TOOL.title}: ${basename(args.path)}`,
|
|
57
57
|
completionMessage: (args, result) => {
|
|
58
58
|
const name = basename(args.path);
|
|
59
59
|
if (result.isError)
|
|
60
|
-
return
|
|
60
|
+
return `${GET_FILE_INFO_TOOL.title}: ${name} • ${result.errorCode}`;
|
|
61
61
|
const sc = result.structuredContent;
|
|
62
62
|
if (!sc.info)
|
|
63
|
-
return
|
|
64
|
-
return
|
|
63
|
+
return `${GET_FILE_INFO_TOOL.title}: ${name} • failed`;
|
|
64
|
+
return `${GET_FILE_INFO_TOOL.title}: ${sc.info.name} • ${formatBytes(sc.info.size)}`;
|
|
65
65
|
},
|
|
66
66
|
});
|
|
67
67
|
}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { type McpServer, type RequestTaskStore, type StandardSchemaWithJSON, type ToolTaskHandler } from '@modelcontextprotocol/server';
|
|
2
2
|
import { type IconInfo, type ToolContext, type ToolContract, type ToolRegistrationOptions, type ToolResult } from './shared.js';
|
|
3
|
+
/**
|
|
4
|
+
* Report an intermediate 'working' status update for the current task.
|
|
5
|
+
* No-op when called outside of a task context.
|
|
6
|
+
*/
|
|
7
|
+
export declare function reportTaskStatus(statusMessage: string): Promise<void>;
|
|
3
8
|
type TaskToolContext = ToolContext & {
|
|
4
9
|
taskId?: string;
|
|
5
10
|
taskStore?: RequestTaskStore;
|