@j0hanz/filesystem-mcp 1.16.2 → 1.16.3
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 +18 -14
- package/dist/assets/logo.svg +26 -11
- package/dist/cli.js +1 -1
- package/dist/completions.d.ts +1 -1
- package/dist/completions.js +1 -2
- package/dist/lib/constants.d.ts +2 -0
- package/dist/lib/constants.js +2 -3
- package/dist/lib/fs-helpers.d.ts +1 -1
- package/dist/lib/fs-helpers.js +0 -1
- package/dist/lib/logger.d.ts +3 -4
- package/dist/lib/logger.js +1 -1
- package/dist/lib/paths.d.ts +1 -1
- package/dist/prompts.d.ts +1 -1
- package/dist/prompts.js +11 -11
- package/dist/resources/workflows.js +12 -0
- package/dist/resources.d.ts +1 -1
- package/dist/resources.js +1 -1
- package/dist/schemas.d.ts +4 -4
- package/dist/server/bootstrap.d.ts +1 -10
- package/dist/server/bootstrap.js +165 -95
- package/dist/server/roots-manager.d.ts +3 -2
- package/dist/server/roots-manager.js +30 -4
- package/dist/server/task-store.d.ts +2 -3
- package/dist/server/task-store.js +1 -1
- package/dist/tools/apply-patch.d.ts +1 -1
- package/dist/tools/apply-patch.js +16 -12
- package/dist/tools/calculate-hash.d.ts +1 -1
- package/dist/tools/calculate-hash.js +8 -12
- package/dist/tools/contract.d.ts +5 -0
- package/dist/tools/create-directory.d.ts +1 -1
- package/dist/tools/create-directory.js +7 -10
- package/dist/tools/delete-file.d.ts +1 -1
- package/dist/tools/delete-file.js +12 -11
- package/dist/tools/diff-files.d.ts +1 -1
- package/dist/tools/diff-files.js +8 -11
- package/dist/tools/edit-file.d.ts +1 -1
- package/dist/tools/edit-file.js +12 -11
- package/dist/tools/icons.d.ts +15 -0
- package/dist/tools/icons.js +24 -0
- package/dist/tools/list-directory.d.ts +1 -1
- package/dist/tools/list-directory.js +7 -10
- package/dist/tools/move-file.d.ts +1 -1
- package/dist/tools/move-file.js +12 -11
- package/dist/tools/read-multiple.d.ts +1 -1
- package/dist/tools/read-multiple.js +8 -12
- package/dist/tools/read.d.ts +1 -1
- package/dist/tools/read.js +7 -10
- package/dist/tools/replace-in-files.d.ts +1 -1
- package/dist/tools/replace-in-files.js +11 -13
- package/dist/tools/roots.d.ts +1 -1
- package/dist/tools/roots.js +7 -10
- package/dist/tools/search-content.d.ts +1 -1
- package/dist/tools/search-content.js +8 -13
- package/dist/tools/search-files.d.ts +1 -1
- package/dist/tools/search-files.js +11 -16
- package/dist/tools/shared.d.ts +15 -12
- package/dist/tools/shared.js +84 -56
- package/dist/tools/stat-many.d.ts +1 -1
- package/dist/tools/stat-many.js +8 -12
- package/dist/tools/stat.d.ts +1 -1
- package/dist/tools/stat.js +7 -10
- package/dist/tools/task-support.d.ts +14 -12
- package/dist/tools/task-support.js +98 -92
- package/dist/tools/tree.d.ts +1 -1
- package/dist/tools/tree.js +11 -15
- package/dist/tools/write-file.d.ts +1 -1
- package/dist/tools/write-file.js +12 -11
- package/dist/tools.d.ts +1 -1
- package/package.json +6 -4
|
@@ -4,8 +4,9 @@ import { withAbort } from '../lib/abort.js';
|
|
|
4
4
|
import { ErrorCode, McpError } from '../lib/errors.js';
|
|
5
5
|
import { validatePathForWrite } from '../lib/paths.js';
|
|
6
6
|
import { CreateDirectoryInputSchema, CreateDirectoryOutputSchema, } from '../schemas.js';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { DIR_CREATE_ICONS } from './icons.js';
|
|
8
|
+
import { buildToolErrorResponse, buildToolResponse, executeToolWithDiagnostics, IDEMPOTENT_WRITE_TOOL_ANNOTATIONS, } from './shared.js';
|
|
9
|
+
import { registerStandardTool } from './task-support.js';
|
|
9
10
|
export const CREATE_DIRECTORY_TOOL = {
|
|
10
11
|
name: 'mkdir',
|
|
11
12
|
title: 'Create Directory',
|
|
@@ -13,6 +14,7 @@ export const CREATE_DIRECTORY_TOOL = {
|
|
|
13
14
|
inputSchema: CreateDirectoryInputSchema,
|
|
14
15
|
outputSchema: CreateDirectoryOutputSchema,
|
|
15
16
|
annotations: IDEMPOTENT_WRITE_TOOL_ANNOTATIONS,
|
|
17
|
+
icons: DIR_CREATE_ICONS,
|
|
16
18
|
taskSupport: 'forbidden',
|
|
17
19
|
};
|
|
18
20
|
async function handleCreateDirectory(args, signal) {
|
|
@@ -34,17 +36,16 @@ async function handleCreateDirectory(args, signal) {
|
|
|
34
36
|
});
|
|
35
37
|
}
|
|
36
38
|
export function registerCreateDirectoryTool(server, options = {}) {
|
|
37
|
-
const handler = (args,
|
|
39
|
+
const handler = (args, ctx) => executeToolWithDiagnostics({
|
|
38
40
|
toolName: 'mkdir',
|
|
39
|
-
|
|
41
|
+
ctx,
|
|
40
42
|
outputSchema: CreateDirectoryOutputSchema,
|
|
41
43
|
timedSignal: {},
|
|
42
44
|
context: { path: args.path ?? args.paths?.[0] },
|
|
43
45
|
run: (signal) => handleCreateDirectory(args, signal),
|
|
44
46
|
onError: (error) => buildToolErrorResponse(error, ErrorCode.UNKNOWN, args.path ?? args.paths?.[0]),
|
|
45
47
|
});
|
|
46
|
-
|
|
47
|
-
guard: options.isInitialized,
|
|
48
|
+
registerStandardTool(server, CREATE_DIRECTORY_TOOL, handler, options, {
|
|
48
49
|
progressMessage: (args) => {
|
|
49
50
|
if (args.path && !args.paths?.length) {
|
|
50
51
|
return `🛠 mkdir: ${basename(args.path)}`;
|
|
@@ -65,8 +66,4 @@ export function registerCreateDirectoryTool(server, options = {}) {
|
|
|
65
66
|
return `🛠 mkdir: ${count} directories`;
|
|
66
67
|
},
|
|
67
68
|
});
|
|
68
|
-
const validatedHandler = withValidatedArgs(CreateDirectoryInputSchema, wrappedHandler);
|
|
69
|
-
if (registerToolTaskIfAvailable(server, 'mkdir', CREATE_DIRECTORY_TOOL, validatedHandler, options.iconInfo, options.isInitialized))
|
|
70
|
-
return;
|
|
71
|
-
server.registerTool('mkdir', withDefaultIcons({ ...CREATE_DIRECTORY_TOOL }, options.iconInfo), validatedHandler);
|
|
72
69
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import { type ToolContract, type ToolRegistrationOptions } from './shared.js';
|
|
3
3
|
export declare const DELETE_FILE_TOOL: ToolContract;
|
|
4
4
|
export declare function registerDeleteFileTool(server: McpServer, options?: ToolRegistrationOptions): void;
|
|
@@ -5,8 +5,9 @@ import { ErrorCode, isNodeError, McpError } from '../lib/errors.js';
|
|
|
5
5
|
import { Logger } from '../lib/logger.js';
|
|
6
6
|
import { isAllowedDirectoryRoot, validatePathForWrite } from '../lib/paths.js';
|
|
7
7
|
import { DeleteFileInputSchema, DeleteFileOutputSchema } from '../schemas.js';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
8
|
+
import { FILE_DELETE_ICONS } from './icons.js';
|
|
9
|
+
import { buildToolErrorResponse, buildToolResponse, DESTRUCTIVE_WRITE_TOOL_ANNOTATIONS, executeToolWithDiagnostics, } from './shared.js';
|
|
10
|
+
import { registerStandardTool } from './task-support.js';
|
|
10
11
|
export const DELETE_FILE_TOOL = {
|
|
11
12
|
name: 'rm',
|
|
12
13
|
title: 'Delete File',
|
|
@@ -14,6 +15,7 @@ export const DELETE_FILE_TOOL = {
|
|
|
14
15
|
inputSchema: DeleteFileInputSchema,
|
|
15
16
|
outputSchema: DeleteFileOutputSchema,
|
|
16
17
|
annotations: DESTRUCTIVE_WRITE_TOOL_ANNOTATIONS,
|
|
18
|
+
icons: FILE_DELETE_ICONS,
|
|
17
19
|
gotchas: ['Non-empty directories require `recursive=true`.'],
|
|
18
20
|
taskSupport: 'forbidden',
|
|
19
21
|
};
|
|
@@ -55,13 +57,17 @@ async function handleDeleteFile(args, signal) {
|
|
|
55
57
|
});
|
|
56
58
|
}
|
|
57
59
|
export function registerDeleteFileTool(server, options = {}) {
|
|
58
|
-
const handler = (args,
|
|
60
|
+
const handler = (args, ctx) => executeToolWithDiagnostics({
|
|
59
61
|
toolName: 'rm',
|
|
60
|
-
|
|
62
|
+
ctx,
|
|
61
63
|
outputSchema: DeleteFileOutputSchema,
|
|
62
64
|
timedSignal: {},
|
|
63
65
|
context: { path: args.path },
|
|
64
|
-
run: (signal) =>
|
|
66
|
+
run: async (signal) => {
|
|
67
|
+
const result = await handleDeleteFile(args, signal);
|
|
68
|
+
void ctx.log?.('info', `rm: ${args.path}`);
|
|
69
|
+
return result;
|
|
70
|
+
},
|
|
65
71
|
onError: (error) => {
|
|
66
72
|
if (isNodeError(error)) {
|
|
67
73
|
if (error.code === 'ENOENT') {
|
|
@@ -83,8 +89,7 @@ export function registerDeleteFileTool(server, options = {}) {
|
|
|
83
89
|
return buildToolErrorResponse(error, ErrorCode.UNKNOWN, args.path);
|
|
84
90
|
},
|
|
85
91
|
});
|
|
86
|
-
|
|
87
|
-
guard: options.isInitialized,
|
|
92
|
+
registerStandardTool(server, DELETE_FILE_TOOL, handler, options, {
|
|
88
93
|
progressMessage: (args) => `🛠 rm: ${basename(args.path)}`,
|
|
89
94
|
completionMessage: (args, result) => {
|
|
90
95
|
const name = basename(args.path);
|
|
@@ -93,8 +98,4 @@ export function registerDeleteFileTool(server, options = {}) {
|
|
|
93
98
|
return `🛠 rm: ${name}`;
|
|
94
99
|
},
|
|
95
100
|
});
|
|
96
|
-
const validatedHandler = withValidatedArgs(DeleteFileInputSchema, wrappedHandler);
|
|
97
|
-
if (registerToolTaskIfAvailable(server, 'rm', DELETE_FILE_TOOL, validatedHandler, options.iconInfo, options.isInitialized))
|
|
98
|
-
return;
|
|
99
|
-
server.registerTool('rm', withDefaultIcons({ ...DELETE_FILE_TOOL }, options.iconInfo), validatedHandler);
|
|
100
101
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import { type ToolContract, type ToolRegistrationOptions } from './shared.js';
|
|
3
3
|
export declare const DIFF_FILES_TOOL: ToolContract;
|
|
4
4
|
export declare function registerDiffFilesTool(server: McpServer, options?: ToolRegistrationOptions): void;
|
package/dist/tools/diff-files.js
CHANGED
|
@@ -6,8 +6,9 @@ import { MAX_TEXT_FILE_SIZE } from '../lib/constants.js';
|
|
|
6
6
|
import { ErrorCode, McpError } from '../lib/errors.js';
|
|
7
7
|
import { validateExistingPath } from '../lib/paths.js';
|
|
8
8
|
import { DiffFilesInputSchema, DiffFilesOutputSchema } from '../schemas.js';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { FILE_READ_ICONS } from './icons.js';
|
|
10
|
+
import { buildResourceLink, buildToolErrorResponse, buildToolResponse, executeToolWithDiagnostics, maybeExternalizeTextContent, READ_ONLY_TOOL_ANNOTATIONS, } from './shared.js';
|
|
11
|
+
import { registerStandardTool } from './task-support.js';
|
|
11
12
|
export const DIFF_FILES_TOOL = {
|
|
12
13
|
name: 'diff_files',
|
|
13
14
|
title: 'Diff Files',
|
|
@@ -17,7 +18,8 @@ export const DIFF_FILES_TOOL = {
|
|
|
17
18
|
inputSchema: DiffFilesInputSchema,
|
|
18
19
|
outputSchema: DiffFilesOutputSchema,
|
|
19
20
|
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
20
|
-
|
|
21
|
+
icons: FILE_READ_ICONS,
|
|
22
|
+
taskSupport: 'optional',
|
|
21
23
|
};
|
|
22
24
|
function computeDiffStats(hunks) {
|
|
23
25
|
let linesAdded = 0;
|
|
@@ -101,17 +103,16 @@ async function handleDiffFiles(args, signal, resourceStore) {
|
|
|
101
103
|
]);
|
|
102
104
|
}
|
|
103
105
|
export function registerDiffFilesTool(server, options = {}) {
|
|
104
|
-
const handler = (args,
|
|
106
|
+
const handler = (args, ctx) => executeToolWithDiagnostics({
|
|
105
107
|
toolName: 'diff_files',
|
|
106
|
-
|
|
108
|
+
ctx,
|
|
107
109
|
outputSchema: DiffFilesOutputSchema,
|
|
108
110
|
timedSignal: {},
|
|
109
111
|
context: { path: args.original },
|
|
110
112
|
run: (signal) => handleDiffFiles(args, signal, options.resourceStore),
|
|
111
113
|
onError: (error) => buildToolErrorResponse(error, ErrorCode.UNKNOWN, args.original),
|
|
112
114
|
});
|
|
113
|
-
|
|
114
|
-
guard: options.isInitialized,
|
|
115
|
+
registerStandardTool(server, DIFF_FILES_TOOL, handler, options, {
|
|
115
116
|
progressMessage: (args) => {
|
|
116
117
|
const n1 = basename(args.original);
|
|
117
118
|
const n2 = basename(args.modified);
|
|
@@ -132,8 +133,4 @@ export function registerDiffFilesTool(server, options = {}) {
|
|
|
132
133
|
return `🕮 diff: ${n1} ⟷ ${n2}`;
|
|
133
134
|
},
|
|
134
135
|
});
|
|
135
|
-
const validatedHandler = withValidatedArgs(DiffFilesInputSchema, wrappedHandler);
|
|
136
|
-
if (registerToolTaskIfAvailable(server, 'diff_files', DIFF_FILES_TOOL, validatedHandler, options.iconInfo, options.isInitialized))
|
|
137
|
-
return;
|
|
138
|
-
server.registerTool('diff_files', withDefaultIcons({ ...DIFF_FILES_TOOL }, options.iconInfo), validatedHandler);
|
|
139
136
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import { type ToolContract, type ToolRegistrationOptions } from './shared.js';
|
|
3
3
|
export declare const EDIT_FILE_TOOL: ToolContract;
|
|
4
4
|
export declare function registerEditFileTool(server: McpServer, options?: ToolRegistrationOptions): void;
|
package/dist/tools/edit-file.js
CHANGED
|
@@ -9,8 +9,9 @@ import { atomicWriteFile } from '../lib/fs-helpers.js';
|
|
|
9
9
|
import { Logger } from '../lib/logger.js';
|
|
10
10
|
import { assertAllowedFileAccess, validateExistingPath } from '../lib/paths.js';
|
|
11
11
|
import { EditFileInputSchema, EditFileOutputSchema } from '../schemas.js';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
12
|
+
import { FILE_EDIT_ICONS } from './icons.js';
|
|
13
|
+
import { buildToolErrorResponse, buildToolResponse, DESTRUCTIVE_WRITE_TOOL_ANNOTATIONS, executeToolWithDiagnostics, } from './shared.js';
|
|
14
|
+
import { registerStandardTool } from './task-support.js';
|
|
14
15
|
export const EDIT_FILE_TOOL = {
|
|
15
16
|
name: 'edit',
|
|
16
17
|
title: 'Edit File',
|
|
@@ -20,6 +21,7 @@ export const EDIT_FILE_TOOL = {
|
|
|
20
21
|
inputSchema: EditFileInputSchema,
|
|
21
22
|
outputSchema: EditFileOutputSchema,
|
|
22
23
|
annotations: DESTRUCTIVE_WRITE_TOOL_ANNOTATIONS,
|
|
24
|
+
icons: FILE_EDIT_ICONS,
|
|
23
25
|
nuances: ['Each edit applies to the output of the previous edit.'],
|
|
24
26
|
taskSupport: 'forbidden',
|
|
25
27
|
};
|
|
@@ -229,22 +231,21 @@ async function handleEditFile(args, signal) {
|
|
|
229
231
|
return buildToolResponse(buildEditMessage(args.path, editResult), structured);
|
|
230
232
|
}
|
|
231
233
|
export function registerEditFileTool(server, options = {}) {
|
|
232
|
-
const handler = (args,
|
|
234
|
+
const handler = (args, ctx) => executeToolWithDiagnostics({
|
|
233
235
|
toolName: 'edit',
|
|
234
|
-
|
|
236
|
+
ctx,
|
|
235
237
|
outputSchema: EditFileOutputSchema,
|
|
236
238
|
timedSignal: {},
|
|
237
239
|
context: { path: args.path },
|
|
238
|
-
run: (signal) =>
|
|
240
|
+
run: async (signal) => {
|
|
241
|
+
const result = await handleEditFile(args, signal);
|
|
242
|
+
void ctx.log?.('info', `edit: ${args.path} (${String(result.structuredContent.appliedEdits ?? 0)} edits)`);
|
|
243
|
+
return result;
|
|
244
|
+
},
|
|
239
245
|
onError: (error) => buildToolErrorResponse(error, ErrorCode.UNKNOWN, args.path),
|
|
240
246
|
});
|
|
241
|
-
|
|
242
|
-
guard: options.isInitialized,
|
|
247
|
+
registerStandardTool(server, EDIT_FILE_TOOL, handler, options, {
|
|
243
248
|
progressMessage: buildEditProgressMessage,
|
|
244
249
|
completionMessage: buildEditCompletionMessage,
|
|
245
250
|
});
|
|
246
|
-
const validatedHandler = withValidatedArgs(EditFileInputSchema, wrappedHandler);
|
|
247
|
-
if (registerToolTaskIfAvailable(server, 'edit', EDIT_FILE_TOOL, validatedHandler, options.iconInfo, options.isInitialized))
|
|
248
|
-
return;
|
|
249
|
-
server.registerTool('edit', withDefaultIcons({ ...EDIT_FILE_TOOL }, options.iconInfo), validatedHandler);
|
|
250
251
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Icon } from '@modelcontextprotocol/server';
|
|
2
|
+
/** Document with lines — read, read_many, stat, stat_many, calculate_hash, diff_files */
|
|
3
|
+
export declare const FILE_READ_ICONS: Icon[];
|
|
4
|
+
/** Folder — ls, tree, find, roots */
|
|
5
|
+
export declare const DIRECTORY_ICONS: Icon[];
|
|
6
|
+
/** Magnifying glass — grep */
|
|
7
|
+
export declare const SEARCH_ICONS: Icon[];
|
|
8
|
+
/** Pencil — write, edit, apply_patch, search_and_replace */
|
|
9
|
+
export declare const FILE_EDIT_ICONS: Icon[];
|
|
10
|
+
/** Arrow — mv */
|
|
11
|
+
export declare const FILE_MOVE_ICONS: Icon[];
|
|
12
|
+
/** Trash — rm */
|
|
13
|
+
export declare const FILE_DELETE_ICONS: Icon[];
|
|
14
|
+
/** Folder with plus — mkdir */
|
|
15
|
+
export declare const DIR_CREATE_ICONS: Icon[];
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const MIME = 'image/svg+xml';
|
|
2
|
+
function svgIcon(paths) {
|
|
3
|
+
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">${paths}</svg>`;
|
|
4
|
+
return [
|
|
5
|
+
{
|
|
6
|
+
src: `data:${MIME};base64,${Buffer.from(svg).toString('base64')}`,
|
|
7
|
+
mimeType: MIME,
|
|
8
|
+
},
|
|
9
|
+
];
|
|
10
|
+
}
|
|
11
|
+
/** Document with lines — read, read_many, stat, stat_many, calculate_hash, diff_files */
|
|
12
|
+
export const FILE_READ_ICONS = svgIcon('<path d="M4 1h5l4 4v9a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1z"/><path d="M9 1v4h4"/><path d="M6 8h4M6 11h3"/>');
|
|
13
|
+
/** Folder — ls, tree, find, roots */
|
|
14
|
+
export const DIRECTORY_ICONS = svgIcon('<path d="M2 4h4l2 2h6v7a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1z"/>');
|
|
15
|
+
/** Magnifying glass — grep */
|
|
16
|
+
export const SEARCH_ICONS = svgIcon('<circle cx="6.5" cy="6.5" r="4"/><path d="M10 10l4 4"/>');
|
|
17
|
+
/** Pencil — write, edit, apply_patch, search_and_replace */
|
|
18
|
+
export const FILE_EDIT_ICONS = svgIcon('<path d="M11 2l3 3-9 9H2v-3z"/>');
|
|
19
|
+
/** Arrow — mv */
|
|
20
|
+
export const FILE_MOVE_ICONS = svgIcon('<path d="M2 8h12M10 4l4 4-4 4"/>');
|
|
21
|
+
/** Trash — rm */
|
|
22
|
+
export const FILE_DELETE_ICONS = svgIcon('<path d="M3 4h10M5.5 4V3h5v1"/><path d="M4 4l.7 9.5h6.6L12 4"/>');
|
|
23
|
+
/** Folder with plus — mkdir */
|
|
24
|
+
export const DIR_CREATE_ICONS = svgIcon('<path d="M2 4h4l2 2h6v7a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1z"/><path d="M8 9v3M6.5 10.5h3"/>');
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import { type ToolContract, type ToolRegistrationOptions } from './shared.js';
|
|
3
3
|
export declare const LIST_DIRECTORY_TOOL: ToolContract;
|
|
4
4
|
export declare function registerListDirectoryTool(server: McpServer, options?: ToolRegistrationOptions): void;
|
|
@@ -7,8 +7,9 @@ import { listDirectory } from '../lib/file-operations/metadata.js';
|
|
|
7
7
|
import { createBase64JsonCodec } from '../lib/zod-codecs.js';
|
|
8
8
|
import { formatOperationSummary, joinLines } from '../config.js';
|
|
9
9
|
import { ListDirectoryInputSchema, ListDirectoryOutputSchema, } from '../schemas.js';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
10
|
+
import { DIRECTORY_ICONS } from './icons.js';
|
|
11
|
+
import { buildToolErrorResponse, buildToolResponse, executeToolWithDiagnostics, READ_ONLY_TOOL_ANNOTATIONS, resolvePathOrRoot, } from './shared.js';
|
|
12
|
+
import { registerStandardTool } from './task-support.js';
|
|
12
13
|
export const LIST_DIRECTORY_TOOL = {
|
|
13
14
|
name: 'ls',
|
|
14
15
|
title: 'List Directory',
|
|
@@ -18,6 +19,7 @@ export const LIST_DIRECTORY_TOOL = {
|
|
|
18
19
|
inputSchema: ListDirectoryInputSchema,
|
|
19
20
|
outputSchema: ListDirectoryOutputSchema,
|
|
20
21
|
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
22
|
+
icons: DIRECTORY_ICONS,
|
|
21
23
|
taskSupport: 'optional',
|
|
22
24
|
nuances: ['`pattern` enables filtered recursive traversal up to `maxDepth`.'],
|
|
23
25
|
};
|
|
@@ -194,16 +196,15 @@ async function handleListDirectory(args, signal) {
|
|
|
194
196
|
return buildToolResponse(buildListTextResult(displayResult, nextCursor), buildStructuredListResult(displayResult, nextCursor));
|
|
195
197
|
}
|
|
196
198
|
export function registerListDirectoryTool(server, options = {}) {
|
|
197
|
-
const handler = (args,
|
|
199
|
+
const handler = (args, ctx) => executeToolWithDiagnostics({
|
|
198
200
|
toolName: 'ls',
|
|
199
|
-
|
|
201
|
+
ctx,
|
|
200
202
|
outputSchema: ListDirectoryOutputSchema,
|
|
201
203
|
context: { path: args.path ?? '.' },
|
|
202
204
|
run: (signal) => handleListDirectory(args, signal),
|
|
203
205
|
onError: (error) => buildToolErrorResponse(error, ErrorCode.NOT_DIRECTORY, args.path ?? '.'),
|
|
204
206
|
});
|
|
205
|
-
|
|
206
|
-
guard: options.isInitialized,
|
|
207
|
+
registerStandardTool(server, LIST_DIRECTORY_TOOL, handler, options, {
|
|
207
208
|
progressMessage: (args) => `≣ ls: ${args.path ? basename(args.path) : '.'}`,
|
|
208
209
|
completionMessage: (args, result) => {
|
|
209
210
|
const base = args.path ? basename(args.path) : '.';
|
|
@@ -214,8 +215,4 @@ export function registerListDirectoryTool(server, options = {}) {
|
|
|
214
215
|
return `≣ ls: ${base} • ${count} ${count === 1 ? 'entry' : 'entries'}`;
|
|
215
216
|
},
|
|
216
217
|
});
|
|
217
|
-
const validatedHandler = withValidatedArgs(ListDirectoryInputSchema, wrappedHandler);
|
|
218
|
-
if (registerToolTaskIfAvailable(server, 'ls', LIST_DIRECTORY_TOOL, validatedHandler, options.iconInfo, options.isInitialized))
|
|
219
|
-
return;
|
|
220
|
-
server.registerTool('ls', withDefaultIcons({ ...LIST_DIRECTORY_TOOL }, options.iconInfo), validatedHandler);
|
|
221
218
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import { type ToolContract, type ToolRegistrationOptions } from './shared.js';
|
|
3
3
|
export declare const MOVE_FILE_TOOL: ToolContract;
|
|
4
4
|
export declare function registerMoveFileTool(server: McpServer, options?: ToolRegistrationOptions): void;
|
package/dist/tools/move-file.js
CHANGED
|
@@ -5,8 +5,9 @@ import { ErrorCode, formatUnknownErrorMessage, isNodeError, McpError, } from '..
|
|
|
5
5
|
import { Logger } from '../lib/logger.js';
|
|
6
6
|
import { assertAllowedFileAccess, validateExistingPath, validatePathForWrite, } from '../lib/paths.js';
|
|
7
7
|
import { MoveFileInputSchema, MoveFileOutputSchema } from '../schemas.js';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
8
|
+
import { FILE_MOVE_ICONS } from './icons.js';
|
|
9
|
+
import { buildStructuredError, buildToolErrorResponse, buildToolResponse, DESTRUCTIVE_WRITE_TOOL_ANNOTATIONS, executeToolWithDiagnostics, } from './shared.js';
|
|
10
|
+
import { registerStandardTool } from './task-support.js';
|
|
10
11
|
export const MOVE_FILE_TOOL = {
|
|
11
12
|
name: 'mv',
|
|
12
13
|
title: 'Move File',
|
|
@@ -14,6 +15,7 @@ export const MOVE_FILE_TOOL = {
|
|
|
14
15
|
inputSchema: MoveFileInputSchema,
|
|
15
16
|
outputSchema: MoveFileOutputSchema,
|
|
16
17
|
annotations: DESTRUCTIVE_WRITE_TOOL_ANNOTATIONS,
|
|
18
|
+
icons: FILE_MOVE_ICONS,
|
|
17
19
|
gotchas: [
|
|
18
20
|
'On POSIX, an existing destination is silently overwritten; on Windows, rename fails with EEXIST if destination exists.',
|
|
19
21
|
],
|
|
@@ -138,17 +140,20 @@ async function handleMoveFile(args, signal) {
|
|
|
138
140
|
});
|
|
139
141
|
}
|
|
140
142
|
export function registerMoveFileTool(server, options = {}) {
|
|
141
|
-
const handler = (args,
|
|
143
|
+
const handler = (args, ctx) => executeToolWithDiagnostics({
|
|
142
144
|
toolName: 'mv',
|
|
143
|
-
|
|
145
|
+
ctx,
|
|
144
146
|
outputSchema: MoveFileOutputSchema,
|
|
145
147
|
timedSignal: {},
|
|
146
148
|
context: { path: args.source ?? args.sources?.[0] },
|
|
147
|
-
run: (signal) =>
|
|
149
|
+
run: async (signal) => {
|
|
150
|
+
const result = await handleMoveFile(args, signal);
|
|
151
|
+
void ctx.log?.('info', `mv: ${args.source ?? args.sources?.join(', ') ?? ''} \u2192 ${args.destination}`);
|
|
152
|
+
return result;
|
|
153
|
+
},
|
|
148
154
|
onError: (error) => buildToolErrorResponse(error, ErrorCode.UNKNOWN, args.source ?? args.sources?.[0]),
|
|
149
155
|
});
|
|
150
|
-
|
|
151
|
-
guard: options.isInitialized,
|
|
156
|
+
registerStandardTool(server, MOVE_FILE_TOOL, handler, options, {
|
|
152
157
|
progressMessage: (args) => {
|
|
153
158
|
const dest = basename(args.destination);
|
|
154
159
|
if (args.source && !args.sources?.length) {
|
|
@@ -171,8 +176,4 @@ export function registerMoveFileTool(server, options = {}) {
|
|
|
171
176
|
return `🛠 mv: ${count} items → ${dest}`;
|
|
172
177
|
},
|
|
173
178
|
});
|
|
174
|
-
const validatedHandler = withValidatedArgs(MoveFileInputSchema, wrappedHandler);
|
|
175
|
-
if (registerToolTaskIfAvailable(server, 'mv', MOVE_FILE_TOOL, validatedHandler, options.iconInfo, options.isInitialized))
|
|
176
|
-
return;
|
|
177
|
-
server.registerTool('mv', withDefaultIcons({ ...MOVE_FILE_TOOL }, options.iconInfo), validatedHandler);
|
|
178
179
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import { type ToolContract, type ToolRegistrationOptions } from './shared.js';
|
|
3
3
|
export declare const READ_MANY_TOOL: ToolContract;
|
|
4
4
|
export declare function registerReadMultipleFilesTool(server: McpServer, options?: ToolRegistrationOptions): void;
|
|
@@ -3,8 +3,9 @@ import { DEFAULT_SEARCH_TIMEOUT_MS } from '../lib/constants.js';
|
|
|
3
3
|
import { ErrorCode } from '../lib/errors.js';
|
|
4
4
|
import { readMultipleFiles } from '../lib/file-operations/metadata.js';
|
|
5
5
|
import { ReadMultipleFilesInputSchema, ReadMultipleFilesOutputSchema, } from '../schemas.js';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { FILE_READ_ICONS } from './icons.js';
|
|
7
|
+
import { buildBatchCompletionSuffix, buildBatchPathContext, buildResourceLink, buildStructuredError, buildToolErrorResponse, buildToolResponse, createBatchProgressCallbacks, executeToolWithDiagnostics, maybeExternalizeTextContent, READ_ONLY_TOOL_ANNOTATIONS, resolveFinalProgressCurrent, } from './shared.js';
|
|
8
|
+
import { registerStandardTool } from './task-support.js';
|
|
8
9
|
const READ_MANY_TOOL_NAME = 'read_many';
|
|
9
10
|
const READ_MANY_TOOL_LABEL = '🕮 read_many';
|
|
10
11
|
const FULL_FILE_CONTENTS_DESCRIPTION = 'Full file contents';
|
|
@@ -16,6 +17,7 @@ export const READ_MANY_TOOL = {
|
|
|
16
17
|
inputSchema: ReadMultipleFilesInputSchema,
|
|
17
18
|
outputSchema: ReadMultipleFilesOutputSchema,
|
|
18
19
|
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
20
|
+
icons: FILE_READ_ICONS,
|
|
19
21
|
taskSupport: 'optional',
|
|
20
22
|
};
|
|
21
23
|
function buildReadManyResourceName(filePath) {
|
|
@@ -161,17 +163,17 @@ async function handleReadMultipleFiles(args, signal, resourceStore, onReadComple
|
|
|
161
163
|
return buildToolResponse(payload.text, structured, payload.resourceLinks);
|
|
162
164
|
}
|
|
163
165
|
export function registerReadMultipleFilesTool(server, options = {}) {
|
|
164
|
-
const handler = (args,
|
|
166
|
+
const handler = (args, ctx) => {
|
|
165
167
|
const primaryPath = args.paths[0] ?? '';
|
|
166
168
|
return executeToolWithDiagnostics({
|
|
167
169
|
toolName: READ_MANY_TOOL_NAME,
|
|
168
|
-
|
|
170
|
+
ctx,
|
|
169
171
|
outputSchema: ReadMultipleFilesOutputSchema,
|
|
170
172
|
timedSignal: { timeoutMs: DEFAULT_SEARCH_TIMEOUT_MS },
|
|
171
173
|
context: { path: primaryPath },
|
|
172
174
|
run: async (signal) => {
|
|
173
175
|
const context = buildBatchPathContext(args.paths, 'files');
|
|
174
|
-
const { progress, onItemComplete } = createBatchProgressCallbacks(
|
|
176
|
+
const { progress, onItemComplete } = createBatchProgressCallbacks(ctx, {
|
|
175
177
|
toolLabel: READ_MANY_TOOL_LABEL,
|
|
176
178
|
context,
|
|
177
179
|
totalItems: args.paths.length,
|
|
@@ -194,11 +196,5 @@ export function registerReadMultipleFilesTool(server, options = {}) {
|
|
|
194
196
|
onError: (error) => buildToolErrorResponse(error, ErrorCode.NOT_FILE, primaryPath),
|
|
195
197
|
});
|
|
196
198
|
};
|
|
197
|
-
|
|
198
|
-
guard: options.isInitialized,
|
|
199
|
-
});
|
|
200
|
-
const validatedHandler = withValidatedArgs(ReadMultipleFilesInputSchema, wrappedHandler);
|
|
201
|
-
if (registerToolTaskIfAvailable(server, READ_MANY_TOOL_NAME, READ_MANY_TOOL, validatedHandler, options.iconInfo, options.isInitialized))
|
|
202
|
-
return;
|
|
203
|
-
server.registerTool(READ_MANY_TOOL_NAME, withDefaultIcons({ ...READ_MANY_TOOL }, options.iconInfo), validatedHandler);
|
|
199
|
+
registerStandardTool(server, READ_MANY_TOOL, handler, options);
|
|
204
200
|
}
|
package/dist/tools/read.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import { type ToolContract, type ToolRegistrationOptions } from './shared.js';
|
|
3
3
|
export declare const READ_FILE_TOOL: ToolContract;
|
|
4
4
|
export declare function registerReadFileTool(server: McpServer, options?: ToolRegistrationOptions): void;
|
package/dist/tools/read.js
CHANGED
|
@@ -4,8 +4,9 @@ import { DEFAULT_SEARCH_TIMEOUT_MS, MAX_TEXT_FILE_SIZE, } from '../lib/constants
|
|
|
4
4
|
import { ErrorCode } from '../lib/errors.js';
|
|
5
5
|
import { readFile } from '../lib/fs-helpers.js';
|
|
6
6
|
import { ReadFileInputSchema, ReadFileOutputSchema } from '../schemas.js';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { FILE_READ_ICONS } from './icons.js';
|
|
8
|
+
import { buildResourceLink, buildToolErrorResponse, buildToolResponse, executeToolWithDiagnostics, maybeExternalizeTextContent, READ_ONLY_TOOL_ANNOTATIONS, } from './shared.js';
|
|
9
|
+
import { registerStandardTool } from './task-support.js';
|
|
9
10
|
export const READ_FILE_TOOL = {
|
|
10
11
|
name: 'read',
|
|
11
12
|
title: 'Read File',
|
|
@@ -15,6 +16,7 @@ export const READ_FILE_TOOL = {
|
|
|
15
16
|
inputSchema: ReadFileInputSchema,
|
|
16
17
|
outputSchema: ReadFileOutputSchema,
|
|
17
18
|
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
19
|
+
icons: FILE_READ_ICONS,
|
|
18
20
|
nuances: [
|
|
19
21
|
'Large content is externalized to `filesystem-mcp://result/{id}` and preview is returned inline.',
|
|
20
22
|
],
|
|
@@ -153,22 +155,17 @@ async function handleReadFile(args, signal, resourceStore) {
|
|
|
153
155
|
return buildToolResponse(result.content, structured);
|
|
154
156
|
}
|
|
155
157
|
export function registerReadFileTool(server, options = {}) {
|
|
156
|
-
const handler = (args,
|
|
158
|
+
const handler = (args, ctx) => executeToolWithDiagnostics({
|
|
157
159
|
toolName: READ_TOOL_NAME,
|
|
158
|
-
|
|
160
|
+
ctx,
|
|
159
161
|
outputSchema: ReadFileOutputSchema,
|
|
160
162
|
timedSignal: { timeoutMs: DEFAULT_SEARCH_TIMEOUT_MS },
|
|
161
163
|
context: { path: args.path },
|
|
162
164
|
run: (signal) => handleReadFile(args, signal, options.resourceStore),
|
|
163
165
|
onError: (error) => buildToolErrorResponse(error, ErrorCode.NOT_FILE, args.path),
|
|
164
166
|
});
|
|
165
|
-
|
|
166
|
-
guard: options.isInitialized,
|
|
167
|
+
registerStandardTool(server, READ_FILE_TOOL, handler, options, {
|
|
167
168
|
progressMessage: buildReadProgressMessage,
|
|
168
169
|
completionMessage: buildReadCompletionMessage,
|
|
169
170
|
});
|
|
170
|
-
const validatedHandler = withValidatedArgs(ReadFileInputSchema, wrappedHandler);
|
|
171
|
-
if (registerToolTaskIfAvailable(server, READ_TOOL_NAME, READ_FILE_TOOL, validatedHandler, options.iconInfo, options.isInitialized))
|
|
172
|
-
return;
|
|
173
|
-
server.registerTool(READ_TOOL_NAME, withDefaultIcons({ ...READ_FILE_TOOL }, options.iconInfo), validatedHandler);
|
|
174
171
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import { type ToolContract, type ToolRegistrationOptions } from './shared.js';
|
|
3
3
|
export declare const SEARCH_AND_REPLACE_TOOL: ToolContract;
|
|
4
4
|
export declare function registerSearchAndReplaceTool(server: McpServer, options?: ToolRegistrationOptions): void;
|
|
@@ -10,8 +10,9 @@ import { atomicWriteFile } from '../lib/fs-helpers.js';
|
|
|
10
10
|
import { Logger } from '../lib/logger.js';
|
|
11
11
|
import { validateExistingPath, validatePathForWrite } from '../lib/paths.js';
|
|
12
12
|
import { SearchAndReplaceInputSchema, SearchAndReplaceOutputSchema, } from '../schemas.js';
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
13
|
+
import { FILE_EDIT_ICONS } from './icons.js';
|
|
14
|
+
import { buildStructuredError, buildToolErrorResponse, buildToolResponse, createToolProgressSession, DESTRUCTIVE_WRITE_TOOL_ANNOTATIONS, executeToolWithDiagnostics, resolveFinalProgressCurrent, resolvePathOrRoot, truncateProgressPattern, } from './shared.js';
|
|
15
|
+
import { registerStandardTool } from './task-support.js';
|
|
15
16
|
export const SEARCH_AND_REPLACE_TOOL = {
|
|
16
17
|
name: 'search_and_replace',
|
|
17
18
|
title: 'Search and Replace',
|
|
@@ -22,6 +23,7 @@ export const SEARCH_AND_REPLACE_TOOL = {
|
|
|
22
23
|
inputSchema: SearchAndReplaceInputSchema,
|
|
23
24
|
outputSchema: SearchAndReplaceOutputSchema,
|
|
24
25
|
annotations: DESTRUCTIVE_WRITE_TOOL_ANNOTATIONS,
|
|
26
|
+
icons: FILE_EDIT_ICONS,
|
|
25
27
|
taskSupport: 'optional',
|
|
26
28
|
};
|
|
27
29
|
const MAX_FAILURES = 20;
|
|
@@ -328,9 +330,9 @@ async function handleSearchAndReplace(args, signal, onProgress = () => { }) {
|
|
|
328
330
|
return buildToolResponse(buildSearchAndReplaceText(summary, args.dryRun), buildSearchAndReplaceStructuredResult(summary, args));
|
|
329
331
|
}
|
|
330
332
|
export function registerSearchAndReplaceTool(server, options = {}) {
|
|
331
|
-
const handler = (args,
|
|
333
|
+
const handler = (args, ctx) => executeToolWithDiagnostics({
|
|
332
334
|
toolName: 'search_and_replace',
|
|
333
|
-
|
|
335
|
+
ctx,
|
|
334
336
|
outputSchema: SearchAndReplaceOutputSchema,
|
|
335
337
|
timedSignal: {},
|
|
336
338
|
...(args.path ? { context: { path: args.path } } : {}),
|
|
@@ -338,7 +340,7 @@ export function registerSearchAndReplaceTool(server, options = {}) {
|
|
|
338
340
|
const dryLabel = args.dryRun ? ' [dry run]' : '';
|
|
339
341
|
const truncatedPattern = truncateProgressPattern(args.searchPattern);
|
|
340
342
|
const context = `"${truncatedPattern}" in ${args.filePattern}${dryLabel}`;
|
|
341
|
-
const progress = createToolProgressSession(
|
|
343
|
+
const progress = createToolProgressSession(ctx, `🛠 replace: ${context}`);
|
|
342
344
|
const progressWithMessage = ({ current, total, }) => {
|
|
343
345
|
progress.update({
|
|
344
346
|
current,
|
|
@@ -356,6 +358,9 @@ export function registerSearchAndReplaceTool(server, options = {}) {
|
|
|
356
358
|
if (sc.failedFiles)
|
|
357
359
|
endSuffix += `, ${sc.failedFiles} failed`;
|
|
358
360
|
progress.complete(`🛠 replace: ${context} • ${endSuffix}`, finalCurrent);
|
|
361
|
+
if (!args.dryRun) {
|
|
362
|
+
void ctx.log?.('info', `search_and_replace: ${String(sc.matches ?? 0)} matches in ${String(sc.filesChanged ?? 0)} files`);
|
|
363
|
+
}
|
|
359
364
|
return result;
|
|
360
365
|
}
|
|
361
366
|
catch (error) {
|
|
@@ -365,14 +370,7 @@ export function registerSearchAndReplaceTool(server, options = {}) {
|
|
|
365
370
|
},
|
|
366
371
|
onError: (error) => buildToolErrorResponse(error, ErrorCode.UNKNOWN, args.path),
|
|
367
372
|
});
|
|
368
|
-
|
|
369
|
-
const wrappedHandler = wrapToolHandler(handler, {
|
|
370
|
-
guard: isInitialized,
|
|
371
|
-
});
|
|
372
|
-
const validatedHandler = withValidatedArgs(SearchAndReplaceInputSchema, wrappedHandler);
|
|
373
|
-
if (registerToolTaskIfAvailable(server, 'search_and_replace', SEARCH_AND_REPLACE_TOOL, validatedHandler, options.iconInfo, isInitialized))
|
|
374
|
-
return;
|
|
375
|
-
server.registerTool('search_and_replace', withDefaultIcons({ ...SEARCH_AND_REPLACE_TOOL }, options.iconInfo), validatedHandler);
|
|
373
|
+
registerStandardTool(server, SEARCH_AND_REPLACE_TOOL, handler, options);
|
|
376
374
|
}
|
|
377
375
|
function buildSearchAndReplaceText(summary, dryRun) {
|
|
378
376
|
const failureSuffix = summary.failedFiles > 0 ? ` (${summary.failedFiles} failed)` : '';
|
package/dist/tools/roots.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import { type ToolContract, type ToolRegistrationOptions } from './shared.js';
|
|
3
3
|
export declare const LIST_ALLOWED_DIRECTORIES_TOOL: ToolContract;
|
|
4
4
|
export declare function registerListAllowedDirectoriesTool(server: McpServer, options?: ToolRegistrationOptions): void;
|