@j0hanz/filesystem-mcp 1.19.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +333 -838
- package/dist/cli-help.d.ts +3 -0
- package/dist/cli-help.d.ts.map +1 -0
- package/dist/cli-help.js +169 -0
- package/dist/cli-help.js.map +1 -0
- package/dist/cli.d.ts +28 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +168 -123
- package/dist/cli.js.map +1 -0
- package/dist/core/concurrency.d.ts +70 -0
- package/dist/core/concurrency.d.ts.map +1 -0
- package/dist/core/concurrency.js +173 -0
- package/dist/core/concurrency.js.map +1 -0
- package/dist/core/config.d.ts +19 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +11 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/cursor.d.ts +23 -0
- package/dist/core/cursor.d.ts.map +1 -0
- package/dist/core/cursor.js +62 -0
- package/dist/core/cursor.js.map +1 -0
- package/dist/core/errors.d.ts +96 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +356 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/file-uri.d.ts +24 -0
- package/dist/core/file-uri.d.ts.map +1 -0
- package/dist/core/file-uri.js +52 -0
- package/dist/core/file-uri.js.map +1 -0
- package/dist/core/fmt.d.ts +38 -0
- package/dist/core/fmt.d.ts.map +1 -0
- package/dist/core/fmt.js +109 -0
- package/dist/core/fmt.js.map +1 -0
- package/dist/core/fs.d.ts +108 -0
- package/dist/core/fs.d.ts.map +1 -0
- package/dist/core/fs.js +243 -0
- package/dist/core/fs.js.map +1 -0
- package/dist/core/glob.d.ts +41 -0
- package/dist/core/glob.d.ts.map +1 -0
- package/dist/core/glob.js +399 -0
- package/dist/core/glob.js.map +1 -0
- package/dist/core/input-required.d.ts +147 -0
- package/dist/core/input-required.d.ts.map +1 -0
- package/dist/core/input-required.js +261 -0
- package/dist/core/input-required.js.map +1 -0
- package/dist/core/mime.d.ts +15 -0
- package/dist/core/mime.d.ts.map +1 -0
- package/dist/core/mime.js +188 -0
- package/dist/core/mime.js.map +1 -0
- package/dist/core/observability.d.ts +10 -0
- package/dist/core/observability.d.ts.map +1 -0
- package/dist/core/observability.js +76 -0
- package/dist/core/observability.js.map +1 -0
- package/dist/core/page-store.d.ts +41 -0
- package/dist/core/page-store.d.ts.map +1 -0
- package/dist/core/page-store.js +74 -0
- package/dist/core/page-store.js.map +1 -0
- package/dist/core/path-completer.d.ts +10 -0
- package/dist/core/path-completer.d.ts.map +1 -0
- package/dist/core/path-completer.js +227 -0
- package/dist/core/path-completer.js.map +1 -0
- package/dist/core/path-discovery.d.ts +8 -0
- package/dist/core/path-discovery.d.ts.map +1 -0
- package/dist/core/path-discovery.js +105 -0
- package/dist/core/path-discovery.js.map +1 -0
- package/dist/core/path-utils.d.ts +9 -0
- package/dist/core/path-utils.d.ts.map +1 -0
- package/dist/core/path-utils.js +121 -0
- package/dist/core/path-utils.js.map +1 -0
- package/dist/core/path.d.ts +148 -0
- package/dist/core/path.d.ts.map +1 -0
- package/dist/core/path.js +674 -0
- package/dist/core/path.js.map +1 -0
- package/dist/core/primitives.d.ts +23 -0
- package/dist/core/primitives.d.ts.map +1 -0
- package/dist/core/primitives.js +54 -0
- package/dist/core/primitives.js.map +1 -0
- package/dist/core/read.d.ts +74 -0
- package/dist/core/read.d.ts.map +1 -0
- package/dist/core/read.js +562 -0
- package/dist/core/read.js.map +1 -0
- package/dist/core/schema.d.ts +139 -0
- package/dist/core/schema.d.ts.map +1 -0
- package/dist/core/schema.js +345 -0
- package/dist/core/schema.js.map +1 -0
- package/dist/core/search.d.ts +100 -0
- package/dist/core/search.d.ts.map +1 -0
- package/dist/core/search.js +248 -0
- package/dist/core/search.js.map +1 -0
- package/dist/core/sensitive.d.ts +6 -0
- package/dist/core/sensitive.d.ts.map +1 -0
- package/dist/core/sensitive.js +142 -0
- package/dist/core/sensitive.js.map +1 -0
- package/dist/core/store.d.ts +57 -0
- package/dist/core/store.d.ts.map +1 -0
- package/dist/core/store.js +162 -0
- package/dist/core/store.js.map +1 -0
- package/dist/core/util.d.ts +26 -0
- package/dist/core/util.d.ts.map +1 -0
- package/dist/core/util.js +66 -0
- package/dist/core/util.js.map +1 -0
- package/dist/core/watcher-registry.d.ts +68 -0
- package/dist/core/watcher-registry.d.ts.map +1 -0
- package/dist/core/watcher-registry.js +312 -0
- package/dist/core/watcher-registry.js.map +1 -0
- package/dist/http-policy.d.ts +121 -0
- package/dist/http-policy.d.ts.map +1 -0
- package/dist/http-policy.js +340 -0
- package/dist/http-policy.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +77 -41
- package/dist/index.js.map +1 -0
- package/dist/instructions.d.ts +12 -0
- package/dist/instructions.d.ts.map +1 -0
- package/dist/instructions.js +71 -0
- package/dist/instructions.js.map +1 -0
- package/dist/prompts.d.ts +8 -6
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +74 -168
- package/dist/prompts.js.map +1 -0
- package/dist/resources.d.ts +73 -9
- package/dist/resources.d.ts.map +1 -0
- package/dist/resources.js +392 -163
- package/dist/resources.js.map +1 -0
- package/dist/server.d.ts +62 -1
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +139 -1
- package/dist/server.js.map +1 -0
- package/dist/tools/batch.d.ts +89 -0
- package/dist/tools/batch.d.ts.map +1 -0
- package/dist/tools/batch.js +157 -0
- package/dist/tools/batch.js.map +1 -0
- package/dist/tools/create.d.ts +2 -0
- package/dist/tools/create.d.ts.map +1 -0
- package/dist/tools/create.js +142 -0
- package/dist/tools/create.js.map +1 -0
- package/dist/tools/define.d.ts +110 -0
- package/dist/tools/define.d.ts.map +1 -0
- package/dist/tools/define.js +394 -0
- package/dist/tools/define.js.map +1 -0
- package/dist/tools/delete-file.d.ts +2 -4
- package/dist/tools/delete-file.d.ts.map +1 -0
- package/dist/tools/delete-file.js +330 -87
- package/dist/tools/delete-file.js.map +1 -0
- package/dist/tools/diff.d.ts +2 -0
- package/dist/tools/diff.d.ts.map +1 -0
- package/dist/tools/diff.js +94 -0
- package/dist/tools/diff.js.map +1 -0
- package/dist/tools/edit.d.ts +2 -0
- package/dist/tools/edit.d.ts.map +1 -0
- package/dist/tools/edit.js +442 -0
- package/dist/tools/edit.js.map +1 -0
- package/dist/tools/index.d.ts +26 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +52 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/list.d.ts +2 -0
- package/dist/tools/list.d.ts.map +1 -0
- package/dist/tools/list.js +291 -0
- package/dist/tools/list.js.map +1 -0
- package/dist/tools/move.d.ts +2 -0
- package/dist/tools/move.d.ts.map +1 -0
- package/dist/tools/move.js +321 -0
- package/dist/tools/move.js.map +1 -0
- package/dist/tools/patch.d.ts +2 -0
- package/dist/tools/patch.d.ts.map +1 -0
- package/dist/tools/patch.js +155 -0
- package/dist/tools/patch.js.map +1 -0
- package/dist/tools/progress.d.ts +52 -0
- package/dist/tools/progress.d.ts.map +1 -0
- package/dist/tools/progress.js +172 -0
- package/dist/tools/progress.js.map +1 -0
- package/dist/tools/read.d.ts +2 -4
- package/dist/tools/read.d.ts.map +1 -0
- package/dist/tools/read.js +398 -152
- package/dist/tools/read.js.map +1 -0
- package/dist/tools/replace-in-files.d.ts +2 -4
- package/dist/tools/replace-in-files.d.ts.map +1 -0
- package/dist/tools/replace-in-files.js +435 -264
- package/dist/tools/replace-in-files.js.map +1 -0
- package/dist/tools/roots.d.ts +2 -4
- package/dist/tools/roots.d.ts.map +1 -0
- package/dist/tools/roots.js +29 -52
- package/dist/tools/roots.js.map +1 -0
- package/dist/tools/search-content.d.ts +2 -4
- package/dist/tools/search-content.d.ts.map +1 -0
- package/dist/tools/search-content.js +262 -228
- package/dist/tools/search-content.js.map +1 -0
- package/dist/tools/search-files.d.ts +2 -4
- package/dist/tools/search-files.d.ts.map +1 -0
- package/dist/tools/search-files.js +162 -161
- package/dist/tools/search-files.js.map +1 -0
- package/dist/tools/stat.d.ts +2 -4
- package/dist/tools/stat.d.ts.map +1 -0
- package/dist/tools/stat.js +202 -62
- package/dist/tools/stat.js.map +1 -0
- package/dist/transport/http.d.ts +5 -0
- package/dist/transport/http.d.ts.map +1 -0
- package/dist/transport/http.js +276 -0
- package/dist/transport/http.js.map +1 -0
- package/dist/transport/shared.d.ts +45 -0
- package/dist/transport/shared.d.ts.map +1 -0
- package/dist/transport/shared.js +65 -0
- package/dist/transport/shared.js.map +1 -0
- package/dist/transport/stdio.d.ts +32 -0
- package/dist/transport/stdio.d.ts.map +1 -0
- package/dist/transport/stdio.js +279 -0
- package/dist/transport/stdio.js.map +1 -0
- package/dist/transport.d.ts +5 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +4 -0
- package/dist/transport.js.map +1 -0
- package/package.json +37 -46
- package/dist/assets/logo.svg +0 -35
- package/dist/completions.d.ts +0 -2
- package/dist/completions.js +0 -572
- package/dist/config.d.ts +0 -119
- package/dist/config.js +0 -31
- package/dist/lib/abort.d.ts +0 -7
- package/dist/lib/abort.js +0 -81
- package/dist/lib/constants.d.ts +0 -42
- package/dist/lib/constants.js +0 -313
- package/dist/lib/errors.d.ts +0 -28
- package/dist/lib/errors.js +0 -301
- package/dist/lib/file-operations/core.d.ts +0 -53
- package/dist/lib/file-operations/core.js +0 -144
- package/dist/lib/file-operations/metadata.d.ts +0 -77
- package/dist/lib/file-operations/metadata.js +0 -878
- package/dist/lib/file-operations/search.d.ts +0 -46
- package/dist/lib/file-operations/search.js +0 -1194
- package/dist/lib/file-operations/traversal.d.ts +0 -40
- package/dist/lib/file-operations/traversal.js +0 -310
- package/dist/lib/fs-helpers.d.ts +0 -46
- package/dist/lib/fs-helpers.js +0 -606
- package/dist/lib/globs.d.ts +0 -2
- package/dist/lib/globs.js +0 -19
- package/dist/lib/logger.d.ts +0 -27
- package/dist/lib/logger.js +0 -91
- package/dist/lib/observability.d.ts +0 -33
- package/dist/lib/observability.js +0 -373
- package/dist/lib/paths.d.ts +0 -35
- package/dist/lib/paths.js +0 -634
- package/dist/lib/resource-store.d.ts +0 -28
- package/dist/lib/resource-store.js +0 -195
- package/dist/lib/utils.d.ts +0 -7
- package/dist/lib/utils.js +0 -37
- package/dist/lib/zod-codecs.d.ts +0 -2
- package/dist/lib/zod-codecs.js +0 -18
- package/dist/pkg-info.d.ts +0 -7
- package/dist/pkg-info.js +0 -9
- package/dist/resources/generated-instructions.d.ts +0 -1
- package/dist/resources/generated-instructions.js +0 -105
- package/dist/resources/tool-catalog.d.ts +0 -2
- package/dist/resources/tool-catalog.js +0 -78
- package/dist/resources/tool-info.d.ts +0 -9
- package/dist/resources/tool-info.js +0 -206
- package/dist/resources/workflows.d.ts +0 -1
- package/dist/resources/workflows.js +0 -72
- package/dist/schemas.d.ts +0 -505
- package/dist/schemas.js +0 -676
- package/dist/server/bootstrap.d.ts +0 -6
- package/dist/server/bootstrap.js +0 -563
- package/dist/server/event-store.d.ts +0 -18
- package/dist/server/event-store.js +0 -71
- package/dist/server/roots-manager.d.ts +0 -28
- package/dist/server/roots-manager.js +0 -227
- package/dist/server/task-store.d.ts +0 -10
- package/dist/server/task-store.js +0 -91
- package/dist/tools/apply-patch.d.ts +0 -4
- package/dist/tools/apply-patch.js +0 -235
- package/dist/tools/calculate-hash.d.ts +0 -4
- package/dist/tools/calculate-hash.js +0 -187
- package/dist/tools/contract.d.ts +0 -50
- package/dist/tools/contract.js +0 -1
- package/dist/tools/create-directory.d.ts +0 -4
- package/dist/tools/create-directory.js +0 -68
- package/dist/tools/diff-files.d.ts +0 -4
- package/dist/tools/diff-files.js +0 -136
- package/dist/tools/edit-file.d.ts +0 -4
- package/dist/tools/edit-file.js +0 -256
- package/dist/tools/icons.d.ts +0 -15
- package/dist/tools/icons.js +0 -24
- package/dist/tools/list-directory.d.ts +0 -4
- package/dist/tools/list-directory.js +0 -218
- package/dist/tools/move-file.d.ts +0 -4
- package/dist/tools/move-file.js +0 -178
- package/dist/tools/read-multiple.d.ts +0 -4
- package/dist/tools/read-multiple.js +0 -207
- package/dist/tools/shared.d.ts +0 -172
- package/dist/tools/shared.js +0 -599
- package/dist/tools/stat-many.d.ts +0 -4
- package/dist/tools/stat-many.js +0 -104
- package/dist/tools/task-support.d.ts +0 -29
- package/dist/tools/task-support.js +0 -472
- package/dist/tools/tree.d.ts +0 -4
- package/dist/tools/tree.js +0 -102
- package/dist/tools/write-file.d.ts +0 -4
- package/dist/tools/write-file.js +0 -60
- package/dist/tools.d.ts +0 -5
- package/dist/tools.js +0 -54
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto';
|
|
2
|
-
import { createReadStream } from 'node:fs';
|
|
3
|
-
import { stat } from 'node:fs/promises';
|
|
4
|
-
import { basename, relative, win32 } from 'node:path';
|
|
5
|
-
import { pipeline } from 'node:stream/promises';
|
|
6
|
-
import { assertNotAborted, withAbort } from '../lib/abort.js';
|
|
7
|
-
import { PARALLEL_CONCURRENCY } from '../lib/constants.js';
|
|
8
|
-
import { classifyError, ErrorCode } from '../lib/errors.js';
|
|
9
|
-
import { isIgnoredByGitignore, loadRootGitignore, } from '../lib/file-operations/core.js';
|
|
10
|
-
import { globEntries } from '../lib/file-operations/traversal.js';
|
|
11
|
-
import { validateExistingPath } from '../lib/paths.js';
|
|
12
|
-
import { CalculateHashInputSchema, CalculateHashOutputSchema, } from '../schemas.js';
|
|
13
|
-
import { FILE_READ_ICONS } from './icons.js';
|
|
14
|
-
import { buildToolErrorResponse, buildToolResponse, createToolProgressSession, executeToolWithDiagnostics, READ_ONLY_TOOL_ANNOTATIONS, resolveFinalProgressCurrent, } from './shared.js';
|
|
15
|
-
import { registerStandardTool } from './task-support.js';
|
|
16
|
-
const WINDOWS_PATH_SEPARATOR = /\\/gu;
|
|
17
|
-
export const CALCULATE_HASH_TOOL = {
|
|
18
|
-
name: 'calculate_hash',
|
|
19
|
-
title: 'Calculate Hash',
|
|
20
|
-
description: 'Calculate SHA-256 hash of a file or directory.',
|
|
21
|
-
inputSchema: CalculateHashInputSchema,
|
|
22
|
-
outputSchema: CalculateHashOutputSchema,
|
|
23
|
-
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
24
|
-
icons: FILE_READ_ICONS,
|
|
25
|
-
nuances: [
|
|
26
|
-
'Directory hashing respects root `.gitignore` and sorts paths for stable output.',
|
|
27
|
-
],
|
|
28
|
-
taskSupport: 'optional',
|
|
29
|
-
};
|
|
30
|
-
async function hashFile(filePath, encoding, signal) {
|
|
31
|
-
const hasher = createHash('sha256');
|
|
32
|
-
await pipeline(createReadStream(filePath, { signal, highWaterMark: 64 * 1024 }), hasher, { signal });
|
|
33
|
-
return encoding ? hasher.digest(encoding) : hasher.digest();
|
|
34
|
-
}
|
|
35
|
-
function toStableRelativePath(root, entryPath) {
|
|
36
|
-
const relativePath = relative(root, entryPath);
|
|
37
|
-
return relativePath.includes(win32.sep)
|
|
38
|
-
? relativePath.replace(WINDOWS_PATH_SEPARATOR, '/')
|
|
39
|
-
: relativePath;
|
|
40
|
-
}
|
|
41
|
-
function comparePaths(left, right) {
|
|
42
|
-
if (left.path < right.path)
|
|
43
|
-
return -1;
|
|
44
|
-
if (left.path > right.path)
|
|
45
|
-
return 1;
|
|
46
|
-
return 0;
|
|
47
|
-
}
|
|
48
|
-
function updateCompositeHash(hasher, pathLengthBytes, relativePath, fileHash) {
|
|
49
|
-
const relativePathBytes = Buffer.from(relativePath, 'utf8');
|
|
50
|
-
pathLengthBytes.writeUInt32BE(relativePathBytes.length, 0);
|
|
51
|
-
hasher.update(pathLengthBytes);
|
|
52
|
-
hasher.update(relativePathBytes);
|
|
53
|
-
hasher.update(fileHash);
|
|
54
|
-
}
|
|
55
|
-
async function hashDirectory(dirPath, options = {}) {
|
|
56
|
-
const { signal, onProgress } = options;
|
|
57
|
-
const gitignoreMatcher = await loadRootGitignore(dirPath, signal);
|
|
58
|
-
// Phase 1: collect all file paths that pass gitignore filtering.
|
|
59
|
-
const filteredPaths = [];
|
|
60
|
-
for await (const entry of globEntries({
|
|
61
|
-
cwd: dirPath,
|
|
62
|
-
pattern: '**/*',
|
|
63
|
-
excludePatterns: [],
|
|
64
|
-
includeHidden: false,
|
|
65
|
-
baseNameMatch: false,
|
|
66
|
-
caseSensitiveMatch: true,
|
|
67
|
-
followSymbolicLinks: false,
|
|
68
|
-
onlyFiles: true,
|
|
69
|
-
stats: false,
|
|
70
|
-
suppressErrors: true,
|
|
71
|
-
})) {
|
|
72
|
-
assertNotAborted(signal);
|
|
73
|
-
if (gitignoreMatcher &&
|
|
74
|
-
isIgnoredByGitignore(gitignoreMatcher, dirPath, entry.path)) {
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
filteredPaths.push({
|
|
78
|
-
filePath: entry.path,
|
|
79
|
-
relativePath: toStableRelativePath(dirPath, entry.path),
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
assertNotAborted(signal);
|
|
83
|
-
const concurrency = Math.min(PARALLEL_CONCURRENCY, 8);
|
|
84
|
-
const entries = [];
|
|
85
|
-
let filesHashed = 0;
|
|
86
|
-
const totalFiles = filteredPaths.length;
|
|
87
|
-
const taskQueue = filteredPaths;
|
|
88
|
-
const worker = async () => {
|
|
89
|
-
while (taskQueue.length > 0) {
|
|
90
|
-
const task = taskQueue.pop();
|
|
91
|
-
if (!task)
|
|
92
|
-
break;
|
|
93
|
-
assertNotAborted(signal);
|
|
94
|
-
const fileHash = await hashFile(task.filePath, undefined, signal);
|
|
95
|
-
entries.push({ path: task.relativePath, hash: fileHash });
|
|
96
|
-
filesHashed++;
|
|
97
|
-
onProgress?.({ current: filesHashed, total: totalFiles });
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
await Promise.all(Array.from({ length: concurrency }, () => worker()));
|
|
101
|
-
onProgress?.({ current: filesHashed, total: totalFiles });
|
|
102
|
-
assertNotAborted(signal);
|
|
103
|
-
// Sort by path with byte-wise semantics for deterministic ordering.
|
|
104
|
-
entries.sort(comparePaths);
|
|
105
|
-
// Create composite hash using length-delimited paths and binary digests.
|
|
106
|
-
const compositeHasher = createHash('sha256');
|
|
107
|
-
const pathLengthBytes = Buffer.allocUnsafe(4);
|
|
108
|
-
for (const { path: filePath, hash: fileHash } of entries) {
|
|
109
|
-
updateCompositeHash(compositeHasher, pathLengthBytes, filePath, fileHash);
|
|
110
|
-
assertNotAborted(signal);
|
|
111
|
-
}
|
|
112
|
-
return {
|
|
113
|
-
hash: compositeHasher.digest('hex'),
|
|
114
|
-
fileCount: entries.length,
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
async function handleCalculateHash(args, signal, onProgress) {
|
|
118
|
-
const validPath = await validateExistingPath(args.path, signal);
|
|
119
|
-
// Check if path is a directory or file
|
|
120
|
-
const stats = await withAbort(stat(validPath), signal);
|
|
121
|
-
if (stats.isDirectory()) {
|
|
122
|
-
// Hash directory: composite hash of all files
|
|
123
|
-
const { hash, fileCount } = await hashDirectory(validPath, {
|
|
124
|
-
...(signal ? { signal } : {}),
|
|
125
|
-
...(onProgress ? { onProgress } : {}),
|
|
126
|
-
});
|
|
127
|
-
return buildToolResponse(`${hash} (${fileCount} files)`, {
|
|
128
|
-
ok: true,
|
|
129
|
-
path: validPath,
|
|
130
|
-
hash,
|
|
131
|
-
isDirectory: true,
|
|
132
|
-
fileCount,
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
else {
|
|
136
|
-
// Hash single file
|
|
137
|
-
const hash = await hashFile(validPath, 'hex', signal);
|
|
138
|
-
onProgress?.({ current: 1 });
|
|
139
|
-
return buildToolResponse(hash, {
|
|
140
|
-
ok: true,
|
|
141
|
-
path: validPath,
|
|
142
|
-
hash,
|
|
143
|
-
isDirectory: false,
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
export function registerCalculateHashTool(server, options = {}) {
|
|
148
|
-
const handler = (args, ctx) => executeToolWithDiagnostics({
|
|
149
|
-
toolName: 'calculate_hash',
|
|
150
|
-
ctx,
|
|
151
|
-
outputSchema: CalculateHashOutputSchema,
|
|
152
|
-
timedSignal: {},
|
|
153
|
-
context: { path: args.path },
|
|
154
|
-
run: async (signal) => {
|
|
155
|
-
const baseName = basename(args.path);
|
|
156
|
-
const progress = createToolProgressSession(ctx, `${CALCULATE_HASH_TOOL.title}: ${baseName}`);
|
|
157
|
-
const progressWithMessage = ({ current, total, }) => {
|
|
158
|
-
progress.update({
|
|
159
|
-
current,
|
|
160
|
-
...(total !== undefined ? { total } : {}),
|
|
161
|
-
message: `${CALCULATE_HASH_TOOL.title}: ${baseName} [${current} files]`,
|
|
162
|
-
});
|
|
163
|
-
};
|
|
164
|
-
try {
|
|
165
|
-
const result = await handleCalculateHash(args, signal, progressWithMessage);
|
|
166
|
-
const sc = result.structuredContent;
|
|
167
|
-
const totalFiles = sc.fileCount ?? 1;
|
|
168
|
-
const finalCurrent = resolveFinalProgressCurrent(progress, totalFiles + 1);
|
|
169
|
-
let suffix;
|
|
170
|
-
if (sc.fileCount !== undefined && sc.fileCount > 1) {
|
|
171
|
-
suffix = `${sc.fileCount} files • ${(sc.hash ?? '').slice(0, 8)}…`;
|
|
172
|
-
}
|
|
173
|
-
else {
|
|
174
|
-
suffix = `${(sc.hash ?? '').slice(0, 8)}…`;
|
|
175
|
-
}
|
|
176
|
-
progress.complete(`${CALCULATE_HASH_TOOL.title}: ${baseName} • ${suffix}`, finalCurrent);
|
|
177
|
-
return result;
|
|
178
|
-
}
|
|
179
|
-
catch (error) {
|
|
180
|
-
progress.fail(`${CALCULATE_HASH_TOOL.title}: ${baseName} • ${classifyError(error)}`);
|
|
181
|
-
throw error;
|
|
182
|
-
}
|
|
183
|
-
},
|
|
184
|
-
onError: (error) => buildToolErrorResponse(error, ErrorCode.UNKNOWN, args.path),
|
|
185
|
-
});
|
|
186
|
-
registerStandardTool(server, CALCULATE_HASH_TOOL, handler, options);
|
|
187
|
-
}
|
package/dist/tools/contract.d.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import type { Icon } from '@modelcontextprotocol/server';
|
|
2
|
-
import type { ZodType } from 'zod';
|
|
3
|
-
export interface ToolContract {
|
|
4
|
-
/**
|
|
5
|
-
* The unique name of the tool (e.g., "read", "grep").
|
|
6
|
-
* This name is used in registration and client calls.
|
|
7
|
-
*/
|
|
8
|
-
name: string;
|
|
9
|
-
/**
|
|
10
|
-
* A short human-readable title for documentation (e.g., "Read File").
|
|
11
|
-
*/
|
|
12
|
-
title: string;
|
|
13
|
-
/**
|
|
14
|
-
* A detailed description of what the tool does.
|
|
15
|
-
*/
|
|
16
|
-
description: string;
|
|
17
|
-
/**
|
|
18
|
-
* Zod schema for the tool's input arguments.
|
|
19
|
-
*/
|
|
20
|
-
inputSchema: ZodType;
|
|
21
|
-
/**
|
|
22
|
-
* Zod schema for the tool's output result (optional).
|
|
23
|
-
*/
|
|
24
|
-
outputSchema?: ZodType;
|
|
25
|
-
/**
|
|
26
|
-
* Optional annotations for tool behavior hints.
|
|
27
|
-
*/
|
|
28
|
-
annotations?: {
|
|
29
|
-
readOnlyHint?: boolean;
|
|
30
|
-
idempotentHint?: boolean;
|
|
31
|
-
destructiveHint?: boolean;
|
|
32
|
-
openWorldHint?: boolean;
|
|
33
|
-
};
|
|
34
|
-
/**
|
|
35
|
-
* Specific usage nuances or edge cases for documentation.
|
|
36
|
-
*/
|
|
37
|
-
nuances?: string[];
|
|
38
|
-
/**
|
|
39
|
-
* Common pitfalls or warnings for documentation.
|
|
40
|
-
*/
|
|
41
|
-
gotchas?: string[];
|
|
42
|
-
/**
|
|
43
|
-
* Optional icons for display in user interfaces.
|
|
44
|
-
*/
|
|
45
|
-
icons?: Icon[];
|
|
46
|
-
/**
|
|
47
|
-
* Task support level for the tool. Defaults to 'forbidden'.
|
|
48
|
-
*/
|
|
49
|
-
taskSupport?: 'optional' | 'required' | 'forbidden';
|
|
50
|
-
}
|
package/dist/tools/contract.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
|
-
import { type ToolContract, type ToolRegistrationOptions } from './shared.js';
|
|
3
|
-
export declare const CREATE_DIRECTORY_TOOL: ToolContract;
|
|
4
|
-
export declare function registerCreateDirectoryTool(server: McpServer, options?: ToolRegistrationOptions): void;
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { mkdir } from 'node:fs/promises';
|
|
2
|
-
import { basename } from 'node:path';
|
|
3
|
-
import { withAbort } from '../lib/abort.js';
|
|
4
|
-
import { ErrorCode, McpError } from '../lib/errors.js';
|
|
5
|
-
import { validatePathForWrite } from '../lib/paths.js';
|
|
6
|
-
import { CreateDirectoryInputSchema, CreateDirectoryOutputSchema, } from '../schemas.js';
|
|
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';
|
|
10
|
-
export const CREATE_DIRECTORY_TOOL = {
|
|
11
|
-
name: 'mkdir',
|
|
12
|
-
title: 'Create Directory',
|
|
13
|
-
description: 'Create a new directory at the specified path (recursive).',
|
|
14
|
-
inputSchema: CreateDirectoryInputSchema,
|
|
15
|
-
outputSchema: CreateDirectoryOutputSchema,
|
|
16
|
-
annotations: IDEMPOTENT_WRITE_TOOL_ANNOTATIONS,
|
|
17
|
-
icons: DIR_CREATE_ICONS,
|
|
18
|
-
taskSupport: 'forbidden',
|
|
19
|
-
};
|
|
20
|
-
async function handleCreateDirectory(args, signal) {
|
|
21
|
-
const allPaths = [];
|
|
22
|
-
if (args.path)
|
|
23
|
-
allPaths.push(args.path);
|
|
24
|
-
if (args.paths)
|
|
25
|
-
allPaths.push(...args.paths);
|
|
26
|
-
if (allPaths.length === 0) {
|
|
27
|
-
throw new McpError(ErrorCode.INVALID_INPUT, 'No paths provided to create.');
|
|
28
|
-
}
|
|
29
|
-
const validPaths = await Promise.all(allPaths.map((p) => validatePathForWrite(p, signal)));
|
|
30
|
-
await Promise.all(validPaths.map((p) => withAbort(mkdir(p, { recursive: true }), signal)));
|
|
31
|
-
const createdPath = validPaths.length === 1 ? validPaths[0] : undefined;
|
|
32
|
-
return buildToolResponse(`Successfully created ${validPaths.length} director${validPaths.length === 1 ? 'y' : 'ies'}`, {
|
|
33
|
-
ok: true,
|
|
34
|
-
...(createdPath ? { path: createdPath } : {}),
|
|
35
|
-
paths: validPaths,
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
export function registerCreateDirectoryTool(server, options = {}) {
|
|
39
|
-
const handler = (args, ctx) => executeToolWithDiagnostics({
|
|
40
|
-
toolName: 'mkdir',
|
|
41
|
-
ctx,
|
|
42
|
-
outputSchema: CreateDirectoryOutputSchema,
|
|
43
|
-
timedSignal: {},
|
|
44
|
-
context: { path: args.path ?? args.paths?.[0] },
|
|
45
|
-
run: (signal) => handleCreateDirectory(args, signal),
|
|
46
|
-
onError: (error) => buildToolErrorResponse(error, ErrorCode.UNKNOWN, args.path ?? args.paths?.[0]),
|
|
47
|
-
});
|
|
48
|
-
registerStandardTool(server, CREATE_DIRECTORY_TOOL, handler, options, {
|
|
49
|
-
progressMessage: (args) => {
|
|
50
|
-
if (args.path && !args.paths?.length) {
|
|
51
|
-
return `${CREATE_DIRECTORY_TOOL.title}: ${basename(args.path)}`;
|
|
52
|
-
}
|
|
53
|
-
const count = (args.path ? 1 : 0) + (args.paths?.length ?? 0);
|
|
54
|
-
return `${CREATE_DIRECTORY_TOOL.title}: ${count} directories`;
|
|
55
|
-
},
|
|
56
|
-
completionMessage: (args, result) => {
|
|
57
|
-
if (args.path && !args.paths?.length) {
|
|
58
|
-
const name = basename(args.path);
|
|
59
|
-
if (result.isError)
|
|
60
|
-
return `${CREATE_DIRECTORY_TOOL.title}: ${name} • ${result.errorCode}`;
|
|
61
|
-
}
|
|
62
|
-
const count = (args.path ? 1 : 0) + (args.paths?.length ?? 0);
|
|
63
|
-
if (result.isError)
|
|
64
|
-
return `${CREATE_DIRECTORY_TOOL.title}: ${count} directories • ${result.errorCode}`;
|
|
65
|
-
return `${CREATE_DIRECTORY_TOOL.title}: ${count} directories`;
|
|
66
|
-
},
|
|
67
|
-
});
|
|
68
|
-
}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
|
-
import { type ToolContract, type ToolRegistrationOptions } from './shared.js';
|
|
3
|
-
export declare const DIFF_FILES_TOOL: ToolContract;
|
|
4
|
-
export declare function registerDiffFilesTool(server: McpServer, options?: ToolRegistrationOptions): void;
|
package/dist/tools/diff-files.js
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import { readFile, stat } from 'node:fs/promises';
|
|
2
|
-
import { basename } from 'node:path';
|
|
3
|
-
import { formatPatch, structuredPatch } from 'diff';
|
|
4
|
-
import { withAbort } from '../lib/abort.js';
|
|
5
|
-
import { MAX_TEXT_FILE_SIZE } from '../lib/constants.js';
|
|
6
|
-
import { ErrorCode, McpError } from '../lib/errors.js';
|
|
7
|
-
import { validateExistingPath } from '../lib/paths.js';
|
|
8
|
-
import { DiffFilesInputSchema, DiffFilesOutputSchema } from '../schemas.js';
|
|
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';
|
|
12
|
-
export const DIFF_FILES_TOOL = {
|
|
13
|
-
name: 'diff_files',
|
|
14
|
-
title: 'Diff Files',
|
|
15
|
-
description: 'Generate a unified diff between two files. ' +
|
|
16
|
-
'Output feeds directly into `apply_patch`. ' +
|
|
17
|
-
'`isIdentical=true` means files match \u2014 no patch needed.',
|
|
18
|
-
inputSchema: DiffFilesInputSchema,
|
|
19
|
-
outputSchema: DiffFilesOutputSchema,
|
|
20
|
-
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
21
|
-
icons: FILE_READ_ICONS,
|
|
22
|
-
taskSupport: 'optional',
|
|
23
|
-
};
|
|
24
|
-
function computeDiffStats(hunks) {
|
|
25
|
-
let linesAdded = 0;
|
|
26
|
-
let linesRemoved = 0;
|
|
27
|
-
for (const hunk of hunks) {
|
|
28
|
-
for (const line of hunk.lines) {
|
|
29
|
-
if (line.startsWith('+') && !line.startsWith('+++'))
|
|
30
|
-
linesAdded++;
|
|
31
|
-
else if (line.startsWith('-') && !line.startsWith('---'))
|
|
32
|
-
linesRemoved++;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return { linesAdded, linesRemoved, hunksCount: hunks.length };
|
|
36
|
-
}
|
|
37
|
-
function assertDiffFileSizeWithinLimit(filePath, size, maxFileSize) {
|
|
38
|
-
if (size <= maxFileSize)
|
|
39
|
-
return;
|
|
40
|
-
throw new McpError(ErrorCode.TOO_LARGE, `File too large for diff (${size} bytes > ${maxFileSize} bytes).`, filePath, { size, maxFileSize });
|
|
41
|
-
}
|
|
42
|
-
async function handleDiffFiles(args, signal, resourceStore) {
|
|
43
|
-
const maxFileSize = MAX_TEXT_FILE_SIZE;
|
|
44
|
-
const [originalPath, modifiedPath] = await Promise.all([
|
|
45
|
-
validateExistingPath(args.original, signal),
|
|
46
|
-
validateExistingPath(args.modified, signal),
|
|
47
|
-
]);
|
|
48
|
-
const [originalStats, modifiedStats] = await Promise.all([
|
|
49
|
-
withAbort(stat(originalPath), signal),
|
|
50
|
-
withAbort(stat(modifiedPath), signal),
|
|
51
|
-
]);
|
|
52
|
-
assertDiffFileSizeWithinLimit(originalPath, originalStats.size, maxFileSize);
|
|
53
|
-
assertDiffFileSizeWithinLimit(modifiedPath, modifiedStats.size, maxFileSize);
|
|
54
|
-
const [originalContent, modifiedContent] = await Promise.all([
|
|
55
|
-
readFile(originalPath, { encoding: 'utf-8', signal }),
|
|
56
|
-
readFile(modifiedPath, { encoding: 'utf-8', signal }),
|
|
57
|
-
]);
|
|
58
|
-
const patchObj = await new Promise((resolve) => {
|
|
59
|
-
structuredPatch(basename(originalPath), basename(modifiedPath), originalContent, modifiedContent, undefined, undefined, {
|
|
60
|
-
...(args.context !== undefined ? { context: args.context } : {}),
|
|
61
|
-
ignoreWhitespace: args.ignoreWhitespace,
|
|
62
|
-
stripTrailingCr: args.stripTrailingCr,
|
|
63
|
-
timeout: 10000,
|
|
64
|
-
callback: (res) => {
|
|
65
|
-
resolve(res);
|
|
66
|
-
},
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
if (!patchObj) {
|
|
70
|
-
throw new McpError(ErrorCode.TIMEOUT, `Diff timed out or too complex.`, originalPath);
|
|
71
|
-
}
|
|
72
|
-
const isIdentical = patchObj.hunks.length === 0;
|
|
73
|
-
const diffText = isIdentical ? '' : formatPatch(patchObj);
|
|
74
|
-
const stats = isIdentical ? undefined : computeDiffStats(patchObj.hunks);
|
|
75
|
-
const externalized = maybeExternalizeTextContent(resourceStore, diffText, {
|
|
76
|
-
name: 'diff:patch',
|
|
77
|
-
mimeType: 'text/x-diff',
|
|
78
|
-
});
|
|
79
|
-
if (!externalized) {
|
|
80
|
-
return buildToolResponse(isIdentical ? 'No differences' : diffText, {
|
|
81
|
-
ok: true,
|
|
82
|
-
diff: diffText,
|
|
83
|
-
isIdentical,
|
|
84
|
-
...(stats ?? {}),
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
const { preview, entry } = externalized;
|
|
88
|
-
return buildToolResponse(preview, {
|
|
89
|
-
ok: true,
|
|
90
|
-
diff: preview,
|
|
91
|
-
isIdentical,
|
|
92
|
-
...(stats ?? {}),
|
|
93
|
-
truncated: true,
|
|
94
|
-
resourceUri: entry.uri,
|
|
95
|
-
}, [
|
|
96
|
-
buildResourceLink({
|
|
97
|
-
uri: entry.uri,
|
|
98
|
-
name: entry.name,
|
|
99
|
-
mimeType: entry.mimeType,
|
|
100
|
-
description: 'Full diff content',
|
|
101
|
-
expiresAt: entry.expiresAt,
|
|
102
|
-
}),
|
|
103
|
-
]);
|
|
104
|
-
}
|
|
105
|
-
export function registerDiffFilesTool(server, options = {}) {
|
|
106
|
-
const handler = (args, ctx) => executeToolWithDiagnostics({
|
|
107
|
-
toolName: 'diff_files',
|
|
108
|
-
ctx,
|
|
109
|
-
outputSchema: DiffFilesOutputSchema,
|
|
110
|
-
timedSignal: {},
|
|
111
|
-
context: { path: args.original },
|
|
112
|
-
run: (signal) => handleDiffFiles(args, signal, options.resourceStore),
|
|
113
|
-
onError: (error) => buildToolErrorResponse(error, ErrorCode.UNKNOWN, args.original),
|
|
114
|
-
});
|
|
115
|
-
registerStandardTool(server, DIFF_FILES_TOOL, handler, options, {
|
|
116
|
-
progressMessage: (args) => {
|
|
117
|
-
const n1 = basename(args.original);
|
|
118
|
-
const n2 = basename(args.modified);
|
|
119
|
-
return `${DIFF_FILES_TOOL.title}: ${n1} ⟷ ${n2}`;
|
|
120
|
-
},
|
|
121
|
-
completionMessage: (args, result) => {
|
|
122
|
-
const n1 = basename(args.original);
|
|
123
|
-
const n2 = basename(args.modified);
|
|
124
|
-
if (result.isError)
|
|
125
|
-
return `${DIFF_FILES_TOOL.title}: ${n1} ⟷ ${n2} • ${result.errorCode}`;
|
|
126
|
-
const sc = result.structuredContent;
|
|
127
|
-
if (sc.isIdentical)
|
|
128
|
-
return `${DIFF_FILES_TOOL.title}: ${n1} ⟷ ${n2} • identical`;
|
|
129
|
-
const added = sc.linesAdded ?? 0;
|
|
130
|
-
const removed = sc.linesRemoved ?? 0;
|
|
131
|
-
if (added > 0 || removed > 0)
|
|
132
|
-
return `${DIFF_FILES_TOOL.title}: ${n1} ⟷ ${n2} • +${added} -${removed}`;
|
|
133
|
-
return `${DIFF_FILES_TOOL.title}: ${n1} ⟷ ${n2}`;
|
|
134
|
-
},
|
|
135
|
-
});
|
|
136
|
-
}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
|
-
import { type ToolContract, type ToolRegistrationOptions } from './shared.js';
|
|
3
|
-
export declare const EDIT_FILE_TOOL: ToolContract;
|
|
4
|
-
export declare function registerEditFileTool(server: McpServer, options?: ToolRegistrationOptions): void;
|