@j0hanz/fs-context-mcp 2.4.2 → 2.4.4
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/resources.js +0 -6
- package/dist/server.js +12 -22
- package/dist/tools/list-directory.js +9 -18
- package/dist/tools/read-multiple.js +3 -18
- package/dist/tools/read.js +10 -18
- package/dist/tools/roots.js +2 -17
- package/dist/tools/search-content.js +10 -18
- package/dist/tools/search-files.js +3 -18
- package/dist/tools/shared.d.ts +5 -1
- package/dist/tools/shared.js +25 -3
- package/dist/tools/stat-many.js +3 -18
- package/dist/tools/stat.js +4 -18
- package/dist/tools/tree.js +9 -18
- package/package.json +1 -1
package/dist/resources.js
CHANGED
|
@@ -14,9 +14,6 @@ export function registerInstructionResource(server, instructions, iconInfo) {
|
|
|
14
14
|
{
|
|
15
15
|
src: iconInfo.src,
|
|
16
16
|
mimeType: iconInfo.mimeType,
|
|
17
|
-
...(iconInfo.mimeType === 'image/svg+xml'
|
|
18
|
-
? { sizes: ['any'] }
|
|
19
|
-
: {}),
|
|
20
17
|
},
|
|
21
18
|
],
|
|
22
19
|
}
|
|
@@ -42,9 +39,6 @@ export function registerResultResources(server, store, iconInfo) {
|
|
|
42
39
|
{
|
|
43
40
|
src: iconInfo.src,
|
|
44
41
|
mimeType: iconInfo.mimeType,
|
|
45
|
-
...(iconInfo.mimeType === 'image/svg+xml'
|
|
46
|
-
? { sizes: ['any'] }
|
|
47
|
-
: {}),
|
|
48
42
|
},
|
|
49
43
|
],
|
|
50
44
|
}
|
package/dist/server.js
CHANGED
|
@@ -260,26 +260,19 @@ catch (error) {
|
|
|
260
260
|
console.error('[WARNING] Failed to load instructions.md:', error instanceof Error ? error.message : String(error));
|
|
261
261
|
}
|
|
262
262
|
async function getLocalIconInfo() {
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
mimeType: mime,
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
catch {
|
|
279
|
-
continue;
|
|
280
|
-
}
|
|
263
|
+
const name = 'logo.svg';
|
|
264
|
+
const mime = 'image/svg+xml';
|
|
265
|
+
try {
|
|
266
|
+
const iconPath = new URL(`../assets/${name}`, import.meta.url);
|
|
267
|
+
const buffer = await fs.readFile(iconPath);
|
|
268
|
+
return {
|
|
269
|
+
src: `data:${mime};base64,${buffer.toString('base64')}`,
|
|
270
|
+
mimeType: mime,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
catch {
|
|
274
|
+
return undefined;
|
|
281
275
|
}
|
|
282
|
-
return undefined;
|
|
283
276
|
}
|
|
284
277
|
function resolveToolErrorCode(message) {
|
|
285
278
|
return extractExplicitErrorCode(message);
|
|
@@ -331,9 +324,6 @@ export async function createServer(options = {}) {
|
|
|
331
324
|
{
|
|
332
325
|
src: localIcon.src,
|
|
333
326
|
mimeType: localIcon.mimeType,
|
|
334
|
-
...(localIcon.mimeType === 'image/svg+xml'
|
|
335
|
-
? { sizes: ['any'] }
|
|
336
|
-
: {}),
|
|
337
327
|
},
|
|
338
328
|
],
|
|
339
329
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import * as path from 'node:path';
|
|
1
2
|
import { formatOperationSummary, joinLines } from '../config.js';
|
|
2
3
|
import { DEFAULT_EXCLUDE_PATTERNS } from '../lib/constants.js';
|
|
3
4
|
import { ErrorCode } from '../lib/errors.js';
|
|
4
5
|
import { listDirectory } from '../lib/file-operations/list-directory.js';
|
|
5
6
|
import { withToolDiagnostics } from '../lib/observability.js';
|
|
6
7
|
import { ListDirectoryInputSchema, ListDirectoryOutputSchema, } from '../schemas.js';
|
|
7
|
-
import { buildToolErrorResponse, buildToolResponse, resolvePathOrRoot, withToolErrorHandling, wrapToolHandler, } from './shared.js';
|
|
8
|
+
import { buildToolErrorResponse, buildToolResponse, resolvePathOrRoot, withDefaultIcons, withToolErrorHandling, wrapToolHandler, } from './shared.js';
|
|
8
9
|
const LIST_DIRECTORY_TOOL = {
|
|
9
10
|
title: 'List Directory',
|
|
10
11
|
description: 'List the immediate contents of a directory (non-recursive). ' +
|
|
@@ -80,23 +81,13 @@ async function handleListDirectory(args, signal) {
|
|
|
80
81
|
}
|
|
81
82
|
export function registerListDirectoryTool(server, options = {}) {
|
|
82
83
|
const handler = (args, extra) => withToolDiagnostics('ls', () => withToolErrorHandling(() => handleListDirectory(args, extra.signal), (error) => buildToolErrorResponse(error, ErrorCode.E_NOT_DIRECTORY, args.path ?? '.')), { path: args.path ?? '.' });
|
|
83
|
-
server.registerTool('ls', {
|
|
84
|
-
...LIST_DIRECTORY_TOOL,
|
|
85
|
-
...(options.iconInfo
|
|
86
|
-
? {
|
|
87
|
-
icons: [
|
|
88
|
-
{
|
|
89
|
-
src: options.iconInfo.src,
|
|
90
|
-
mimeType: options.iconInfo.mimeType,
|
|
91
|
-
...(options.iconInfo.mimeType === 'image/svg+xml'
|
|
92
|
-
? { sizes: ['any'] }
|
|
93
|
-
: {}),
|
|
94
|
-
},
|
|
95
|
-
],
|
|
96
|
-
}
|
|
97
|
-
: {}),
|
|
98
|
-
}, wrapToolHandler(handler, {
|
|
84
|
+
server.registerTool('ls', withDefaultIcons({ ...LIST_DIRECTORY_TOOL }, options.iconInfo), wrapToolHandler(handler, {
|
|
99
85
|
guard: options.isInitialized,
|
|
100
|
-
progressMessage: (args) =>
|
|
86
|
+
progressMessage: (args) => {
|
|
87
|
+
if (args.path) {
|
|
88
|
+
return `ls | ${path.basename(args.path)}`;
|
|
89
|
+
}
|
|
90
|
+
return 'ls';
|
|
91
|
+
},
|
|
101
92
|
}));
|
|
102
93
|
}
|
|
@@ -5,7 +5,7 @@ import { readMultipleFiles } from '../lib/file-operations/read-multiple-files.js
|
|
|
5
5
|
import { createTimedAbortSignal } from '../lib/fs-helpers.js';
|
|
6
6
|
import { withToolDiagnostics } from '../lib/observability.js';
|
|
7
7
|
import { ReadMultipleFilesInputSchema, ReadMultipleFilesOutputSchema, } from '../schemas.js';
|
|
8
|
-
import { buildResourceLink, buildToolErrorResponse, buildToolResponse, maybeExternalizeTextContent, withToolErrorHandling, wrapToolHandler, } from './shared.js';
|
|
8
|
+
import { buildResourceLink, buildToolErrorResponse, buildToolResponse, maybeExternalizeTextContent, withDefaultIcons, withToolErrorHandling, wrapToolHandler, } from './shared.js';
|
|
9
9
|
const READ_MULTIPLE_FILES_TOOL = {
|
|
10
10
|
title: 'Read Multiple Files',
|
|
11
11
|
description: 'Read multiple text files in a single request. ' +
|
|
@@ -104,23 +104,8 @@ export function registerReadMultipleFilesTool(server, options = {}) {
|
|
|
104
104
|
}
|
|
105
105
|
}, (error) => buildToolErrorResponse(error, ErrorCode.E_NOT_FILE, primaryPath)), { path: primaryPath });
|
|
106
106
|
};
|
|
107
|
-
server.registerTool('read_many', {
|
|
108
|
-
...READ_MULTIPLE_FILES_TOOL,
|
|
109
|
-
...(options.iconInfo
|
|
110
|
-
? {
|
|
111
|
-
icons: [
|
|
112
|
-
{
|
|
113
|
-
src: options.iconInfo.src,
|
|
114
|
-
mimeType: options.iconInfo.mimeType,
|
|
115
|
-
...(options.iconInfo.mimeType === 'image/svg+xml'
|
|
116
|
-
? { sizes: ['any'] }
|
|
117
|
-
: {}),
|
|
118
|
-
},
|
|
119
|
-
],
|
|
120
|
-
}
|
|
121
|
-
: {}),
|
|
122
|
-
}, wrapToolHandler(handler, {
|
|
107
|
+
server.registerTool('read_many', withDefaultIcons({ ...READ_MULTIPLE_FILES_TOOL }, options.iconInfo), wrapToolHandler(handler, {
|
|
123
108
|
guard: options.isInitialized,
|
|
124
|
-
progressMessage: (args) => `read_many
|
|
109
|
+
progressMessage: (args) => `read_many | ${args.paths.length} files`,
|
|
125
110
|
}));
|
|
126
111
|
}
|
package/dist/tools/read.js
CHANGED
|
@@ -5,7 +5,7 @@ import { readFile } from '../lib/fs-helpers.js';
|
|
|
5
5
|
import { createTimedAbortSignal } from '../lib/fs-helpers.js';
|
|
6
6
|
import { withToolDiagnostics } from '../lib/observability.js';
|
|
7
7
|
import { ReadFileInputSchema, ReadFileOutputSchema } from '../schemas.js';
|
|
8
|
-
import { buildResourceLink, buildToolErrorResponse, buildToolResponse, maybeExternalizeTextContent, withToolErrorHandling, wrapToolHandler, } from './shared.js';
|
|
8
|
+
import { buildResourceLink, buildToolErrorResponse, buildToolResponse, maybeExternalizeTextContent, withDefaultIcons, withToolErrorHandling, wrapToolHandler, } from './shared.js';
|
|
9
9
|
const READ_FILE_TOOL = {
|
|
10
10
|
title: 'Read File',
|
|
11
11
|
description: 'Read the text contents of a file. ' +
|
|
@@ -87,23 +87,15 @@ export function registerReadFileTool(server, options = {}) {
|
|
|
87
87
|
cleanup();
|
|
88
88
|
}
|
|
89
89
|
}, (error) => buildToolErrorResponse(error, ErrorCode.E_NOT_FILE, args.path)), { path: args.path });
|
|
90
|
-
server.registerTool('read', {
|
|
91
|
-
...READ_FILE_TOOL,
|
|
92
|
-
...(options.iconInfo
|
|
93
|
-
? {
|
|
94
|
-
icons: [
|
|
95
|
-
{
|
|
96
|
-
src: options.iconInfo.src,
|
|
97
|
-
mimeType: options.iconInfo.mimeType,
|
|
98
|
-
...(options.iconInfo.mimeType === 'image/svg+xml'
|
|
99
|
-
? { sizes: ['any'] }
|
|
100
|
-
: {}),
|
|
101
|
-
},
|
|
102
|
-
],
|
|
103
|
-
}
|
|
104
|
-
: {}),
|
|
105
|
-
}, wrapToolHandler(handler, {
|
|
90
|
+
server.registerTool('read', withDefaultIcons({ ...READ_FILE_TOOL }, options.iconInfo), wrapToolHandler(handler, {
|
|
106
91
|
guard: options.isInitialized,
|
|
107
|
-
progressMessage: (args) =>
|
|
92
|
+
progressMessage: (args) => {
|
|
93
|
+
const name = path.basename(args.path);
|
|
94
|
+
if (args.startLine !== undefined) {
|
|
95
|
+
const end = args.endLine ?? '…';
|
|
96
|
+
return `read | ${name} | ${args.startLine}-${end}`;
|
|
97
|
+
}
|
|
98
|
+
return `read | ${name}`;
|
|
99
|
+
},
|
|
108
100
|
}));
|
|
109
101
|
}
|
package/dist/tools/roots.js
CHANGED
|
@@ -3,7 +3,7 @@ import { ErrorCode } from '../lib/errors.js';
|
|
|
3
3
|
import { withToolDiagnostics } from '../lib/observability.js';
|
|
4
4
|
import { getAllowedDirectories } from '../lib/path-validation.js';
|
|
5
5
|
import { ListAllowedDirectoriesInputSchema, ListAllowedDirectoriesOutputSchema, } from '../schemas.js';
|
|
6
|
-
import { buildToolErrorResponse, buildToolResponse, withToolErrorHandling, wrapToolHandler, } from './shared.js';
|
|
6
|
+
import { buildToolErrorResponse, buildToolResponse, withDefaultIcons, withToolErrorHandling, wrapToolHandler, } from './shared.js';
|
|
7
7
|
const LIST_ALLOWED_DIRECTORIES_TOOL = {
|
|
8
8
|
title: 'Workspace Roots',
|
|
9
9
|
description: 'List the workspace roots this server can access. ' +
|
|
@@ -36,22 +36,7 @@ function handleListAllowedDirectories() {
|
|
|
36
36
|
}
|
|
37
37
|
export function registerListAllowedDirectoriesTool(server, options = {}) {
|
|
38
38
|
const handler = () => withToolErrorHandling(() => withToolDiagnostics('roots', () => Promise.resolve(handleListAllowedDirectories())), (error) => buildToolErrorResponse(error, ErrorCode.E_UNKNOWN));
|
|
39
|
-
server.registerTool('roots', {
|
|
40
|
-
...LIST_ALLOWED_DIRECTORIES_TOOL,
|
|
41
|
-
...(options.iconInfo
|
|
42
|
-
? {
|
|
43
|
-
icons: [
|
|
44
|
-
{
|
|
45
|
-
src: options.iconInfo.src,
|
|
46
|
-
mimeType: options.iconInfo.mimeType,
|
|
47
|
-
...(options.iconInfo.mimeType === 'image/svg+xml'
|
|
48
|
-
? { sizes: ['any'] }
|
|
49
|
-
: {}),
|
|
50
|
-
},
|
|
51
|
-
],
|
|
52
|
-
}
|
|
53
|
-
: {}),
|
|
54
|
-
}, wrapToolHandler(handler, {
|
|
39
|
+
server.registerTool('roots', withDefaultIcons({ ...LIST_ALLOWED_DIRECTORIES_TOOL }, options.iconInfo), wrapToolHandler(handler, {
|
|
55
40
|
guard: options.isInitialized,
|
|
56
41
|
progressMessage: () => 'roots',
|
|
57
42
|
}));
|
|
@@ -4,7 +4,7 @@ import { ErrorCode } from '../lib/errors.js';
|
|
|
4
4
|
import { searchContent } from '../lib/file-operations/search-content.js';
|
|
5
5
|
import { withToolDiagnostics } from '../lib/observability.js';
|
|
6
6
|
import { SearchContentInputSchema, SearchContentOutputSchema, } from '../schemas.js';
|
|
7
|
-
import { buildResourceLink, buildToolErrorResponse, buildToolResponse, createProgressReporter, resolvePathOrRoot, withToolErrorHandling, wrapToolHandler, } from './shared.js';
|
|
7
|
+
import { buildResourceLink, buildToolErrorResponse, buildToolResponse, createProgressReporter, resolvePathOrRoot, withDefaultIcons, withToolErrorHandling, wrapToolHandler, } from './shared.js';
|
|
8
8
|
const MAX_INLINE_MATCHES = 50;
|
|
9
9
|
const SEARCH_CONTENT_TOOL = {
|
|
10
10
|
title: 'Search Content',
|
|
@@ -134,23 +134,15 @@ async function handleSearchContent(args, signal, resourceStore, onProgress) {
|
|
|
134
134
|
}
|
|
135
135
|
export function registerSearchContentTool(server, options = {}) {
|
|
136
136
|
const handler = (args, extra) => withToolDiagnostics('grep', () => withToolErrorHandling(async () => handleSearchContent(args, extra.signal, options.resourceStore, createProgressReporter(extra)), (error) => buildToolErrorResponse(error, ErrorCode.E_UNKNOWN, args.path ?? '.')), { path: args.path ?? '.' });
|
|
137
|
-
server.registerTool('grep', {
|
|
138
|
-
...SEARCH_CONTENT_TOOL,
|
|
139
|
-
...(options.iconInfo
|
|
140
|
-
? {
|
|
141
|
-
icons: [
|
|
142
|
-
{
|
|
143
|
-
src: options.iconInfo.src,
|
|
144
|
-
mimeType: options.iconInfo.mimeType,
|
|
145
|
-
...(options.iconInfo.mimeType === 'image/svg+xml'
|
|
146
|
-
? { sizes: ['any'] }
|
|
147
|
-
: {}),
|
|
148
|
-
},
|
|
149
|
-
],
|
|
150
|
-
}
|
|
151
|
-
: {}),
|
|
152
|
-
}, wrapToolHandler(handler, {
|
|
137
|
+
server.registerTool('grep', withDefaultIcons({ ...SEARCH_CONTENT_TOOL }, options.iconInfo), wrapToolHandler(handler, {
|
|
153
138
|
guard: options.isInitialized,
|
|
154
|
-
progressMessage: (args) => `grep
|
|
139
|
+
progressMessage: (args) => `grep | ${args.pattern}`,
|
|
140
|
+
completionMessage: (args, result) => {
|
|
141
|
+
if ('isError' in result && result.isError)
|
|
142
|
+
return undefined;
|
|
143
|
+
const { structuredContent: sc } = result;
|
|
144
|
+
const suffix = sc.ok && sc.totalMatches ? String(sc.totalMatches) : 'No matches';
|
|
145
|
+
return `grep | ${args.pattern} | ${suffix}`;
|
|
146
|
+
},
|
|
155
147
|
}));
|
|
156
148
|
}
|
|
@@ -6,7 +6,7 @@ import { searchFiles } from '../lib/file-operations/search-files.js';
|
|
|
6
6
|
import { createTimedAbortSignal } from '../lib/fs-helpers.js';
|
|
7
7
|
import { withToolDiagnostics } from '../lib/observability.js';
|
|
8
8
|
import { SearchFilesInputSchema, SearchFilesOutputSchema } from '../schemas.js';
|
|
9
|
-
import { buildToolErrorResponse, buildToolResponse, resolvePathOrRoot, withToolErrorHandling, wrapToolHandler, } from './shared.js';
|
|
9
|
+
import { buildToolErrorResponse, buildToolResponse, resolvePathOrRoot, withDefaultIcons, withToolErrorHandling, wrapToolHandler, } from './shared.js';
|
|
10
10
|
const SEARCH_FILES_TOOL = {
|
|
11
11
|
title: 'Find Files',
|
|
12
12
|
description: 'Find files by glob pattern (e.g., **/*.ts). ' +
|
|
@@ -74,23 +74,8 @@ export function registerSearchFilesTool(server, options = {}) {
|
|
|
74
74
|
cleanup();
|
|
75
75
|
}
|
|
76
76
|
}, (error) => buildToolErrorResponse(error, ErrorCode.E_INVALID_PATTERN, args.path)), { path: args.path ?? '.' });
|
|
77
|
-
server.registerTool('find', {
|
|
78
|
-
...SEARCH_FILES_TOOL,
|
|
79
|
-
...(options.iconInfo
|
|
80
|
-
? {
|
|
81
|
-
icons: [
|
|
82
|
-
{
|
|
83
|
-
src: options.iconInfo.src,
|
|
84
|
-
mimeType: options.iconInfo.mimeType,
|
|
85
|
-
...(options.iconInfo.mimeType === 'image/svg+xml'
|
|
86
|
-
? { sizes: ['any'] }
|
|
87
|
-
: {}),
|
|
88
|
-
},
|
|
89
|
-
],
|
|
90
|
-
}
|
|
91
|
-
: {}),
|
|
92
|
-
}, wrapToolHandler(handler, {
|
|
77
|
+
server.registerTool('find', withDefaultIcons({ ...SEARCH_FILES_TOOL }, options.iconInfo), wrapToolHandler(handler, {
|
|
93
78
|
guard: options.isInitialized,
|
|
94
|
-
progressMessage: (args) => `find
|
|
79
|
+
progressMessage: (args) => `find | ${args.pattern}`,
|
|
95
80
|
}));
|
|
96
81
|
}
|
package/dist/tools/shared.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ContentBlock, ProgressNotificationParams } from '@modelcontextprotocol/sdk/types.js';
|
|
1
|
+
import type { ContentBlock, Icon, ProgressNotificationParams } from '@modelcontextprotocol/sdk/types.js';
|
|
2
2
|
import { ErrorCode } from '../lib/errors.js';
|
|
3
3
|
import type { ResourceStore } from '../lib/resource-store.js';
|
|
4
4
|
type ResourceEntry = ReturnType<ResourceStore['putText']>;
|
|
@@ -56,6 +56,9 @@ export interface IconInfo {
|
|
|
56
56
|
src: string;
|
|
57
57
|
mimeType: string;
|
|
58
58
|
}
|
|
59
|
+
export declare function withDefaultIcons<T extends object>(tool: T, iconInfo: IconInfo | undefined): T & {
|
|
60
|
+
icons?: Icon[];
|
|
61
|
+
};
|
|
59
62
|
export interface ToolRegistrationOptions {
|
|
60
63
|
resourceStore?: ResourceStore;
|
|
61
64
|
isInitialized?: () => boolean;
|
|
@@ -71,6 +74,7 @@ export declare function createProgressReporter(extra: ToolExtra): (progress: {
|
|
|
71
74
|
export declare function wrapToolHandler<Args, Result>(handler: (args: Args, extra: ToolExtra) => Promise<ToolResult<Result>>, options: {
|
|
72
75
|
guard?: (() => boolean) | undefined;
|
|
73
76
|
progressMessage?: (args: Args) => string;
|
|
77
|
+
completionMessage?: (args: Args, result: ToolResult<Result>) => string | undefined;
|
|
74
78
|
}): (args: Args, extra?: ToolExtra) => Promise<ToolResult<Result>>;
|
|
75
79
|
export declare function resolvePathOrRoot(pathValue: string | undefined): string;
|
|
76
80
|
export {};
|
package/dist/tools/shared.js
CHANGED
|
@@ -57,6 +57,23 @@ export function canSendProgress(extra) {
|
|
|
57
57
|
return (extra._meta?.progressToken !== undefined &&
|
|
58
58
|
extra.sendNotification !== undefined);
|
|
59
59
|
}
|
|
60
|
+
export function withDefaultIcons(tool, iconInfo) {
|
|
61
|
+
if (!iconInfo)
|
|
62
|
+
return tool;
|
|
63
|
+
const existingIcons = tool.icons;
|
|
64
|
+
if (existingIcons && existingIcons.length > 0) {
|
|
65
|
+
return tool;
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
...tool,
|
|
69
|
+
icons: [
|
|
70
|
+
{
|
|
71
|
+
src: iconInfo.src,
|
|
72
|
+
mimeType: iconInfo.mimeType,
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
};
|
|
76
|
+
}
|
|
60
77
|
const NOT_INITIALIZED_ERROR = new McpError(ErrorCode.E_INVALID_INPUT, 'Client not initialized; wait for notifications/initialized');
|
|
61
78
|
export async function withToolErrorHandling(run, onError) {
|
|
62
79
|
try {
|
|
@@ -118,7 +135,7 @@ export function createProgressReporter(extra) {
|
|
|
118
135
|
});
|
|
119
136
|
};
|
|
120
137
|
}
|
|
121
|
-
async function withProgress(message, extra, run) {
|
|
138
|
+
async function withProgress(message, extra, run, getCompletionMessage) {
|
|
122
139
|
if (!canSendProgress(extra)) {
|
|
123
140
|
return await run();
|
|
124
141
|
}
|
|
@@ -132,11 +149,12 @@ async function withProgress(message, extra, run) {
|
|
|
132
149
|
});
|
|
133
150
|
try {
|
|
134
151
|
const result = await run();
|
|
152
|
+
const endMessage = getCompletionMessage?.(result) ?? message;
|
|
135
153
|
await sendProgressNotification(extra, {
|
|
136
154
|
progressToken: token,
|
|
137
155
|
progress: total,
|
|
138
156
|
total,
|
|
139
|
-
message,
|
|
157
|
+
message: endMessage,
|
|
140
158
|
});
|
|
141
159
|
return result;
|
|
142
160
|
}
|
|
@@ -158,7 +176,11 @@ export function wrapToolHandler(handler, options) {
|
|
|
158
176
|
}
|
|
159
177
|
if (options.progressMessage) {
|
|
160
178
|
const message = options.progressMessage(args);
|
|
161
|
-
|
|
179
|
+
const { completionMessage } = options;
|
|
180
|
+
const completionFn = completionMessage
|
|
181
|
+
? (result) => completionMessage(args, result)
|
|
182
|
+
: undefined;
|
|
183
|
+
return await withProgress(message, resolvedExtra, () => handler(args, resolvedExtra), completionFn);
|
|
162
184
|
}
|
|
163
185
|
return await handler(args, resolvedExtra);
|
|
164
186
|
};
|
package/dist/tools/stat-many.js
CHANGED
|
@@ -5,7 +5,7 @@ import { getMultipleFileInfo } from '../lib/file-operations/file-info.js';
|
|
|
5
5
|
import { createTimedAbortSignal } from '../lib/fs-helpers.js';
|
|
6
6
|
import { withToolDiagnostics } from '../lib/observability.js';
|
|
7
7
|
import { GetMultipleFileInfoInputSchema, GetMultipleFileInfoOutputSchema, } from '../schemas.js';
|
|
8
|
-
import { buildToolErrorResponse, buildToolResponse, withToolErrorHandling, wrapToolHandler, } from './shared.js';
|
|
8
|
+
import { buildToolErrorResponse, buildToolResponse, withDefaultIcons, withToolErrorHandling, wrapToolHandler, } from './shared.js';
|
|
9
9
|
const GET_MULTIPLE_FILE_INFO_TOOL = {
|
|
10
10
|
title: 'Get Multiple File Info',
|
|
11
11
|
description: 'Get metadata for multiple files or directories in one request.',
|
|
@@ -84,23 +84,8 @@ export function registerGetMultipleFileInfoTool(server, options = {}) {
|
|
|
84
84
|
}
|
|
85
85
|
}, (error) => buildToolErrorResponse(error, ErrorCode.E_NOT_FOUND, primaryPath)), { path: primaryPath });
|
|
86
86
|
};
|
|
87
|
-
server.registerTool('stat_many', {
|
|
88
|
-
...GET_MULTIPLE_FILE_INFO_TOOL,
|
|
89
|
-
...(options.iconInfo
|
|
90
|
-
? {
|
|
91
|
-
icons: [
|
|
92
|
-
{
|
|
93
|
-
src: options.iconInfo.src,
|
|
94
|
-
mimeType: options.iconInfo.mimeType,
|
|
95
|
-
...(options.iconInfo.mimeType === 'image/svg+xml'
|
|
96
|
-
? { sizes: ['any'] }
|
|
97
|
-
: {}),
|
|
98
|
-
},
|
|
99
|
-
],
|
|
100
|
-
}
|
|
101
|
-
: {}),
|
|
102
|
-
}, wrapToolHandler(handler, {
|
|
87
|
+
server.registerTool('stat_many', withDefaultIcons({ ...GET_MULTIPLE_FILE_INFO_TOOL }, options.iconInfo), wrapToolHandler(handler, {
|
|
103
88
|
guard: options.isInitialized,
|
|
104
|
-
progressMessage: (args) => `stat_many
|
|
89
|
+
progressMessage: (args) => `stat_many ${args.paths.length} paths`,
|
|
105
90
|
}));
|
|
106
91
|
}
|
package/dist/tools/stat.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as path from 'node:path';
|
|
1
2
|
import { formatBytes, joinLines } from '../config.js';
|
|
2
3
|
import { DEFAULT_SEARCH_TIMEOUT_MS } from '../lib/constants.js';
|
|
3
4
|
import { ErrorCode } from '../lib/errors.js';
|
|
@@ -5,7 +6,7 @@ import { getFileInfo } from '../lib/file-operations/file-info.js';
|
|
|
5
6
|
import { createTimedAbortSignal } from '../lib/fs-helpers.js';
|
|
6
7
|
import { withToolDiagnostics } from '../lib/observability.js';
|
|
7
8
|
import { GetFileInfoInputSchema, GetFileInfoOutputSchema } from '../schemas.js';
|
|
8
|
-
import { buildToolErrorResponse, buildToolResponse, withToolErrorHandling, wrapToolHandler, } from './shared.js';
|
|
9
|
+
import { buildToolErrorResponse, buildToolResponse, withDefaultIcons, withToolErrorHandling, wrapToolHandler, } from './shared.js';
|
|
9
10
|
const GET_FILE_INFO_TOOL = {
|
|
10
11
|
title: 'Get File Info',
|
|
11
12
|
description: 'Get metadata (size, modified time, permissions, mime type) for a file or directory.',
|
|
@@ -71,23 +72,8 @@ export function registerGetFileInfoTool(server, options = {}) {
|
|
|
71
72
|
cleanup();
|
|
72
73
|
}
|
|
73
74
|
}, (error) => buildToolErrorResponse(error, ErrorCode.E_NOT_FOUND, args.path)), { path: args.path });
|
|
74
|
-
server.registerTool('stat', {
|
|
75
|
-
...GET_FILE_INFO_TOOL,
|
|
76
|
-
...(options.iconInfo
|
|
77
|
-
? {
|
|
78
|
-
icons: [
|
|
79
|
-
{
|
|
80
|
-
src: options.iconInfo.src,
|
|
81
|
-
mimeType: options.iconInfo.mimeType,
|
|
82
|
-
...(options.iconInfo.mimeType === 'image/svg+xml'
|
|
83
|
-
? { sizes: ['any'] }
|
|
84
|
-
: {}),
|
|
85
|
-
},
|
|
86
|
-
],
|
|
87
|
-
}
|
|
88
|
-
: {}),
|
|
89
|
-
}, wrapToolHandler(handler, {
|
|
75
|
+
server.registerTool('stat', withDefaultIcons({ ...GET_FILE_INFO_TOOL }, options.iconInfo), wrapToolHandler(handler, {
|
|
90
76
|
guard: options.isInitialized,
|
|
91
|
-
progressMessage: (args) => `stat
|
|
77
|
+
progressMessage: (args) => `stat | ${path.basename(args.path)}`,
|
|
92
78
|
}));
|
|
93
79
|
}
|
package/dist/tools/tree.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import * as path from 'node:path';
|
|
1
2
|
import { DEFAULT_SEARCH_TIMEOUT_MS } from '../lib/constants.js';
|
|
2
3
|
import { ErrorCode } from '../lib/errors.js';
|
|
3
4
|
import { formatTreeAscii, treeDirectory } from '../lib/file-operations/tree.js';
|
|
4
5
|
import { createTimedAbortSignal } from '../lib/fs-helpers.js';
|
|
5
6
|
import { withToolDiagnostics } from '../lib/observability.js';
|
|
6
7
|
import { TreeInputSchema, TreeOutputSchema } from '../schemas.js';
|
|
7
|
-
import { buildToolErrorResponse, buildToolResponse, resolvePathOrRoot, withToolErrorHandling, wrapToolHandler, } from './shared.js';
|
|
8
|
+
import { buildToolErrorResponse, buildToolResponse, resolvePathOrRoot, withDefaultIcons, withToolErrorHandling, wrapToolHandler, } from './shared.js';
|
|
8
9
|
const TREE_TOOL = {
|
|
9
10
|
title: 'Tree',
|
|
10
11
|
description: 'Render a directory tree (bounded recursion). ' +
|
|
@@ -51,23 +52,13 @@ export function registerTreeTool(server, options = {}) {
|
|
|
51
52
|
}
|
|
52
53
|
}, (error) => buildToolErrorResponse(error, ErrorCode.E_NOT_DIRECTORY, targetPath)), { path: targetPath });
|
|
53
54
|
};
|
|
54
|
-
server.registerTool('tree', {
|
|
55
|
-
...TREE_TOOL,
|
|
56
|
-
...(options.iconInfo
|
|
57
|
-
? {
|
|
58
|
-
icons: [
|
|
59
|
-
{
|
|
60
|
-
src: options.iconInfo.src,
|
|
61
|
-
mimeType: options.iconInfo.mimeType,
|
|
62
|
-
...(options.iconInfo.mimeType === 'image/svg+xml'
|
|
63
|
-
? { sizes: ['any'] }
|
|
64
|
-
: {}),
|
|
65
|
-
},
|
|
66
|
-
],
|
|
67
|
-
}
|
|
68
|
-
: {}),
|
|
69
|
-
}, wrapToolHandler(handler, {
|
|
55
|
+
server.registerTool('tree', withDefaultIcons({ ...TREE_TOOL }, options.iconInfo), wrapToolHandler(handler, {
|
|
70
56
|
guard: options.isInitialized,
|
|
71
|
-
progressMessage: (args) =>
|
|
57
|
+
progressMessage: (args) => {
|
|
58
|
+
if (args.path) {
|
|
59
|
+
return `tree | ${path.basename(args.path)}`;
|
|
60
|
+
}
|
|
61
|
+
return 'tree';
|
|
62
|
+
},
|
|
72
63
|
}));
|
|
73
64
|
}
|
package/package.json
CHANGED