@j0hanz/filesystem-mcp 1.19.1 → 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.
Files changed (301) hide show
  1. package/README.md +333 -838
  2. package/dist/cli-help.d.ts +3 -0
  3. package/dist/cli-help.d.ts.map +1 -0
  4. package/dist/cli-help.js +169 -0
  5. package/dist/cli-help.js.map +1 -0
  6. package/dist/cli.d.ts +28 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +168 -123
  9. package/dist/cli.js.map +1 -0
  10. package/dist/core/concurrency.d.ts +70 -0
  11. package/dist/core/concurrency.d.ts.map +1 -0
  12. package/dist/core/concurrency.js +173 -0
  13. package/dist/core/concurrency.js.map +1 -0
  14. package/dist/core/config.d.ts +19 -0
  15. package/dist/core/config.d.ts.map +1 -0
  16. package/dist/core/config.js +11 -0
  17. package/dist/core/config.js.map +1 -0
  18. package/dist/core/cursor.d.ts +23 -0
  19. package/dist/core/cursor.d.ts.map +1 -0
  20. package/dist/core/cursor.js +62 -0
  21. package/dist/core/cursor.js.map +1 -0
  22. package/dist/core/errors.d.ts +96 -0
  23. package/dist/core/errors.d.ts.map +1 -0
  24. package/dist/core/errors.js +356 -0
  25. package/dist/core/errors.js.map +1 -0
  26. package/dist/core/file-uri.d.ts +24 -0
  27. package/dist/core/file-uri.d.ts.map +1 -0
  28. package/dist/core/file-uri.js +52 -0
  29. package/dist/core/file-uri.js.map +1 -0
  30. package/dist/core/fmt.d.ts +38 -0
  31. package/dist/core/fmt.d.ts.map +1 -0
  32. package/dist/core/fmt.js +109 -0
  33. package/dist/core/fmt.js.map +1 -0
  34. package/dist/core/fs.d.ts +108 -0
  35. package/dist/core/fs.d.ts.map +1 -0
  36. package/dist/core/fs.js +243 -0
  37. package/dist/core/fs.js.map +1 -0
  38. package/dist/core/glob.d.ts +41 -0
  39. package/dist/core/glob.d.ts.map +1 -0
  40. package/dist/core/glob.js +399 -0
  41. package/dist/core/glob.js.map +1 -0
  42. package/dist/core/input-required.d.ts +147 -0
  43. package/dist/core/input-required.d.ts.map +1 -0
  44. package/dist/core/input-required.js +261 -0
  45. package/dist/core/input-required.js.map +1 -0
  46. package/dist/core/mime.d.ts +15 -0
  47. package/dist/core/mime.d.ts.map +1 -0
  48. package/dist/core/mime.js +188 -0
  49. package/dist/core/mime.js.map +1 -0
  50. package/dist/core/observability.d.ts +10 -0
  51. package/dist/core/observability.d.ts.map +1 -0
  52. package/dist/core/observability.js +76 -0
  53. package/dist/core/observability.js.map +1 -0
  54. package/dist/core/page-store.d.ts +41 -0
  55. package/dist/core/page-store.d.ts.map +1 -0
  56. package/dist/core/page-store.js +74 -0
  57. package/dist/core/page-store.js.map +1 -0
  58. package/dist/core/path-completer.d.ts +10 -0
  59. package/dist/core/path-completer.d.ts.map +1 -0
  60. package/dist/core/path-completer.js +227 -0
  61. package/dist/core/path-completer.js.map +1 -0
  62. package/dist/core/path-discovery.d.ts +8 -0
  63. package/dist/core/path-discovery.d.ts.map +1 -0
  64. package/dist/core/path-discovery.js +105 -0
  65. package/dist/core/path-discovery.js.map +1 -0
  66. package/dist/core/path-utils.d.ts +9 -0
  67. package/dist/core/path-utils.d.ts.map +1 -0
  68. package/dist/core/path-utils.js +121 -0
  69. package/dist/core/path-utils.js.map +1 -0
  70. package/dist/core/path.d.ts +148 -0
  71. package/dist/core/path.d.ts.map +1 -0
  72. package/dist/core/path.js +674 -0
  73. package/dist/core/path.js.map +1 -0
  74. package/dist/core/primitives.d.ts +23 -0
  75. package/dist/core/primitives.d.ts.map +1 -0
  76. package/dist/core/primitives.js +54 -0
  77. package/dist/core/primitives.js.map +1 -0
  78. package/dist/core/read.d.ts +74 -0
  79. package/dist/core/read.d.ts.map +1 -0
  80. package/dist/core/read.js +562 -0
  81. package/dist/core/read.js.map +1 -0
  82. package/dist/core/schema.d.ts +139 -0
  83. package/dist/core/schema.d.ts.map +1 -0
  84. package/dist/core/schema.js +345 -0
  85. package/dist/core/schema.js.map +1 -0
  86. package/dist/core/search.d.ts +100 -0
  87. package/dist/core/search.d.ts.map +1 -0
  88. package/dist/core/search.js +248 -0
  89. package/dist/core/search.js.map +1 -0
  90. package/dist/core/sensitive.d.ts +6 -0
  91. package/dist/core/sensitive.d.ts.map +1 -0
  92. package/dist/core/sensitive.js +142 -0
  93. package/dist/core/sensitive.js.map +1 -0
  94. package/dist/core/store.d.ts +57 -0
  95. package/dist/core/store.d.ts.map +1 -0
  96. package/dist/core/store.js +162 -0
  97. package/dist/core/store.js.map +1 -0
  98. package/dist/core/util.d.ts +26 -0
  99. package/dist/core/util.d.ts.map +1 -0
  100. package/dist/core/util.js +66 -0
  101. package/dist/core/util.js.map +1 -0
  102. package/dist/core/watcher-registry.d.ts +68 -0
  103. package/dist/core/watcher-registry.d.ts.map +1 -0
  104. package/dist/core/watcher-registry.js +312 -0
  105. package/dist/core/watcher-registry.js.map +1 -0
  106. package/dist/http-policy.d.ts +121 -0
  107. package/dist/http-policy.d.ts.map +1 -0
  108. package/dist/http-policy.js +340 -0
  109. package/dist/http-policy.js.map +1 -0
  110. package/dist/index.d.ts +1 -0
  111. package/dist/index.d.ts.map +1 -0
  112. package/dist/index.js +77 -41
  113. package/dist/index.js.map +1 -0
  114. package/dist/instructions.d.ts +12 -0
  115. package/dist/instructions.d.ts.map +1 -0
  116. package/dist/instructions.js +71 -0
  117. package/dist/instructions.js.map +1 -0
  118. package/dist/prompts.d.ts +8 -6
  119. package/dist/prompts.d.ts.map +1 -0
  120. package/dist/prompts.js +74 -168
  121. package/dist/prompts.js.map +1 -0
  122. package/dist/resources.d.ts +73 -9
  123. package/dist/resources.d.ts.map +1 -0
  124. package/dist/resources.js +392 -163
  125. package/dist/resources.js.map +1 -0
  126. package/dist/server.d.ts +62 -1
  127. package/dist/server.d.ts.map +1 -0
  128. package/dist/server.js +139 -1
  129. package/dist/server.js.map +1 -0
  130. package/dist/tools/batch.d.ts +89 -0
  131. package/dist/tools/batch.d.ts.map +1 -0
  132. package/dist/tools/batch.js +157 -0
  133. package/dist/tools/batch.js.map +1 -0
  134. package/dist/tools/create.d.ts +2 -0
  135. package/dist/tools/create.d.ts.map +1 -0
  136. package/dist/tools/create.js +142 -0
  137. package/dist/tools/create.js.map +1 -0
  138. package/dist/tools/define.d.ts +110 -0
  139. package/dist/tools/define.d.ts.map +1 -0
  140. package/dist/tools/define.js +394 -0
  141. package/dist/tools/define.js.map +1 -0
  142. package/dist/tools/delete-file.d.ts +2 -4
  143. package/dist/tools/delete-file.d.ts.map +1 -0
  144. package/dist/tools/delete-file.js +330 -87
  145. package/dist/tools/delete-file.js.map +1 -0
  146. package/dist/tools/diff.d.ts +2 -0
  147. package/dist/tools/diff.d.ts.map +1 -0
  148. package/dist/tools/diff.js +94 -0
  149. package/dist/tools/diff.js.map +1 -0
  150. package/dist/tools/edit.d.ts +2 -0
  151. package/dist/tools/edit.d.ts.map +1 -0
  152. package/dist/tools/edit.js +442 -0
  153. package/dist/tools/edit.js.map +1 -0
  154. package/dist/tools/index.d.ts +26 -0
  155. package/dist/tools/index.d.ts.map +1 -0
  156. package/dist/tools/index.js +52 -0
  157. package/dist/tools/index.js.map +1 -0
  158. package/dist/tools/list.d.ts +2 -0
  159. package/dist/tools/list.d.ts.map +1 -0
  160. package/dist/tools/list.js +291 -0
  161. package/dist/tools/list.js.map +1 -0
  162. package/dist/tools/move.d.ts +2 -0
  163. package/dist/tools/move.d.ts.map +1 -0
  164. package/dist/tools/move.js +321 -0
  165. package/dist/tools/move.js.map +1 -0
  166. package/dist/tools/patch.d.ts +2 -0
  167. package/dist/tools/patch.d.ts.map +1 -0
  168. package/dist/tools/patch.js +155 -0
  169. package/dist/tools/patch.js.map +1 -0
  170. package/dist/tools/progress.d.ts +52 -0
  171. package/dist/tools/progress.d.ts.map +1 -0
  172. package/dist/tools/progress.js +172 -0
  173. package/dist/tools/progress.js.map +1 -0
  174. package/dist/tools/read.d.ts +2 -4
  175. package/dist/tools/read.d.ts.map +1 -0
  176. package/dist/tools/read.js +398 -152
  177. package/dist/tools/read.js.map +1 -0
  178. package/dist/tools/replace-in-files.d.ts +2 -4
  179. package/dist/tools/replace-in-files.d.ts.map +1 -0
  180. package/dist/tools/replace-in-files.js +435 -264
  181. package/dist/tools/replace-in-files.js.map +1 -0
  182. package/dist/tools/roots.d.ts +2 -4
  183. package/dist/tools/roots.d.ts.map +1 -0
  184. package/dist/tools/roots.js +29 -52
  185. package/dist/tools/roots.js.map +1 -0
  186. package/dist/tools/search-content.d.ts +2 -4
  187. package/dist/tools/search-content.d.ts.map +1 -0
  188. package/dist/tools/search-content.js +262 -228
  189. package/dist/tools/search-content.js.map +1 -0
  190. package/dist/tools/search-files.d.ts +2 -4
  191. package/dist/tools/search-files.d.ts.map +1 -0
  192. package/dist/tools/search-files.js +162 -161
  193. package/dist/tools/search-files.js.map +1 -0
  194. package/dist/tools/stat.d.ts +2 -4
  195. package/dist/tools/stat.d.ts.map +1 -0
  196. package/dist/tools/stat.js +202 -62
  197. package/dist/tools/stat.js.map +1 -0
  198. package/dist/transport/http.d.ts +5 -0
  199. package/dist/transport/http.d.ts.map +1 -0
  200. package/dist/transport/http.js +276 -0
  201. package/dist/transport/http.js.map +1 -0
  202. package/dist/transport/shared.d.ts +45 -0
  203. package/dist/transport/shared.d.ts.map +1 -0
  204. package/dist/transport/shared.js +65 -0
  205. package/dist/transport/shared.js.map +1 -0
  206. package/dist/transport/stdio.d.ts +32 -0
  207. package/dist/transport/stdio.d.ts.map +1 -0
  208. package/dist/transport/stdio.js +279 -0
  209. package/dist/transport/stdio.js.map +1 -0
  210. package/dist/transport.d.ts +5 -0
  211. package/dist/transport.d.ts.map +1 -0
  212. package/dist/transport.js +4 -0
  213. package/dist/transport.js.map +1 -0
  214. package/package.json +37 -46
  215. package/dist/assets/logo.svg +0 -35
  216. package/dist/completions.d.ts +0 -2
  217. package/dist/completions.js +0 -572
  218. package/dist/config.d.ts +0 -119
  219. package/dist/config.js +0 -31
  220. package/dist/lib/abort.d.ts +0 -7
  221. package/dist/lib/abort.js +0 -81
  222. package/dist/lib/constants.d.ts +0 -42
  223. package/dist/lib/constants.js +0 -313
  224. package/dist/lib/errors.d.ts +0 -28
  225. package/dist/lib/errors.js +0 -301
  226. package/dist/lib/file-operations/core.d.ts +0 -53
  227. package/dist/lib/file-operations/core.js +0 -144
  228. package/dist/lib/file-operations/metadata.d.ts +0 -77
  229. package/dist/lib/file-operations/metadata.js +0 -878
  230. package/dist/lib/file-operations/search.d.ts +0 -46
  231. package/dist/lib/file-operations/search.js +0 -1194
  232. package/dist/lib/file-operations/traversal.d.ts +0 -40
  233. package/dist/lib/file-operations/traversal.js +0 -310
  234. package/dist/lib/fs-helpers.d.ts +0 -46
  235. package/dist/lib/fs-helpers.js +0 -606
  236. package/dist/lib/globs.d.ts +0 -2
  237. package/dist/lib/globs.js +0 -19
  238. package/dist/lib/logger.d.ts +0 -27
  239. package/dist/lib/logger.js +0 -91
  240. package/dist/lib/observability.d.ts +0 -33
  241. package/dist/lib/observability.js +0 -373
  242. package/dist/lib/paths.d.ts +0 -35
  243. package/dist/lib/paths.js +0 -634
  244. package/dist/lib/resource-store.d.ts +0 -28
  245. package/dist/lib/resource-store.js +0 -195
  246. package/dist/lib/utils.d.ts +0 -7
  247. package/dist/lib/utils.js +0 -37
  248. package/dist/lib/zod-codecs.d.ts +0 -2
  249. package/dist/lib/zod-codecs.js +0 -18
  250. package/dist/pkg-info.d.ts +0 -7
  251. package/dist/pkg-info.js +0 -9
  252. package/dist/resources/generated-instructions.d.ts +0 -1
  253. package/dist/resources/generated-instructions.js +0 -105
  254. package/dist/resources/tool-catalog.d.ts +0 -2
  255. package/dist/resources/tool-catalog.js +0 -78
  256. package/dist/resources/tool-info.d.ts +0 -9
  257. package/dist/resources/tool-info.js +0 -206
  258. package/dist/resources/workflows.d.ts +0 -1
  259. package/dist/resources/workflows.js +0 -72
  260. package/dist/schemas.d.ts +0 -505
  261. package/dist/schemas.js +0 -676
  262. package/dist/server/bootstrap.d.ts +0 -6
  263. package/dist/server/bootstrap.js +0 -585
  264. package/dist/server/event-store.d.ts +0 -18
  265. package/dist/server/event-store.js +0 -71
  266. package/dist/server/roots-manager.d.ts +0 -28
  267. package/dist/server/roots-manager.js +0 -227
  268. package/dist/server/task-store.d.ts +0 -10
  269. package/dist/server/task-store.js +0 -91
  270. package/dist/tools/apply-patch.d.ts +0 -4
  271. package/dist/tools/apply-patch.js +0 -235
  272. package/dist/tools/calculate-hash.d.ts +0 -4
  273. package/dist/tools/calculate-hash.js +0 -187
  274. package/dist/tools/contract.d.ts +0 -50
  275. package/dist/tools/contract.js +0 -1
  276. package/dist/tools/create-directory.d.ts +0 -4
  277. package/dist/tools/create-directory.js +0 -68
  278. package/dist/tools/diff-files.d.ts +0 -4
  279. package/dist/tools/diff-files.js +0 -136
  280. package/dist/tools/edit-file.d.ts +0 -4
  281. package/dist/tools/edit-file.js +0 -256
  282. package/dist/tools/icons.d.ts +0 -15
  283. package/dist/tools/icons.js +0 -24
  284. package/dist/tools/list-directory.d.ts +0 -4
  285. package/dist/tools/list-directory.js +0 -218
  286. package/dist/tools/move-file.d.ts +0 -4
  287. package/dist/tools/move-file.js +0 -178
  288. package/dist/tools/read-multiple.d.ts +0 -4
  289. package/dist/tools/read-multiple.js +0 -207
  290. package/dist/tools/shared.d.ts +0 -172
  291. package/dist/tools/shared.js +0 -599
  292. package/dist/tools/stat-many.d.ts +0 -4
  293. package/dist/tools/stat-many.js +0 -104
  294. package/dist/tools/task-support.d.ts +0 -29
  295. package/dist/tools/task-support.js +0 -473
  296. package/dist/tools/tree.d.ts +0 -4
  297. package/dist/tools/tree.js +0 -102
  298. package/dist/tools/write-file.d.ts +0 -4
  299. package/dist/tools/write-file.js +0 -60
  300. package/dist/tools.d.ts +0 -5
  301. 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
- }
@@ -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
- }
@@ -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;
@@ -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;