@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,182 +1,183 @@
1
- import { basename, relative } from 'node:path';
2
- import { DEFAULT_EXCLUDE_PATTERNS, DEFAULT_SEARCH_TIMEOUT_MS, } from '../lib/constants.js';
3
- import { classifyError, ErrorCode } from '../lib/errors.js';
4
- import { searchFiles } from '../lib/file-operations/search.js';
5
- import { formatOperationSummary, joinLines } from '../config.js';
6
- import { SearchFilesInputSchema, SearchFilesOutputSchema } from '../schemas.js';
7
- import { DIRECTORY_ICONS } from './icons.js';
8
- import { buildToolErrorResponse, buildToolResponse, createProgressReporter, decodeOffsetCursor, encodeOffsetCursor, executeToolWithDiagnostics, notifyProgress, READ_ONLY_TOOL_ANNOTATIONS, resolvePathOrRoot, truncateProgressPattern, } from './shared.js';
9
- import { registerStandardTool } from './task-support.js';
10
- export const SEARCH_FILES_TOOL = {
11
- name: 'find',
12
- title: 'Find Files',
13
- description: 'Find files by glob pattern (e.g. `**/*.ts`). Returns matching files with metadata. ' +
14
- 'For content search, use `grep`. For bulk edits, pass the same glob to `search_and_replace`.',
15
- inputSchema: SearchFilesInputSchema,
16
- outputSchema: SearchFilesOutputSchema,
17
- annotations: READ_ONLY_TOOL_ANNOTATIONS,
18
- icons: DIRECTORY_ICONS,
19
- nuances: ['Respects `.gitignore` unless `includeIgnored=true`.'],
20
- taskSupport: 'optional',
21
- };
22
- function buildTruncatedReason(summary) {
23
- if (!summary.truncated)
24
- return undefined;
25
- if (summary.stoppedReason === 'timeout')
26
- return 'timeout';
27
- if (summary.stoppedReason === 'maxFiles')
28
- return `max files (${summary.filesScanned})`;
29
- return `max results (${summary.matched})`;
30
- }
1
+ import * as z from 'zod/v4';
2
+ import { SearchStoppedReasonSchema } from '../core/concurrency.js';
3
+ import { createFirstPage, readNextPage } from '../core/cursor.js';
4
+ import { ErrorCode } from '../core/errors.js';
5
+ import { formatCount, truncateProgressPattern } from '../core/fmt.js';
6
+ import { DEFAULT_EXCLUDE_PATTERNS } from '../core/glob.js';
7
+ import { toPosixRelative } from '../core/path.js';
8
+ import { CursorSchema, includeHiddenField, includeIgnoredField, maxDepthField, NextCursorSchema, NonNegInt, OptionalPath, SafeGlobPattern, } from '../core/schema.js';
9
+ import { searchFiles } from '../core/search.js';
10
+ import { putJsonResource } from '../core/store.js';
11
+ import { DEFAULT_SEARCH_RESULTS, DEFAULT_SEARCH_TIMEOUT_MS, MAX_SEARCH_RESULTS, } from '../core/util.js';
12
+ import { defineTool } from './define.js';
13
+ // ---------------------------------------------------------------------------
14
+ const SearchFilesInputSchema = z.strictObject({
15
+ path: OptionalPath.describe('Base directory to search under (default: first allowed root)'),
16
+ pattern: SafeGlobPattern.describe('Glob pattern to match file paths (e.g. **/*.ts, src/**/*.js)'),
17
+ maxResults: z
18
+ .uint32()
19
+ .min(1)
20
+ .max(MAX_SEARCH_RESULTS)
21
+ .optional()
22
+ .default(DEFAULT_SEARCH_RESULTS)
23
+ .describe('Maximum number of matching files to return per page'),
24
+ includeIgnored: includeIgnoredField(),
25
+ includeHidden: includeHiddenField(),
26
+ sortBy: z
27
+ .enum(['name', 'path'])
28
+ .optional()
29
+ .default('path')
30
+ .describe('Sort order: path = full path (default), name = basename only'),
31
+ maxDepth: maxDepthField(),
32
+ cursor: CursorSchema,
33
+ });
34
+ const SearchFilesOutputSchema = z.strictObject({
35
+ root: z.string().describe('Resolved base directory used as the search root'),
36
+ results: z
37
+ .array(z.strictObject({
38
+ path: z.string().describe('File path relative to the search root'),
39
+ }))
40
+ .describe('Matched files ordered by sortBy'),
41
+ totalMatches: NonNegInt.optional().describe('Total number of matching files found'),
42
+ filesScanned: NonNegInt.optional().describe('Total number of files examined during the search'),
43
+ skippedInaccessible: NonNegInt.optional().describe('Files skipped due to permission or access errors'),
44
+ stoppedReason: SearchStoppedReasonSchema.describe('Why the search ended early: maxResults = result cap reached, timeout = time limit hit or the request was cancelled. Absent when the scan ran to completion.'),
45
+ resourceUri: z
46
+ .string()
47
+ .optional()
48
+ .describe('URI to the full results JSON in the resource store; first page only, when results are paginated'),
49
+ nextCursor: NextCursorSchema,
50
+ });
31
51
  function buildRelativeResults(basePath, displayResults) {
32
52
  const relativeResults = [];
33
53
  for (const entry of displayResults) {
34
54
  relativeResults.push({
35
- path: relative(basePath, entry.path),
36
- size: entry.size,
37
- modified: entry.modified?.toISOString(),
55
+ path: toPosixRelative(basePath, entry.path),
38
56
  });
39
57
  }
40
58
  return relativeResults;
41
59
  }
42
- function computeNextCursor(summary, displayResultsCount, cursorOffset) {
43
- if (summary.truncated && displayResultsCount > 0) {
44
- return encodeOffsetCursor(cursorOffset + displayResultsCount);
45
- }
46
- return undefined;
60
+ function searchFilesQueryKey(args, basePath) {
61
+ return JSON.stringify({
62
+ method: 'find_files',
63
+ path: basePath,
64
+ pattern: args.pattern,
65
+ includeIgnored: args.includeIgnored,
66
+ includeHidden: args.includeHidden,
67
+ sortBy: args.sortBy,
68
+ maxDepth: args.maxDepth,
69
+ });
47
70
  }
48
- function applySummaryFields(structured, summary, nextCursor) {
49
- if (summary.truncated)
50
- structured.truncated = true;
51
- if (summary.skippedInaccessible)
52
- structured.skippedInaccessible = summary.skippedInaccessible;
53
- if (summary.stoppedReason)
54
- structured.stoppedReason = summary.stoppedReason;
55
- if (nextCursor !== undefined)
56
- structured.nextCursor = nextCursor;
71
+ function searchFilesOutput(results, metadata, nextCursor) {
72
+ return {
73
+ root: metadata.root,
74
+ results: [...results],
75
+ totalMatches: metadata.totalMatches,
76
+ filesScanned: metadata.filesScanned,
77
+ ...(metadata.skippedInaccessible ? { skippedInaccessible: metadata.skippedInaccessible } : {}),
78
+ ...(metadata.stoppedReason !== undefined ? { stoppedReason: metadata.stoppedReason } : {}),
79
+ ...(metadata.resourceUri ? { resourceUri: metadata.resourceUri } : {}),
80
+ ...(nextCursor !== undefined ? { nextCursor } : {}),
81
+ };
57
82
  }
58
- async function handleSearchFiles(args, signal, onProgress) {
59
- const basePath = resolvePathOrRoot(args.path);
83
+ async function handleSearchFiles(args, ctx) {
84
+ const requestedBasePath = ctx.fs.pathGuard.resolvePathOrRoot(args.path);
85
+ const queryKey = searchFilesQueryKey(args, requestedBasePath);
86
+ if (args.cursor !== undefined) {
87
+ const paged = readNextPage({
88
+ store: ctx.pageStore,
89
+ queryKey,
90
+ cursor: args.cursor,
91
+ pageSize: args.maxResults,
92
+ });
93
+ // First page only — see the same note in list.ts: the overflow entry expires
94
+ // on ResourceStore's clock, not this snapshot's.
95
+ const { resourceUri: _firstPageOnly, ...pageMetadata } = paged.metadata;
96
+ return {
97
+ structured: searchFilesOutput(paged.page, pageMetadata, paged.nextCursor),
98
+ };
99
+ }
100
+ const basePath = await ctx.fs.pathGuard.validateExistingDirectory(requestedBasePath);
60
101
  const excludePatterns = args.includeIgnored ? [] : DEFAULT_EXCLUDE_PATTERNS;
61
- const cursorOffset = args.cursor !== undefined ? decodeOffsetCursor(args.cursor) : 0;
62
- const pageSize = args.maxResults;
63
- const fetchMax = cursorOffset + pageSize;
64
102
  const searchOptions = {
65
- maxResults: fetchMax,
103
+ maxResults: MAX_SEARCH_RESULTS,
66
104
  includeHidden: args.includeHidden,
67
105
  sortBy: args.sortBy,
68
106
  respectGitignore: !args.includeIgnored,
107
+ ...(args.maxDepth !== undefined ? { maxDepth: args.maxDepth } : {}),
108
+ signal: ctx.signal,
69
109
  };
70
- if (args.maxDepth !== undefined)
71
- searchOptions.maxDepth = args.maxDepth;
72
- if (onProgress)
73
- searchOptions.onProgress = onProgress;
74
- if (signal)
75
- searchOptions.signal = signal;
76
- const result = await searchFiles(basePath, args.pattern, excludePatterns, searchOptions);
77
- const allResults = result.results;
78
- let displayResults = allResults;
79
- if (cursorOffset > 0)
80
- displayResults = allResults.slice(cursorOffset);
81
- const nextCursor = computeNextCursor(result.summary, displayResults.length, cursorOffset);
82
- const relativeResults = buildRelativeResults(result.basePath, displayResults);
83
- const structured = {
84
- ok: true,
85
- root: basePath,
86
- results: relativeResults,
110
+ const result = await searchFiles(basePath, args.pattern, excludePatterns, searchOptions, ctx.fs.pathGuard);
111
+ const relativeResults = buildRelativeResults(result.basePath, result.results);
112
+ // Store the full result set so a caller can fetch all matching files by URI
113
+ // when the response is incomplete: `nextCursor` covers the multi-page case,
114
+ // and `summary.truncated` covers a single page that already hit the hard result
115
+ // cap (no nextCursor, but more matches exist beyond the cap).
116
+ let resourceUri;
117
+ let link;
118
+ if (ctx.resourceStore !== undefined &&
119
+ (relativeResults.length > args.maxResults || result.summary.truncated)) {
120
+ const stored = putJsonResource(ctx.resourceStore, `${args.pattern} files`, relativeResults);
121
+ resourceUri = stored.entry.uri;
122
+ link = stored.link;
123
+ }
124
+ const metadata = {
125
+ root: result.basePath,
87
126
  totalMatches: result.summary.matched,
88
127
  filesScanned: result.summary.filesScanned,
128
+ ...(result.summary.skippedInaccessible
129
+ ? { skippedInaccessible: result.summary.skippedInaccessible }
130
+ : {}),
131
+ ...(result.summary.stoppedReason !== undefined && result.summary.stoppedReason !== 'maxFiles'
132
+ ? { stoppedReason: result.summary.stoppedReason }
133
+ : {}),
134
+ ...(resourceUri ? { resourceUri } : {}),
89
135
  };
90
- applySummaryFields(structured, result.summary, nextCursor);
91
- const truncatedReason = buildTruncatedReason(result.summary);
92
- const summaryOptions = {
93
- truncated: result.summary.truncated,
94
- };
95
- if (truncatedReason)
96
- summaryOptions.truncatedReason = truncatedReason;
97
- const textLines = [];
98
- if (relativeResults.length === 0) {
99
- textLines.push('No matches');
100
- }
101
- else {
102
- textLines.push(`Found ${relativeResults.length}:`);
103
- for (const entry of relativeResults) {
104
- textLines.push(` ${entry.path}`);
105
- }
106
- }
107
- let text = joinLines(textLines) + formatOperationSummary(summaryOptions);
108
- if (nextCursor) {
109
- text += `\n[Next page available. Use cursor: "${nextCursor}"]`;
110
- }
111
- return buildToolResponse(text, structured);
112
- }
113
- export function registerSearchFilesTool(server, options = {}) {
114
- const handler = (args, ctx) => executeToolWithDiagnostics({
115
- toolName: 'find',
116
- ctx,
117
- outputSchema: SearchFilesOutputSchema,
118
- timedSignal: { timeoutMs: DEFAULT_SEARCH_TIMEOUT_MS },
119
- context: { path: args.path ?? '.' },
120
- run: async (signal) => {
121
- const rawScopeLabel = args.path ? basename(args.path) : '.';
122
- const scopeLabel = rawScopeLabel || '.';
123
- const { pattern } = args;
124
- const truncatedPattern = truncateProgressPattern(pattern);
125
- const context = `${truncatedPattern} in ${scopeLabel}`;
126
- let progressCursor = 0;
127
- notifyProgress(ctx, {
128
- current: 0,
129
- message: `${SEARCH_FILES_TOOL.title}: ${truncatedPattern}`,
130
- });
131
- const baseReporter = createProgressReporter(ctx);
132
- const progressWithMessage = ({ current, total, }) => {
133
- if (current > progressCursor)
134
- progressCursor = current;
135
- baseReporter({
136
- current,
137
- ...(total !== undefined ? { total } : {}),
138
- message: `${SEARCH_FILES_TOOL.title}: ${truncatedPattern} [${current} files]`,
139
- });
140
- };
141
- try {
142
- const result = await handleSearchFiles(args, signal, progressWithMessage);
143
- const sc = result.structuredContent;
144
- const { totalMatches = 0, stoppedReason } = sc;
145
- let suffix;
146
- if (totalMatches === 0) {
147
- suffix = 'No matches';
148
- }
149
- else {
150
- suffix = `${totalMatches} ${totalMatches === 1 ? 'match' : 'matches'}`;
151
- if (stoppedReason === 'timeout') {
152
- suffix += ' [timeout]';
153
- }
154
- else if (stoppedReason === 'maxResults') {
155
- suffix += ' [max results]';
156
- }
157
- else if (stoppedReason === 'maxFiles') {
158
- suffix += ' [max files]';
159
- }
160
- }
161
- const finalCurrent = Math.max((sc.filesScanned ?? 0) + 1, progressCursor + 1);
162
- notifyProgress(ctx, {
163
- current: finalCurrent,
164
- total: finalCurrent,
165
- message: `${SEARCH_FILES_TOOL.title}: ${context} • ${suffix}`,
166
- });
167
- return result;
168
- }
169
- catch (error) {
170
- const finalCurrent = Math.max(progressCursor + 1, 1);
171
- notifyProgress(ctx, {
172
- current: finalCurrent,
173
- total: finalCurrent,
174
- message: `${SEARCH_FILES_TOOL.title}: ${context} • ${classifyError(error)}`,
175
- });
176
- throw error;
177
- }
178
- },
179
- onError: (error) => buildToolErrorResponse(error, ErrorCode.UNKNOWN, args.path),
136
+ const paged = createFirstPage({
137
+ store: ctx.pageStore,
138
+ queryKey,
139
+ items: relativeResults,
140
+ metadata,
141
+ pageSize: args.maxResults,
180
142
  });
181
- registerStandardTool(server, SEARCH_FILES_TOOL, handler, options);
143
+ return {
144
+ structured: searchFilesOutput(paged.page, metadata, paged.nextCursor),
145
+ ...(link !== undefined ? { link } : {}),
146
+ };
182
147
  }
148
+ export const SEARCH_FILES = defineTool({
149
+ name: 'find_files',
150
+ title: 'Find Files',
151
+ description: 'Find files matching a glob pattern. Returns matched paths with optional metadata. ' +
152
+ 'Pagination cursors reference a query-bound snapshot that expires after 60 seconds. ' +
153
+ 'For content search use search_text; for bulk regex replacements use replace_text with the same glob.',
154
+ input: SearchFilesInputSchema,
155
+ output: SearchFilesOutputSchema,
156
+ annotations: {
157
+ readOnlyHint: true,
158
+ idempotentHint: true,
159
+ destructiveHint: false,
160
+ openWorldHint: false,
161
+ },
162
+ timeoutMs: DEFAULT_SEARCH_TIMEOUT_MS,
163
+ defaultErrorCode: ErrorCode.UNKNOWN,
164
+ progress: (args) => ({
165
+ label: 'Find',
166
+ subject: truncateProgressPattern(args.pattern),
167
+ }),
168
+ progressDone: (_args, result) => ({
169
+ detail: formatCount(result.totalMatches ?? 0, 'match', 'matches'),
170
+ }),
171
+ accessPaths: (args) => (args.path ? [args.path] : []),
172
+ run: async (args, ctx) => {
173
+ const { structured, link } = await handleSearchFiles(args, ctx);
174
+ const text = structured.results.length > 0
175
+ ? structured.results.map((r) => r.path).join('\n')
176
+ : `No files matching '${args.pattern}'`;
177
+ if (link) {
178
+ return { structured, text, resources: [link] };
179
+ }
180
+ return { structured, text };
181
+ },
182
+ });
183
+ //# sourceMappingURL=search-files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-files.js","sourceRoot":"","sources":["../../src/tools/search-files.ts"],"names":[],"mappings":"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","sourcesContent":["import * as z from 'zod/v4';\n\nimport { SearchStoppedReasonSchema } from '../core/concurrency.js';\nimport { createFirstPage, readNextPage } from '../core/cursor.js';\nimport { ErrorCode } from '../core/errors.js';\nimport { formatCount, truncateProgressPattern } from '../core/fmt.js';\nimport { DEFAULT_EXCLUDE_PATTERNS } from '../core/glob.js';\nimport { toPosixRelative } from '../core/path.js';\nimport {\n CursorSchema,\n includeHiddenField,\n includeIgnoredField,\n maxDepthField,\n NextCursorSchema,\n NonNegInt,\n OptionalPath,\n SafeGlobPattern,\n} from '../core/schema.js';\nimport { searchFiles } from '../core/search.js';\nimport { putJsonResource } from '../core/store.js';\nimport {\n DEFAULT_SEARCH_RESULTS,\n DEFAULT_SEARCH_TIMEOUT_MS,\n MAX_SEARCH_RESULTS,\n} from '../core/util.js';\nimport { defineTool, type ToolCtx } from './define.js';\n\n// ---------------------------------------------------------------------------\n\nconst SearchFilesInputSchema = z.strictObject({\n path: OptionalPath.describe('Base directory to search under (default: first allowed root)'),\n pattern: SafeGlobPattern.describe('Glob pattern to match file paths (e.g. **/*.ts, src/**/*.js)'),\n maxResults: z\n .uint32()\n .min(1)\n .max(MAX_SEARCH_RESULTS)\n .optional()\n .default(DEFAULT_SEARCH_RESULTS)\n .describe('Maximum number of matching files to return per page'),\n includeIgnored: includeIgnoredField(),\n includeHidden: includeHiddenField(),\n sortBy: z\n .enum(['name', 'path'])\n .optional()\n .default('path')\n .describe('Sort order: path = full path (default), name = basename only'),\n maxDepth: maxDepthField(),\n cursor: CursorSchema,\n});\n\nconst SearchFilesOutputSchema = z.strictObject({\n root: z.string().describe('Resolved base directory used as the search root'),\n results: z\n .array(\n z.strictObject({\n path: z.string().describe('File path relative to the search root'),\n }),\n )\n .describe('Matched files ordered by sortBy'),\n totalMatches: NonNegInt.optional().describe('Total number of matching files found'),\n filesScanned: NonNegInt.optional().describe('Total number of files examined during the search'),\n skippedInaccessible: NonNegInt.optional().describe(\n 'Files skipped due to permission or access errors',\n ),\n stoppedReason: SearchStoppedReasonSchema.describe(\n 'Why the search ended early: maxResults = result cap reached, timeout = time limit hit or the request was cancelled. Absent when the scan ran to completion.',\n ),\n resourceUri: z\n .string()\n .optional()\n .describe(\n 'URI to the full results JSON in the resource store; first page only, when results are paginated',\n ),\n nextCursor: NextCursorSchema,\n});\n\nfunction buildRelativeResults(\n basePath: string,\n displayResults: readonly { path: string }[],\n): NonNullable<z.infer<typeof SearchFilesOutputSchema>['results']> {\n const relativeResults: NonNullable<z.infer<typeof SearchFilesOutputSchema>['results']> = [];\n for (const entry of displayResults) {\n relativeResults.push({\n path: toPosixRelative(basePath, entry.path),\n });\n }\n return relativeResults;\n}\n\ntype SearchFileResult = NonNullable<z.infer<typeof SearchFilesOutputSchema>['results']>[number];\n\ninterface SearchFilesPageMetadata {\n readonly root: string;\n readonly totalMatches: number;\n readonly filesScanned: number;\n readonly skippedInaccessible?: number;\n readonly stoppedReason?: z.infer<typeof SearchFilesOutputSchema>['stoppedReason'];\n readonly resourceUri?: string;\n}\n\nfunction searchFilesQueryKey(\n args: z.infer<typeof SearchFilesInputSchema>,\n basePath: string,\n): string {\n return JSON.stringify({\n method: 'find_files',\n path: basePath,\n pattern: args.pattern,\n includeIgnored: args.includeIgnored,\n includeHidden: args.includeHidden,\n sortBy: args.sortBy,\n maxDepth: args.maxDepth,\n });\n}\n\nfunction searchFilesOutput(\n results: readonly SearchFileResult[],\n metadata: SearchFilesPageMetadata,\n nextCursor: string | undefined,\n): z.infer<typeof SearchFilesOutputSchema> {\n return {\n root: metadata.root,\n results: [...results],\n totalMatches: metadata.totalMatches,\n filesScanned: metadata.filesScanned,\n ...(metadata.skippedInaccessible ? { skippedInaccessible: metadata.skippedInaccessible } : {}),\n ...(metadata.stoppedReason !== undefined ? { stoppedReason: metadata.stoppedReason } : {}),\n ...(metadata.resourceUri ? { resourceUri: metadata.resourceUri } : {}),\n ...(nextCursor !== undefined ? { nextCursor } : {}),\n };\n}\n\nasync function handleSearchFiles(\n args: z.infer<typeof SearchFilesInputSchema>,\n ctx: ToolCtx,\n): Promise<{\n structured: z.infer<typeof SearchFilesOutputSchema>;\n link?: ReturnType<typeof putJsonResource>['link'];\n}> {\n const requestedBasePath = ctx.fs.pathGuard.resolvePathOrRoot(args.path);\n const queryKey = searchFilesQueryKey(args, requestedBasePath);\n if (args.cursor !== undefined) {\n const paged = readNextPage<SearchFileResult, SearchFilesPageMetadata>({\n store: ctx.pageStore,\n queryKey,\n cursor: args.cursor,\n pageSize: args.maxResults,\n });\n // First page only — see the same note in list.ts: the overflow entry expires\n // on ResourceStore's clock, not this snapshot's.\n const { resourceUri: _firstPageOnly, ...pageMetadata } = paged.metadata;\n return {\n structured: searchFilesOutput(paged.page, pageMetadata, paged.nextCursor),\n };\n }\n\n const basePath = await ctx.fs.pathGuard.validateExistingDirectory(requestedBasePath);\n const excludePatterns = args.includeIgnored ? [] : DEFAULT_EXCLUDE_PATTERNS;\n const searchOptions: Parameters<typeof searchFiles>[3] = {\n maxResults: MAX_SEARCH_RESULTS,\n includeHidden: args.includeHidden,\n sortBy: args.sortBy,\n respectGitignore: !args.includeIgnored,\n ...(args.maxDepth !== undefined ? { maxDepth: args.maxDepth } : {}),\n signal: ctx.signal,\n };\n const result = await searchFiles(\n basePath,\n args.pattern,\n excludePatterns,\n searchOptions,\n ctx.fs.pathGuard,\n );\n const relativeResults = buildRelativeResults(result.basePath, result.results);\n\n // Store the full result set so a caller can fetch all matching files by URI\n // when the response is incomplete: `nextCursor` covers the multi-page case,\n // and `summary.truncated` covers a single page that already hit the hard result\n // cap (no nextCursor, but more matches exist beyond the cap).\n let resourceUri: string | undefined;\n let link: ReturnType<typeof putJsonResource>['link'] | undefined;\n if (\n ctx.resourceStore !== undefined &&\n (relativeResults.length > args.maxResults || result.summary.truncated)\n ) {\n const stored = putJsonResource(ctx.resourceStore, `${args.pattern} files`, relativeResults);\n resourceUri = stored.entry.uri;\n link = stored.link;\n }\n\n const metadata: SearchFilesPageMetadata = {\n root: result.basePath,\n totalMatches: result.summary.matched,\n filesScanned: result.summary.filesScanned,\n ...(result.summary.skippedInaccessible\n ? { skippedInaccessible: result.summary.skippedInaccessible }\n : {}),\n ...(result.summary.stoppedReason !== undefined && result.summary.stoppedReason !== 'maxFiles'\n ? { stoppedReason: result.summary.stoppedReason }\n : {}),\n ...(resourceUri ? { resourceUri } : {}),\n };\n const paged = createFirstPage<SearchFileResult, SearchFilesPageMetadata>({\n store: ctx.pageStore,\n queryKey,\n items: relativeResults,\n metadata,\n pageSize: args.maxResults,\n });\n return {\n structured: searchFilesOutput(paged.page, metadata, paged.nextCursor),\n ...(link !== undefined ? { link } : {}),\n };\n}\n\nexport const SEARCH_FILES = defineTool({\n name: 'find_files',\n title: 'Find Files',\n description:\n 'Find files matching a glob pattern. Returns matched paths with optional metadata. ' +\n 'Pagination cursors reference a query-bound snapshot that expires after 60 seconds. ' +\n 'For content search use search_text; for bulk regex replacements use replace_text with the same glob.',\n input: SearchFilesInputSchema,\n output: SearchFilesOutputSchema,\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: false,\n },\n timeoutMs: DEFAULT_SEARCH_TIMEOUT_MS,\n defaultErrorCode: ErrorCode.UNKNOWN,\n progress: (args) => ({\n label: 'Find',\n subject: truncateProgressPattern(args.pattern),\n }),\n progressDone: (_args, result) => ({\n detail: formatCount(result.totalMatches ?? 0, 'match', 'matches'),\n }),\n accessPaths: (args) => (args.path ? [args.path] : []),\n run: async (args, ctx) => {\n const { structured, link } = await handleSearchFiles(args, ctx);\n const text =\n structured.results.length > 0\n ? structured.results.map((r) => r.path).join('\\n')\n : `No files matching '${args.pattern}'`;\n if (link) {\n return { structured, text, resources: [link] };\n }\n return { structured, text };\n },\n});\n"]}
@@ -1,4 +1,2 @@
1
- import type { McpServer } from '@modelcontextprotocol/server';
2
- import { type ToolContract, type ToolRegistrationOptions } from './shared.js';
3
- export declare const GET_FILE_INFO_TOOL: ToolContract;
4
- export declare function registerGetFileInfoTool(server: McpServer, options?: ToolRegistrationOptions): void;
1
+ export declare const GET_FILE_INFO: import("./define.js").DefinedTool;
2
+ //# sourceMappingURL=stat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stat.d.ts","sourceRoot":"","sources":["../../src/tools/stat.ts"],"names":[],"mappings":"AAgMA,eAAO,MAAM,aAAa,mCAkFxB,CAAC"}