@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.
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 -563
  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 -472
  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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.js","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n CacheHint,\n McpServer,\n ReadResourceResult,\n Resource,\n ResourceUpdatedNotificationParams,\n Role,\n ServerContext,\n ServerNotifier,\n SubscribeRequestParams,\n UnsubscribeRequestParams,\n} from '@modelcontextprotocol/server';\nimport {\n checkResourceAllowed,\n ProtocolError,\n ProtocolErrorCode,\n ResourceNotFoundError,\n ResourceTemplate,\n resourceUrlFromServerUrl,\n UriTemplate,\n} from '@modelcontextprotocol/server';\n\nimport type { FsError } from './core/errors.js';\nimport {\n ErrorCode,\n formatUnknownErrorMessage,\n fsErrorCode,\n hasErrorShape,\n isFsError,\n} from './core/errors.js';\nimport {\n decodeFileUriPath,\n encodeFileUriPath,\n extractPath,\n FILESYSTEM_FILE_URI_TEMPLATE,\n} from './core/file-uri.js';\nimport { GuardedFileSystem } from './core/fs.js';\nimport { Logger } from './core/observability.js';\nimport { PathCompleter } from './core/path-completer.js';\nimport type { PathGuard } from './core/path.js';\nimport type { ResourceStore } from './core/store.js';\nimport {\n createWatcherRegistry,\n MAX_WATCHERS,\n type WatcherRegistry,\n} from './core/watcher-registry.js';\nimport {\n buildSectionsRecord,\n INSTRUCTIONS_SUMMARY,\n INSTRUCTIONS_URI,\n renderSections,\n} from './instructions.js';\n\n// ═══════════════════════════════════════════════════════════════\n// shared\n// ═══════════════════════════════════════════════════════════════\n\nexport interface ResourceRegistrationOptions {\n resourceStore: ResourceStore;\n pathGuard?: PathGuard;\n /** Mirrors the `--read-only` gate so the instructions match the tools actually registered. */\n readOnly: boolean;\n /**\n * Shared file-watcher registry for the modern (per-request) HTTP leg. When set,\n * the resource uses this handler-scoped registry instead of creating its own\n * per-server one, so file-change watchers persist across requests and publish\n * to the shared ServerEventBus. Omitted (per-server registry) on legacy/stdio.\n */\n watcherRegistry?: WatcherRegistry;\n /** Modern-leg typed notification publisher. */\n notifier?: ServerNotifier;\n /** The protocol era this instance serves; omitted where the caller does not know. */\n era?: 'legacy' | 'modern';\n /**\n * Scope for shared-content cache hints. 'private' when the endpoint is\n * API-key gated, mirroring the list hints in server.ts — a shared cache must\n * not store an authenticated response body. Defaults to 'public'.\n */\n cacheScope?: 'public' | 'private';\n}\n\ntype ResourceRegistrarDeps = Omit<ResourceRegistrationOptions, 'pathGuard' | 'readOnly'> & {\n readonly server: McpServer;\n readonly pathGuard: PathGuard;\n readonly readOnly?: boolean;\n};\n\n/**\n * A filesystem failure that reads as not-found on the resource wire, for both\n * `resources/read` and `resources/subscribe`. ACCESS_DENIED folds in\n * deliberately: masking whether an out-of-root or denylisted path exists is the\n * security-correct answer, and the `FsError` message still carries the real\n * cause to the client.\n */\nfunction isNotFoundish(error: unknown): error is FsError {\n return (\n isFsError(error) &&\n (error.code === ErrorCode.NOT_FOUND || error.code === ErrorCode.ACCESS_DENIED)\n );\n}\n\n// ═══════════════════════════════════════════════════════════════\n// contract\n// ═══════════════════════════════════════════════════════════════\n\ninterface BaseResourceContract {\n name: string;\n title?: string;\n description?: string;\n mimeType?: string;\n cacheHint?: CacheHint;\n annotations?: {\n audience?: Role[];\n priority?: number;\n };\n readonly read: (\n uri: URL,\n variables: Record<string, string | string[]>,\n ctx: ServerContext,\n ) => Promise<ReadResourceResult> | ReadResourceResult;\n readonly subscribe?: (\n uri: string,\n notify: (uri: string) => void,\n ) => Promise<boolean | undefined> | boolean | undefined;\n readonly unsubscribe?: (uri: string) => void;\n readonly destroy?: () => void;\n readonly list?: (\n ctx: ServerContext,\n ) => Promise<{ resources: Resource[] }> | { resources: Resource[] };\n}\n\n/** A resource with a fixed, enumerable URI (e.g. internal://instructions). */\ninterface StaticResourceContract extends BaseResourceContract {\n uri: string;\n uriTemplate?: never;\n complete?: never;\n}\n\n/** A resource identified by a URI template (FILESYSTEM_FILE_URI_TEMPLATE). */\ninterface TemplateResourceContract extends BaseResourceContract {\n uriTemplate: string;\n uri?: never;\n complete?: (\n variable: string,\n value: string,\n ctx?: { arguments?: Record<string, string> },\n ) => Promise<string[]> | string[];\n}\n\ntype ResourceContract = StaticResourceContract | TemplateResourceContract;\n\n// ═══════════════════════════════════════════════════════════════\n// instructions\n// ═══════════════════════════════════════════════════════════════\n\nfunction createInstructionsResource(options: ResourceRegistrationOptions): ResourceContract {\n const text = renderSections(buildSectionsRecord(options.readOnly));\n return {\n name: 'filesystem-mcp-instructions',\n title: 'Server Instructions',\n description: INSTRUCTIONS_SUMMARY,\n mimeType: 'text/markdown',\n uri: INSTRUCTIONS_URI,\n annotations: { audience: ['assistant'], priority: 0.8 },\n cacheHint: { cacheScope: options.cacheScope ?? 'public', ttlMs: 300_000 },\n read(uri) {\n return {\n contents: [\n {\n uri: uri.href,\n mimeType: 'text/markdown',\n text,\n },\n ],\n };\n },\n };\n}\n\n// ═══════════════════════════════════════════════════════════════\n// filesystem\n// ═══════════════════════════════════════════════════════════════\n\nfunction createFilesystemResource(options: ResourceRegistrationOptions): ResourceContract {\n const completer = options.pathGuard ? new PathCompleter(options.pathGuard) : undefined;\n const registry = options.watcherRegistry ?? createWatcherRegistry();\n // Only the per-server (legacy/stdio) registry is owned by this resource and\n // destroyed on dispose; the shared modern-leg registry is owned by the host\n // and torn down at server shutdown.\n const ownsRegistry = options.watcherRegistry === undefined;\n // The URIs this connection holds a `resources/subscribe` lease for. The wire\n // verb is per-URI and idempotent — a second subscribe is the same\n // subscription, and one unsubscribe ends it — but the registry ref-counts\n // leases (the HTTP listen leg needs that). Without this set a double\n // subscribe took two leases that one unsubscribe could not release, and an\n // unsubscribe for a URI never subscribed released a lease this connection\n // never took, dropping a watcher some other holder still wanted.\n const leasedUris = new Set<string>();\n // Subscribes mid-acquire, keyed by URI. Two concurrent subscribes for the\n // same URI must share one acquire: both passing the `leasedUris` check\n // before either finished took two registry leases that the single set entry\n // could release only once — on the shared modern registry that orphan lease\n // pinned a watcher until process shutdown.\n const inflight = new Map<string, Promise<boolean | undefined>>();\n\n return {\n name: 'filesystem-mcp-file',\n title: 'Workspace File',\n description: 'Read a file from the workspace. Subscribe to get updates when the file changes.',\n uriTemplate: FILESYSTEM_FILE_URI_TEMPLATE,\n annotations: { audience: ['assistant'], priority: 0.8 },\n // Without this the SDK falls back to its conservative `{ ttlMs: 0,\n // cacheScope: 'private' }`, making every file read uncacheable — and this\n // is the one resource with a live invalidation channel, so TTL and the\n // watcher compose exactly as the spec's caching section describes. The TTL\n // stays short because a non-subscriber gets no invalidation signal at all.\n cacheHint: { cacheScope: options.cacheScope ?? 'public', ttlMs: 5_000 },\n\n // No `list`: the template registers with `list: undefined` — readable but\n // not enumerable. Listing each allowed root as a concrete resource\n // duplicated the template and grew resources/list linearly with roots;\n // `list_roots` owns root discovery.\n\n async read(uri, _variables, _ctx: ServerContext) {\n if (!options.pathGuard) {\n throw new ProtocolError(ProtocolErrorCode.InternalError, 'PathGuard not configured');\n }\n // Decode via extractPath — the same decoder resources/subscribe uses — so\n // both consumers are symmetric with buildFileResourceUri's encoding. The\n // {+path} template variable arrives still percent-encoded, so validating\n // it directly would treat \"c%3A/proj/a.ts\" as a literal relative path;\n // no fallback to it here, or the two branches would validate different\n // strings. extractPath only fails past the template match on undecodable\n // percent-encoding, which is the caller's malformed URI.\n const rawPath = extractPath(uri.href);\n if (rawPath === undefined) {\n throw new ProtocolError(\n ProtocolErrorCode.InvalidParams,\n 'Malformed file URI: path is not valid percent-encoding',\n );\n }\n await options.pathGuard.validateExistingPath(rawPath);\n const fs = new GuardedFileSystem(options.pathGuard);\n const readResult = await fs.readRaw(rawPath);\n\n return {\n contents: [\n {\n uri: uri.href,\n mimeType: readResult.mimeType || 'application/octet-stream',\n ...(readResult.isBinary\n ? { blob: readResult.content.toString('base64') }\n : { text: readResult.content.toString('utf-8') }),\n },\n ],\n };\n },\n\n async complete(variable, value) {\n if (variable !== 'path' || !completer) return [];\n // Both ends speak the `{+path}` form (see encodeFileUriPath), not raw OS\n // paths: the partial arriving here is whatever this returned last, so the\n // decode mirrors the encode. An undecodable partial is matched as typed.\n const suggestions = await completer.suggest(decodeFileUriPath(value) ?? value);\n return suggestions.map(encodeFileUriPath);\n },\n\n subscribe(uri, notify) {\n const pathGuard = options.pathGuard;\n if (!pathGuard) return undefined;\n // Already subscribed on this connection: the watcher is live and the sink\n // is registered, so this is a no-op success rather than a second lease.\n if (leasedUris.has(uri)) return undefined;\n // A subscribe for this URI is mid-acquire: share its outcome instead of\n // taking a second lease the lease set cannot represent.\n const pending = inflight.get(uri);\n if (pending) return pending;\n\n const acquire = async (): Promise<boolean | undefined> => {\n const result = await registry.acquire(pathGuard, uri, notify, {\n markSubscribe: true,\n });\n if (result.ok) {\n leasedUris.add(uri);\n return undefined;\n }\n\n if (result.reason === 'bad-uri') {\n throw new ResourceNotFoundError(uri, `Cannot subscribe: not a filesystem URI`);\n }\n if (result.reason === 'invalid-path') {\n const err = result.error;\n if (isNotFoundish(err)) {\n throw new ResourceNotFoundError(uri, `Cannot subscribe to ${uri}: ${err.message}`);\n }\n Logger.warn(\n `Unexpected error validating path for watcher ${uri}: ${formatUnknownErrorMessage(err)}`,\n );\n throw err;\n }\n // Unsubscribed (or the registry destroyed) mid-await: the caller already\n // asked for this to stop, so there is nothing to reject.\n if (result.reason === 'stale') return undefined;\n // capped / attach-failed: `false` tells the handler to reject, since\n // undefined would report success with no watcher attached.\n return false;\n };\n\n const promise = acquire().finally(() => inflight.delete(uri));\n inflight.set(uri, promise);\n return promise;\n },\n\n unsubscribe(uri) {\n // Only release a lease this connection actually took.\n if (!leasedUris.delete(uri)) return;\n registry.release(uri);\n },\n\n destroy() {\n // Release what this connection still holds before the registry goes: on\n // the shared (modern) registry nothing else would ever end these leases.\n for (const uri of leasedUris) registry.release(uri);\n leasedUris.clear();\n if (ownsRegistry) registry.destroy();\n },\n };\n}\n\n// ═══════════════════════════════════════════════════════════════\n// result\n// ═══════════════════════════════════════════════════════════════\n\nfunction createResultResource(options: ResourceRegistrationOptions): ResourceContract {\n return {\n name: 'filesystem-mcp-result',\n title: 'Cached Tool Result',\n description:\n 'Ephemeral cached tool output. Listed via resources/list; entries expire after the cache TTL.',\n mimeType: 'application/json',\n uriTemplate: 'filesystem-mcp://result/{id}',\n annotations: { audience: ['assistant'], priority: 0.3 },\n cacheHint: { cacheScope: 'private', ttlMs: 60_000 },\n list() {\n const store = options.resourceStore;\n const uris = store.keys(); // prunes expired first\n const resources: Resource[] = [];\n for (const uri of uris) {\n try {\n const entry = store.getEntry(uri);\n resources.push({\n uri: entry.uri,\n name: entry.name,\n mimeType: entry.mimeType,\n size: entry.size,\n });\n } catch (err) {\n // An entry may expire between keys() and getEntry; skip it.\n if (isFsError(err) && err.code === ErrorCode.NOT_FOUND) continue;\n throw err;\n }\n }\n // Recent-first: keys() returns insertion order, so the newest is last.\n resources.reverse();\n return { resources };\n },\n read(uri, variables) {\n const { id } = variables;\n if (typeof id !== 'string' || id.length === 0) {\n throw new ProtocolError(\n ProtocolErrorCode.InvalidParams,\n 'Malformed result URI: missing {id}. Use the exact resourceUri returned by the tool.',\n );\n }\n\n let entry;\n try {\n entry = options.resourceStore.getEntry(uri.toString());\n } catch (err) {\n if (isFsError(err) && err.code === ErrorCode.NOT_FOUND) {\n throw new ResourceNotFoundError(\n uri.toString(),\n 'Cached result not found or expired. Re-run the tool to regenerate.',\n );\n }\n throw err;\n }\n return {\n contents: [{ uri: entry.uri, mimeType: entry.mimeType, text: entry.text }],\n };\n },\n };\n}\n\n// ═══════════════════════════════════════════════════════════════\n// export contracts\n// ═══════════════════════════════════════════════════════════════\n\nexport function getResourceContracts(options: ResourceRegistrationOptions): ResourceContract[] {\n return [\n createInstructionsResource(options),\n createResultResource(options),\n createFilesystemResource(options),\n ];\n}\n\n// ═══════════════════════════════════════════════════════════════\n// registrar\n// ═══════════════════════════════════════════════════════════════\n\nfunction wrapRead(contract: ResourceContract) {\n return async (uri: URL, variables: Record<string, string | string[]>, ctx: ServerContext) => {\n try {\n return await contract.read(uri, variables, ctx);\n } catch (error) {\n if (hasErrorShape(error, 'ProtocolError')) throw error;\n // A missing or out-of-root path is a not-found, not a malformed request.\n // The SDK puts ResourceNotFoundError on the wire as -32602 with\n // `data.uri`, which is what clients match on; -32002 is the older code\n // they also accept, and this SDK never emits it.\n if (isNotFoundish(error)) {\n throw new ResourceNotFoundError(uri.toString(), error.message);\n }\n // A remaining FsError (NOT_FILE, TOO_LARGE, ...) traces to the\n // caller-supplied URI; anything else is a server-side failure and must\n // not be blamed on the request.\n const msg = isFsError(error) ? error.message : formatUnknownErrorMessage(error);\n throw new ProtocolError(fsErrorCode(error), msg);\n }\n };\n}\n\nexport function registerResources(deps: ResourceRegistrarDeps): { dispose(): void } {\n const server = deps.server;\n const resourceContracts = getResourceContracts({ ...deps, readOnly: deps.readOnly ?? false });\n\n for (const contract of resourceContracts) {\n const config = {\n ...(contract.title !== undefined ? { title: contract.title } : {}),\n ...(contract.description !== undefined ? { description: contract.description } : {}),\n ...(contract.mimeType !== undefined ? { mimeType: contract.mimeType } : {}),\n ...(contract.annotations !== undefined ? { annotations: contract.annotations } : {}),\n ...(contract.cacheHint !== undefined ? { cacheHint: contract.cacheHint } : {}),\n };\n\n if (contract.uriTemplate) {\n const template = new ResourceTemplate(contract.uriTemplate, {\n list: contract.list,\n ...(contract.complete\n ? {\n complete: Object.fromEntries(\n new UriTemplate(contract.uriTemplate).variableNames.map((varName) => [\n varName,\n (value: string, ctx?: { arguments?: Record<string, string> }) => {\n const completeFn = contract.complete;\n return completeFn ? completeFn(varName, value, ctx) : [];\n },\n ]),\n ),\n }\n : {}),\n });\n\n server.registerResource(contract.name, template, config, wrapRead(contract));\n } else if (contract.uri) {\n server.registerResource(contract.name, contract.uri, config, (uri: URL, ctx: ServerContext) =>\n wrapRead(contract)(uri, {}, ctx),\n );\n }\n }\n\n // `resources/subscribe`/`unsubscribe` are 2025-era-only verbs; a modern\n // server answers `-32601 Method not found` for them, so registering these\n // handlers on a modern-era instance would dispatch to code no request can\n // reach.\n if (deps.era !== 'modern') {\n server.server.assertCanSetRequestHandler('resources/subscribe');\n server.server.assertCanSetRequestHandler('resources/unsubscribe');\n\n // One stable callback for the whole registrar, NOT one per subscribe. The\n // registry holds these in a Set keyed by identity, so a fresh closure per\n // request made a second `resources/subscribe` for the same URI register a\n // second sink: one file change then sent N notifications, and `unsubscribe`\n // (which only ends a lease) removed none of them. Subscribe is per-URI on\n // the wire, so the sink must be too — this makes it idempotent.\n const notifyUpdated = (updatedUri: string): void => {\n if (deps.notifier) {\n deps.notifier.resourceUpdated(updatedUri);\n return;\n }\n const updatePayload: ResourceUpdatedNotificationParams = { uri: updatedUri };\n // A failed notify means the connection went away; nothing to recover.\n void server.server.sendResourceUpdated(updatePayload).catch((err: unknown) => {\n Logger.debug('resource update not delivered', {\n uri: updatedUri,\n error: formatUnknownErrorMessage(err),\n });\n });\n };\n\n server.server.setRequestHandler(\n 'resources/subscribe',\n async (req: { params: SubscribeRequestParams }) => {\n const requestedResource = resourceUrlFromServerUrl(req.params.uri);\n let foundMatch = false;\n // A resource that exists but has no watcher (the instructions text, a\n // cached result) is NOT a not-found: reporting it as one told clients a\n // URI they can list and read does not exist. Track the two cases apart.\n let knownButNotSubscribable = false;\n for (const contract of resourceContracts) {\n const configured = contract.uri ?? contract.uriTemplate.split('{')[0];\n if (!contract.subscribe) {\n if (\n configured &&\n checkResourceAllowed({ requestedResource, configuredResource: configured })\n ) {\n knownButNotSubscribable = true;\n }\n continue;\n }\n if (!configured) continue;\n if (\n checkResourceAllowed({\n requestedResource,\n configuredResource: configured,\n })\n ) {\n foundMatch = true;\n const subscribeResult = await contract.subscribe(\n requestedResource.toString(),\n notifyUpdated,\n );\n if (subscribeResult === false) {\n // InternalError for want of anything better: ProtocolErrorCode\n // has no resource-limit member, and the message already names\n // the actionable cause.\n throw new ProtocolError(\n ProtocolErrorCode.InternalError,\n `Subscription rejected: no watcher attached (watcher limit ${MAX_WATCHERS} reached, or fs.watch failed to start).`,\n );\n }\n break;\n }\n }\n if (!foundMatch) {\n if (knownButNotSubscribable) {\n throw new ProtocolError(\n ProtocolErrorCode.InvalidParams,\n `Resource ${requestedResource.toString()} does not support subscriptions; only ${FILESYSTEM_FILE_URI_TEMPLATE} does. Read it again for the current contents.`,\n );\n }\n throw new ResourceNotFoundError(\n requestedResource.toString(),\n `Resource not found: ${requestedResource.toString()}`,\n );\n }\n return {};\n },\n );\n\n server.server.setRequestHandler(\n 'resources/unsubscribe',\n (req: { params: UnsubscribeRequestParams }) => {\n // Route by URI prefix, mirroring the subscribe handler: a broadcast\n // to every contract works while only one is subscribable, but hands a\n // second subscribable contract someone else's URI the day it appears.\n const requestedResource = resourceUrlFromServerUrl(req.params.uri);\n for (const contract of resourceContracts) {\n if (!contract.unsubscribe) continue;\n const configured = contract.uri ?? contract.uriTemplate.split('{')[0];\n if (!configured) continue;\n if (checkResourceAllowed({ requestedResource, configuredResource: configured })) {\n contract.unsubscribe(requestedResource.toString());\n }\n }\n return {};\n },\n );\n }\n\n return {\n dispose(): void {\n for (const contract of resourceContracts) {\n if (contract.destroy) {\n contract.destroy();\n }\n }\n },\n };\n}\n"]}
package/dist/server.d.ts CHANGED
@@ -1 +1,62 @@
1
- export { createServer, startHttpServer, startServer, } from './server/bootstrap.js';
1
+ import type { ServerNotifier } from '@modelcontextprotocol/server';
2
+ import { McpServer } from '@modelcontextprotocol/server';
3
+ import { GuardedFileSystem } from './core/fs.js';
4
+ import { PageSnapshotStore } from './core/page-store.js';
5
+ import type { ServerOptions } from './core/path.js';
6
+ import { PathGuard } from './core/path.js';
7
+ import { ResourceStore } from './core/store.js';
8
+ import type { WatcherRegistry } from './core/watcher-registry.js';
9
+ export type { ServerNotifier };
10
+ export type { ServerOptions };
11
+ export declare class FilesystemServerContext {
12
+ readonly mcp: McpServer;
13
+ readonly pathGuard: PathGuard;
14
+ readonly fs: GuardedFileSystem;
15
+ readonly pages: PageSnapshotStore;
16
+ readonly resources: ResourceStore;
17
+ /** False when the store is shared across instances and outlives this one. */
18
+ private readonly ownsPages;
19
+ private readonly resourceDisposable?;
20
+ private cleanedUp;
21
+ constructor(mcp: McpServer, pathGuard: PathGuard, pages: PageSnapshotStore, resources: ResourceStore, ownsPages: boolean, resourceDisposable?: {
22
+ dispose(): void;
23
+ });
24
+ disposeRuntimeState(): void;
25
+ close(): Promise<void>;
26
+ }
27
+ export declare function createServer(options?: ServerOptions, extraDeps?: {
28
+ /** Shared file-watcher registry for the modern (per-request) HTTP leg. */
29
+ watcherRegistry?: WatcherRegistry;
30
+ /** Modern-leg typed notification publisher. */
31
+ notifier?: ServerNotifier;
32
+ /**
33
+ * Guard to use instead of constructing one. The HTTP leg builds a single
34
+ * guard for the whole endpoint and passes it to every per-request instance,
35
+ * so an accepted access grant survives the request that accepted it (R8) and
36
+ * the listen-watcher path validates against the same allowed set. Omitted on
37
+ * stdio, where the instance is pinned for the connection and owns its guard.
38
+ */
39
+ pathGuard?: PathGuard;
40
+ /**
41
+ * Store to use instead of constructing one. The HTTP modern leg shares one
42
+ * store across every per-request instance, so a result a tool externalized
43
+ * in one POST survives to the follow-up resources/read. Omitted on stdio,
44
+ * where the pinned instance owns its store for the connection.
45
+ */
46
+ resourceStore?: ResourceStore;
47
+ /**
48
+ * Pagination snapshots shared by every modern HTTP request. Omitted on
49
+ * stdio, where the connection-owned context clears its store on close.
50
+ */
51
+ pageStore?: PageSnapshotStore;
52
+ /** The protocol era this instance serves; omitted where the caller does not know. */
53
+ era?: 'legacy' | 'modern';
54
+ /**
55
+ * The resolved HTTP credential, from `--api-key` or `API_KEY`. Lives here
56
+ * rather than on `ServerOptions` because that object is `PathGuard`'s
57
+ * constructor argument and is exposed on its public `options` field — a
58
+ * bearer secret has no business being reachable from a tool handler.
59
+ */
60
+ apiKey?: string;
61
+ }): Promise<FilesystemServerContext>;
62
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,cAAc,EACf,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAGzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAMlE,YAAY,EAAE,cAAc,EAAE,CAAC;AAC/B,YAAY,EAAE,aAAa,EAAE,CAAC;AAY9B,qBAAa,uBAAuB;IAClC,SAAgB,GAAG,EAAE,SAAS,CAAC;IAC/B,SAAgB,SAAS,EAAE,SAAS,CAAC;IACrC,SAAgB,EAAE,EAAE,iBAAiB,CAAC;IACtC,SAAgB,KAAK,EAAE,iBAAiB,CAAC;IACzC,SAAgB,SAAS,EAAE,aAAa,CAAC;IACzC,6EAA6E;IAC7E,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAU;IACpC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAkC;IACtE,OAAO,CAAC,SAAS,CAAS;gBAGxB,GAAG,EAAE,SAAS,EACd,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,iBAAiB,EACxB,SAAS,EAAE,aAAa,EACxB,SAAS,EAAE,OAAO,EAClB,kBAAkB,CAAC,EAAE;QAAE,OAAO,IAAI,IAAI,CAAA;KAAE;IAW1C,mBAAmB,IAAI,IAAI;IAOrB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAI7B;AAED,wBAAsB,YAAY,CAChC,OAAO,GAAE,aAAkB,EAC3B,SAAS,CAAC,EAAE;IACV,0EAA0E;IAC1E,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;;OAGG;IACH,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,qFAAqF;IACrF,GAAG,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC1B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GACA,OAAO,CAAC,uBAAuB,CAAC,CAwGlC"}
package/dist/server.js CHANGED
@@ -1 +1,139 @@
1
- export { createServer, startHttpServer, startServer, } from './server/bootstrap.js';
1
+ import { McpServer } from '@modelcontextprotocol/server';
2
+ import packageJson from '../package.json' with { type: 'json' };
3
+ import { GuardedFileSystem } from './core/fs.js';
4
+ import { requestStateCodec } from './core/input-required.js';
5
+ import { Logger } from './core/observability.js';
6
+ import { PageSnapshotStore } from './core/page-store.js';
7
+ import { PathGuard } from './core/path.js';
8
+ import { ResourceStore } from './core/store.js';
9
+ import { INSTRUCTIONS_SUMMARY, INSTRUCTIONS_URI } from './instructions.js';
10
+ import { registerPrompts } from './prompts.js';
11
+ import { registerResources } from './resources.js';
12
+ import { registerTools } from './tools/index.js';
13
+ // ═══════════════════════════════════════════════════════════════
14
+ // bootstrap
15
+ // ═══════════════════════════════════════════════════════════════
16
+ const { version: SERVER_VERSION, description: SERVER_DESCRIPTION, homepage: SERVER_HOMEPAGE, } = packageJson;
17
+ export class FilesystemServerContext {
18
+ mcp;
19
+ pathGuard;
20
+ fs;
21
+ pages;
22
+ resources;
23
+ /** False when the store is shared across instances and outlives this one. */
24
+ ownsPages;
25
+ resourceDisposable;
26
+ cleanedUp = false;
27
+ constructor(mcp, pathGuard, pages, resources, ownsPages, resourceDisposable) {
28
+ this.mcp = mcp;
29
+ this.pathGuard = pathGuard;
30
+ this.fs = new GuardedFileSystem(pathGuard);
31
+ this.pages = pages;
32
+ this.resources = resources;
33
+ this.ownsPages = ownsPages;
34
+ this.resourceDisposable = resourceDisposable;
35
+ }
36
+ disposeRuntimeState() {
37
+ if (this.cleanedUp)
38
+ return;
39
+ this.cleanedUp = true;
40
+ if (this.ownsPages)
41
+ this.pages.clear();
42
+ this.resourceDisposable?.dispose();
43
+ }
44
+ async close() {
45
+ this.disposeRuntimeState();
46
+ await this.mcp.close();
47
+ }
48
+ }
49
+ export async function createServer(options = {}, extraDeps) {
50
+ // `resources.subscribe` stays advertised on both eras: the verb itself is
51
+ // 2025-only, but with enforceStrictCapabilities the SDK also gates outbound
52
+ // `notifications/resources/updated` — which the modern `subscriptions/listen`
53
+ // stream delivers — on this same capability bit.
54
+ const capabilities = {
55
+ resources: { subscribe: true, listChanged: true },
56
+ tools: {},
57
+ prompts: {},
58
+ completions: {},
59
+ };
60
+ const cacheScope = extraDeps?.apiKey ? 'private' : 'public';
61
+ const serverConfig = {
62
+ capabilities,
63
+ enforceStrictCapabilities: true,
64
+ cacheHints: {
65
+ 'tools/list': { ttlMs: 3_600_000, cacheScope },
66
+ 'prompts/list': { ttlMs: 3_600_000, cacheScope },
67
+ // Always private, never `cacheScope`: this list enumerates the
68
+ // ResourceStore, so its entries are one caller's externalized tool output
69
+ // — the same entries whose own read hint is `private` (resources.ts). The
70
+ // other four lists are the same for every caller and follow the key, and
71
+ // they are built from frozen module-level arrays that cannot change at
72
+ // runtime, so an hour is honest: a shorter hint only buys the client a
73
+ // re-fetch of bytes that cannot have differed, at the cost of the prompt
74
+ // cache stability the spec asks deterministic ordering to preserve.
75
+ 'resources/list': { ttlMs: 30_000, cacheScope: 'private' },
76
+ 'resources/templates/list': { ttlMs: 3_600_000, cacheScope },
77
+ 'server/discover': { ttlMs: 3_600_000, cacheScope },
78
+ },
79
+ // Multi-round-trip `requestState` integrity (protocol revision 2026-07-28):
80
+ // the codec verifies the HMAC on every retried round before the handler
81
+ // runs, so a tampered or expired state is rejected as `-32602` rather than
82
+ // trusted. The decoded `PendingState` reaches handlers via
83
+ // `ctx.mcpReq.requestState<T>()`.
84
+ // eslint-disable-next-line @typescript-eslint/unbound-method
85
+ requestState: { verify: requestStateCodec.verify },
86
+ };
87
+ serverConfig.instructions =
88
+ `${INSTRUCTIONS_SUMMARY} ` +
89
+ `For full guidance, read ${INSTRUCTIONS_URI} or run the get-help prompt.`;
90
+ const implementation = {
91
+ name: 'filesystem-mcp',
92
+ title: 'Filesystem MCP',
93
+ version: SERVER_VERSION,
94
+ ...(SERVER_DESCRIPTION ? { description: SERVER_DESCRIPTION } : {}),
95
+ ...(SERVER_HOMEPAGE ? { websiteUrl: SERVER_HOMEPAGE } : {}),
96
+ };
97
+ const server = new McpServer(implementation, serverConfig);
98
+ server.server.fallbackNotificationHandler = (notification) => {
99
+ Logger.debug('Unhandled client notification', { method: notification.method });
100
+ return Promise.resolve();
101
+ };
102
+ // A failed send means the connection went away; nothing to recover.
103
+ const resourceStore = extraDeps?.resourceStore ??
104
+ new ResourceStore(() => {
105
+ if (extraDeps?.notifier) {
106
+ extraDeps.notifier.resourcesChanged();
107
+ return;
108
+ }
109
+ void server.server.sendResourceListChanged().catch((error) => {
110
+ Logger.debug('resource list_changed not delivered', { error: String(error) });
111
+ });
112
+ });
113
+ const pageStore = extraDeps?.pageStore ?? new PageSnapshotStore();
114
+ const pathGuard = extraDeps?.pathGuard ?? new PathGuard(options, true);
115
+ // Recompute once per guard, keyed on the guard's own state rather than on
116
+ // whether it was injected — an injected-but-uninitialized guard would
117
+ // otherwise deny every path. Not unconditional: the HTTP leg shares one guard
118
+ // across a fresh instance per request, and a repeat recompute would both redo
119
+ // the root resolution per request and race a concurrent `applyGrant`, which
120
+ // commits under a mutation lock this call does not take.
121
+ if (!pathGuard.isInitialized())
122
+ await pathGuard.recomputeAllowedDirectories();
123
+ const deps = {
124
+ server,
125
+ pathGuard,
126
+ pageStore,
127
+ resourceStore,
128
+ cacheScope,
129
+ ...(options.readOnly ? { readOnly: true } : {}),
130
+ ...(extraDeps?.watcherRegistry ? { watcherRegistry: extraDeps.watcherRegistry } : {}),
131
+ ...(extraDeps?.notifier ? { notifier: extraDeps.notifier } : {}),
132
+ ...(extraDeps?.era ? { era: extraDeps.era } : {}),
133
+ };
134
+ const resourceDisposable = registerResources(deps);
135
+ registerPrompts(deps);
136
+ registerTools(deps);
137
+ return new FilesystemServerContext(server, pathGuard, pageStore, resourceStore, extraDeps?.pageStore === undefined, resourceDisposable);
138
+ }
139
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n Implementation,\n ServerCapabilities,\n ServerNotifier,\n} from '@modelcontextprotocol/server';\nimport { McpServer } from '@modelcontextprotocol/server';\n\nimport packageJson from '../package.json' with { type: 'json' };\nimport { GuardedFileSystem } from './core/fs.js';\nimport { requestStateCodec } from './core/input-required.js';\nimport { Logger } from './core/observability.js';\nimport { PageSnapshotStore } from './core/page-store.js';\nimport type { ServerOptions } from './core/path.js';\nimport { PathGuard } from './core/path.js';\nimport { ResourceStore } from './core/store.js';\nimport type { WatcherRegistry } from './core/watcher-registry.js';\nimport { INSTRUCTIONS_SUMMARY, INSTRUCTIONS_URI } from './instructions.js';\nimport { registerPrompts } from './prompts.js';\nimport { registerResources } from './resources.js';\nimport { registerTools } from './tools/index.js';\n\nexport type { ServerNotifier };\nexport type { ServerOptions };\n\n// ═══════════════════════════════════════════════════════════════\n// bootstrap\n// ═══════════════════════════════════════════════════════════════\n\nconst {\n version: SERVER_VERSION,\n description: SERVER_DESCRIPTION,\n homepage: SERVER_HOMEPAGE,\n} = packageJson;\n\nexport class FilesystemServerContext {\n public readonly mcp: McpServer;\n public readonly pathGuard: PathGuard;\n public readonly fs: GuardedFileSystem;\n public readonly pages: PageSnapshotStore;\n public readonly resources: ResourceStore;\n /** False when the store is shared across instances and outlives this one. */\n private readonly ownsPages: boolean;\n private readonly resourceDisposable?: { dispose(): void } | undefined;\n private cleanedUp = false;\n\n constructor(\n mcp: McpServer,\n pathGuard: PathGuard,\n pages: PageSnapshotStore,\n resources: ResourceStore,\n ownsPages: boolean,\n resourceDisposable?: { dispose(): void },\n ) {\n this.mcp = mcp;\n this.pathGuard = pathGuard;\n this.fs = new GuardedFileSystem(pathGuard);\n this.pages = pages;\n this.resources = resources;\n this.ownsPages = ownsPages;\n this.resourceDisposable = resourceDisposable;\n }\n\n disposeRuntimeState(): void {\n if (this.cleanedUp) return;\n this.cleanedUp = true;\n if (this.ownsPages) this.pages.clear();\n this.resourceDisposable?.dispose();\n }\n\n async close(): Promise<void> {\n this.disposeRuntimeState();\n await this.mcp.close();\n }\n}\n\nexport async function createServer(\n options: ServerOptions = {},\n extraDeps?: {\n /** Shared file-watcher registry for the modern (per-request) HTTP leg. */\n watcherRegistry?: WatcherRegistry;\n /** Modern-leg typed notification publisher. */\n notifier?: ServerNotifier;\n /**\n * Guard to use instead of constructing one. The HTTP leg builds a single\n * guard for the whole endpoint and passes it to every per-request instance,\n * so an accepted access grant survives the request that accepted it (R8) and\n * the listen-watcher path validates against the same allowed set. Omitted on\n * stdio, where the instance is pinned for the connection and owns its guard.\n */\n pathGuard?: PathGuard;\n /**\n * Store to use instead of constructing one. The HTTP modern leg shares one\n * store across every per-request instance, so a result a tool externalized\n * in one POST survives to the follow-up resources/read. Omitted on stdio,\n * where the pinned instance owns its store for the connection.\n */\n resourceStore?: ResourceStore;\n /**\n * Pagination snapshots shared by every modern HTTP request. Omitted on\n * stdio, where the connection-owned context clears its store on close.\n */\n pageStore?: PageSnapshotStore;\n /** The protocol era this instance serves; omitted where the caller does not know. */\n era?: 'legacy' | 'modern';\n /**\n * The resolved HTTP credential, from `--api-key` or `API_KEY`. Lives here\n * rather than on `ServerOptions` because that object is `PathGuard`'s\n * constructor argument and is exposed on its public `options` field — a\n * bearer secret has no business being reachable from a tool handler.\n */\n apiKey?: string;\n },\n): Promise<FilesystemServerContext> {\n // `resources.subscribe` stays advertised on both eras: the verb itself is\n // 2025-only, but with enforceStrictCapabilities the SDK also gates outbound\n // `notifications/resources/updated` — which the modern `subscriptions/listen`\n // stream delivers — on this same capability bit.\n const capabilities = {\n resources: { subscribe: true, listChanged: true },\n tools: {},\n prompts: {},\n completions: {},\n } satisfies ServerCapabilities;\n\n const cacheScope: 'private' | 'public' = extraDeps?.apiKey ? 'private' : 'public';\n const serverConfig: NonNullable<ConstructorParameters<typeof McpServer>[1]> = {\n capabilities,\n enforceStrictCapabilities: true,\n cacheHints: {\n 'tools/list': { ttlMs: 3_600_000, cacheScope },\n 'prompts/list': { ttlMs: 3_600_000, cacheScope },\n // Always private, never `cacheScope`: this list enumerates the\n // ResourceStore, so its entries are one caller's externalized tool output\n // — the same entries whose own read hint is `private` (resources.ts). The\n // other four lists are the same for every caller and follow the key, and\n // they are built from frozen module-level arrays that cannot change at\n // runtime, so an hour is honest: a shorter hint only buys the client a\n // re-fetch of bytes that cannot have differed, at the cost of the prompt\n // cache stability the spec asks deterministic ordering to preserve.\n 'resources/list': { ttlMs: 30_000, cacheScope: 'private' },\n 'resources/templates/list': { ttlMs: 3_600_000, cacheScope },\n 'server/discover': { ttlMs: 3_600_000, cacheScope },\n },\n // Multi-round-trip `requestState` integrity (protocol revision 2026-07-28):\n // the codec verifies the HMAC on every retried round before the handler\n // runs, so a tampered or expired state is rejected as `-32602` rather than\n // trusted. The decoded `PendingState` reaches handlers via\n // `ctx.mcpReq.requestState<T>()`.\n // eslint-disable-next-line @typescript-eslint/unbound-method\n requestState: { verify: requestStateCodec.verify },\n };\n\n serverConfig.instructions =\n `${INSTRUCTIONS_SUMMARY} ` +\n `For full guidance, read ${INSTRUCTIONS_URI} or run the get-help prompt.`;\n\n const implementation: Implementation = {\n name: 'filesystem-mcp',\n title: 'Filesystem MCP',\n version: SERVER_VERSION,\n ...(SERVER_DESCRIPTION ? { description: SERVER_DESCRIPTION } : {}),\n ...(SERVER_HOMEPAGE ? { websiteUrl: SERVER_HOMEPAGE } : {}),\n };\n const server = new McpServer(implementation, serverConfig);\n server.server.fallbackNotificationHandler = (notification) => {\n Logger.debug('Unhandled client notification', { method: notification.method });\n return Promise.resolve();\n };\n\n // A failed send means the connection went away; nothing to recover.\n const resourceStore =\n extraDeps?.resourceStore ??\n new ResourceStore(() => {\n if (extraDeps?.notifier) {\n extraDeps.notifier.resourcesChanged();\n return;\n }\n void server.server.sendResourceListChanged().catch((error: unknown) => {\n Logger.debug('resource list_changed not delivered', { error: String(error) });\n });\n });\n const pageStore = extraDeps?.pageStore ?? new PageSnapshotStore();\n\n const pathGuard = extraDeps?.pathGuard ?? new PathGuard(options, true);\n // Recompute once per guard, keyed on the guard's own state rather than on\n // whether it was injected — an injected-but-uninitialized guard would\n // otherwise deny every path. Not unconditional: the HTTP leg shares one guard\n // across a fresh instance per request, and a repeat recompute would both redo\n // the root resolution per request and race a concurrent `applyGrant`, which\n // commits under a mutation lock this call does not take.\n if (!pathGuard.isInitialized()) await pathGuard.recomputeAllowedDirectories();\n\n const deps = {\n server,\n pathGuard,\n pageStore,\n resourceStore,\n cacheScope,\n ...(options.readOnly ? { readOnly: true } : {}),\n ...(extraDeps?.watcherRegistry ? { watcherRegistry: extraDeps.watcherRegistry } : {}),\n ...(extraDeps?.notifier ? { notifier: extraDeps.notifier } : {}),\n ...(extraDeps?.era ? { era: extraDeps.era } : {}),\n };\n\n const resourceDisposable = registerResources(deps);\n registerPrompts(deps);\n registerTools(deps);\n\n return new FilesystemServerContext(\n server,\n pathGuard,\n pageStore,\n resourceStore,\n extraDeps?.pageStore === undefined,\n resourceDisposable,\n );\n}\n"]}
@@ -0,0 +1,89 @@
1
+ import type { InputRequiredResult } from '@modelcontextprotocol/server';
2
+ import { ErrorCode } from '../core/errors.js';
3
+ import type { PairFailureItem } from '../core/schema.js';
4
+ import type { ToolCtx } from './define.js';
5
+ interface PerPathError {
6
+ code: ErrorCode;
7
+ message: string;
8
+ path?: string;
9
+ suggestion?: string;
10
+ }
11
+ export type PerPathResult<T> = {
12
+ path: string;
13
+ value: T;
14
+ } | {
15
+ path: string;
16
+ error: PerPathError;
17
+ };
18
+ export interface BatchResult<T> {
19
+ results: PerPathResult<T>[];
20
+ summary: {
21
+ total: number;
22
+ succeeded: number;
23
+ failed: number;
24
+ };
25
+ }
26
+ type BatchInput<TOverride> = {
27
+ path: string;
28
+ } | {
29
+ paths: string[];
30
+ } | {
31
+ files: ({
32
+ path: string;
33
+ } & TOverride)[];
34
+ };
35
+ interface RunOverPathsOptions {
36
+ defaultErrorCode?: ErrorCode;
37
+ concurrency?: number;
38
+ }
39
+ export declare function runOverPaths<TOverride, TPerPath>(args: BatchInput<TOverride>, ctx: ToolCtx, perPath: (item: {
40
+ path: string;
41
+ override?: TOverride;
42
+ }, ctx: ToolCtx) => Promise<TPerPath>, options?: RunOverPathsOptions): Promise<BatchResult<TPerPath>>;
43
+ /** The minimum a pair plan must expose for the shared driver to route it. */
44
+ export interface PairPlan {
45
+ readonly pair: {
46
+ source: string;
47
+ destination: string;
48
+ };
49
+ readonly validDest: string;
50
+ readonly pending: boolean;
51
+ }
52
+ export type PairPlanResult<TPlan extends PairPlan> = {
53
+ status: 'fail';
54
+ failure: PairFailureItem;
55
+ } | {
56
+ status: 'noop';
57
+ } | {
58
+ status: 'plan';
59
+ plan: TPlan;
60
+ };
61
+ /** A discriminated union, so the fold below narrows without a generic cast. */
62
+ export type PairExecResult<TResult> = {
63
+ readonly skipped: string;
64
+ } | {
65
+ readonly value: TResult;
66
+ };
67
+ export interface PairBatchOutcome<TResult> {
68
+ results: TResult[];
69
+ skipped: string[];
70
+ failures: PairFailureItem[];
71
+ }
72
+ export declare function pairFailure(pair: {
73
+ source: string;
74
+ destination: string;
75
+ }, error: unknown): PairFailureItem;
76
+ interface RunOverPairsOptions<TItem, TPlan extends PairPlan, TResult> {
77
+ readonly op: 'copy' | 'move';
78
+ readonly plan: (item: TItem) => Promise<PairPlanResult<TPlan>>;
79
+ readonly execute: (plan: TPlan, pendingSorted: readonly string[]) => Promise<PairExecResult<TResult>>;
80
+ }
81
+ /**
82
+ * The source→destination sibling of `runOverPaths`: plan every pair, fail closed
83
+ * on a duplicated destination, round-trip the overwrite confirmations as one
84
+ * set, then execute what survived in parallel. `copy` and `move` differ only in
85
+ * their `plan` and `execute` callbacks.
86
+ */
87
+ export declare function runOverPairs<TItem, TPlan extends PairPlan, TResult>(items: readonly TItem[], ctx: ToolCtx, opts: RunOverPairsOptions<TItem, TPlan, TResult>): Promise<PairBatchOutcome<TResult> | InputRequiredResult>;
88
+ export {};
89
+ //# sourceMappingURL=batch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch.d.ts","sourceRoot":"","sources":["../../src/tools/batch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,157 @@
1
+ import { processInParallel } from '../core/concurrency.js';
2
+ import { ErrorCode, FsError, Problem, rethrowIfAborted } from '../core/errors.js';
3
+ import { choiceInput, pendingRoundTrip } from '../core/input-required.js';
4
+ import { IS_CASE_INSENSITIVE_FS } from '../core/path-utils.js';
5
+ import { PARALLEL_CONCURRENCY } from '../core/util.js';
6
+ function normalizeBatchItems(args) {
7
+ if ('path' in args)
8
+ return [{ path: args.path }];
9
+ if ('paths' in args)
10
+ return args.paths.map((path) => ({ path }));
11
+ if ('files' in args)
12
+ return args.files.map(({ path, ...rest }) => ({
13
+ path,
14
+ override: rest,
15
+ }));
16
+ return [];
17
+ }
18
+ export async function runOverPaths(args, ctx, perPath, options) {
19
+ const items = normalizeBatchItems(args);
20
+ if (items.length === 0) {
21
+ throw new FsError(ErrorCode.INVALID_INPUT, "runOverPaths: at least one of 'path', 'paths', or 'files' must be provided");
22
+ }
23
+ const defaultErrorCode = options?.defaultErrorCode ?? ErrorCode.UNKNOWN;
24
+ const concurrency = options?.concurrency ?? PARALLEL_CONCURRENCY;
25
+ const total = items.length;
26
+ let completed = 0;
27
+ const results = new Array(total);
28
+ const tick = () => {
29
+ completed += 1;
30
+ ctx.onProgress?.({ current: completed, total });
31
+ };
32
+ await processInParallel(items.map((item, index) => ({ item, index })), async ({ item, index }) => {
33
+ try {
34
+ const value = await perPath(item, ctx);
35
+ results[index] = { path: item.path, value };
36
+ }
37
+ catch (error) {
38
+ results[index] = {
39
+ path: item.path,
40
+ error: Problem.toPerFileError(error, defaultErrorCode, item.path),
41
+ };
42
+ }
43
+ finally {
44
+ tick();
45
+ }
46
+ return undefined;
47
+ }, concurrency, ctx.signal);
48
+ let succeeded = 0;
49
+ for (const result of results) {
50
+ if (!('error' in result))
51
+ succeeded += 1;
52
+ }
53
+ return {
54
+ results,
55
+ summary: { total, succeeded, failed: total - succeeded },
56
+ };
57
+ }
58
+ export function pairFailure(pair, error) {
59
+ return {
60
+ source: pair.source,
61
+ destination: pair.destination,
62
+ error: Problem.toPerFileError(error, ErrorCode.UNKNOWN, pair.source),
63
+ };
64
+ }
65
+ /**
66
+ * The source→destination sibling of `runOverPaths`: plan every pair, fail closed
67
+ * on a duplicated destination, round-trip the overwrite confirmations as one
68
+ * set, then execute what survived in parallel. `copy` and `move` differ only in
69
+ * their `plan` and `execute` callbacks.
70
+ */
71
+ export async function runOverPairs(items, ctx, opts) {
72
+ const verb = opts.op === 'copy' ? 'Copy' : 'Move';
73
+ const { results: planned, errors: planErrors } = await processInParallel(items, opts.plan, PARALLEL_CONCURRENCY, ctx.signal);
74
+ // plan callbacks are fail-closed (they return { status: 'fail' }, never
75
+ // throw), so planErrors should always be empty. Surface the first rather
76
+ // than silently dropping the item if a future plan callback violates that.
77
+ const firstPlanError = planErrors[0];
78
+ if (firstPlanError)
79
+ throw firstPlanError.error;
80
+ const failures = [];
81
+ const candidates = [];
82
+ for (const { value } of planned) {
83
+ if (value.status === 'fail')
84
+ failures.push(value.failure);
85
+ else if (value.status === 'plan')
86
+ candidates.push(value.plan);
87
+ // 'noop' (self-copy / self-move) is silently skipped.
88
+ }
89
+ // Two sources targeting the same destination in one batch would otherwise
90
+ // collapse to a single shared overwrite confirmation and let the second
91
+ // one silently clobber the first's freshly-written content. Fail closed:
92
+ // only the first plan per destination proceeds; later ones targeting the
93
+ // same destination are reported as a per-item failure.
94
+ const seenDest = new Set();
95
+ const ready = [];
96
+ for (const plan of candidates) {
97
+ const destKey = IS_CASE_INSENSITIVE_FS ? plan.validDest.toLowerCase() : plan.validDest;
98
+ if (seenDest.has(destKey)) {
99
+ failures.push(pairFailure(plan.pair, new FsError(ErrorCode.INVALID_INPUT, `${verb} cancelled: another entry in this batch already targets destination "${plan.pair.destination}"`, plan.pair.destination)));
100
+ continue;
101
+ }
102
+ seenDest.add(destKey);
103
+ ready.push(plan);
104
+ }
105
+ const pendingSorted = ready
106
+ .filter((p) => p.pending)
107
+ .map((p) => p.validDest)
108
+ .sort();
109
+ if (pendingSorted.length > 0) {
110
+ // Round 1 returns input_required; a retry whose verified state does not
111
+ // bind this overwrite set throws (R9) via `pendingRoundTrip`.
112
+ const round = await pendingRoundTrip({
113
+ op: opts.op,
114
+ pending: pendingSorted,
115
+ requestState: ctx.requestState,
116
+ clientCapabilities: ctx.clientCapabilities,
117
+ buildInputs: (dests) => dests.map((dest, i) => choiceInput(`confirm_${i}`, opts.op === 'move'
118
+ ? `"${dest}" already exists. Overwrite it?`
119
+ : `Destination "${dest}" already exists. Overwrite it?`, [
120
+ { value: 'overwrite', title: 'Overwrite' },
121
+ { value: 'skip', title: 'Skip' },
122
+ ])),
123
+ });
124
+ if (round !== undefined)
125
+ return round;
126
+ }
127
+ const total = ready.length;
128
+ let completed = 0;
129
+ const tick = () => {
130
+ completed += 1;
131
+ ctx.onProgress?.({ current: completed, total });
132
+ };
133
+ const { results: execResults, errors: execErrors } = await processInParallel(ready, async (plan) => {
134
+ try {
135
+ return await opts.execute(plan, pendingSorted);
136
+ }
137
+ finally {
138
+ tick();
139
+ }
140
+ }, PARALLEL_CONCURRENCY, ctx.signal);
141
+ for (const { error, index } of execErrors) {
142
+ rethrowIfAborted(error);
143
+ const plan = ready[index];
144
+ if (plan)
145
+ failures.push(pairFailure(plan.pair, error));
146
+ }
147
+ const results = [];
148
+ const skipped = [];
149
+ for (const { value } of execResults) {
150
+ if ('skipped' in value)
151
+ skipped.push(value.skipped);
152
+ else
153
+ results.push(value.value);
154
+ }
155
+ return { results, skipped, failures };
156
+ }
157
+ //# sourceMappingURL=batch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch.js","sourceRoot":"","sources":["../../src/tools/batch.ts"],"names":[],"mappings":"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","sourcesContent":["import type { InputRequiredResult } from '@modelcontextprotocol/server';\n\nimport { processInParallel } from '../core/concurrency.js';\nimport { ErrorCode, FsError, Problem, rethrowIfAborted } from '../core/errors.js';\nimport { choiceInput, pendingRoundTrip } from '../core/input-required.js';\nimport { IS_CASE_INSENSITIVE_FS } from '../core/path-utils.js';\nimport type { PairFailureItem } from '../core/schema.js';\nimport { PARALLEL_CONCURRENCY } from '../core/util.js';\nimport type { ToolCtx } from './define.js';\n\ninterface PerPathError {\n code: ErrorCode;\n message: string;\n path?: string;\n suggestion?: string;\n}\n\nexport type PerPathResult<T> = { path: string; value: T } | { path: string; error: PerPathError };\n\nexport interface BatchResult<T> {\n results: PerPathResult<T>[];\n summary: { total: number; succeeded: number; failed: number };\n}\n\ntype BatchInput<TOverride> =\n { path: string } | { paths: string[] } | { files: ({ path: string } & TOverride)[] };\n\ninterface RunOverPathsOptions {\n defaultErrorCode?: ErrorCode;\n concurrency?: number;\n}\n\nfunction normalizeBatchItems<TOverride>(\n args: BatchInput<TOverride>,\n): { path: string; override?: TOverride }[] {\n if ('path' in args) return [{ path: args.path }];\n if ('paths' in args) return args.paths.map((path) => ({ path }));\n if ('files' in args)\n return args.files.map(({ path, ...rest }) => ({\n path,\n override: rest as TOverride,\n }));\n return [];\n}\n\nexport async function runOverPaths<TOverride, TPerPath>(\n args: BatchInput<TOverride>,\n ctx: ToolCtx,\n perPath: (item: { path: string; override?: TOverride }, ctx: ToolCtx) => Promise<TPerPath>,\n options?: RunOverPathsOptions,\n): Promise<BatchResult<TPerPath>> {\n const items = normalizeBatchItems(args);\n if (items.length === 0) {\n throw new FsError(\n ErrorCode.INVALID_INPUT,\n \"runOverPaths: at least one of 'path', 'paths', or 'files' must be provided\",\n );\n }\n\n const defaultErrorCode = options?.defaultErrorCode ?? ErrorCode.UNKNOWN;\n const concurrency = options?.concurrency ?? PARALLEL_CONCURRENCY;\n\n const total = items.length;\n let completed = 0;\n const results: PerPathResult<TPerPath>[] = new Array<PerPathResult<TPerPath>>(total);\n\n const tick = (): void => {\n completed += 1;\n ctx.onProgress?.({ current: completed, total });\n };\n\n await processInParallel<\n { item: { path: string; override?: TOverride }; index: number },\n undefined\n >(\n items.map((item, index) => ({ item, index })),\n async ({ item, index }) => {\n try {\n const value = await perPath(item, ctx);\n results[index] = { path: item.path, value };\n } catch (error: unknown) {\n results[index] = {\n path: item.path,\n error: Problem.toPerFileError(error, defaultErrorCode, item.path),\n };\n } finally {\n tick();\n }\n return undefined;\n },\n concurrency,\n ctx.signal,\n );\n\n let succeeded = 0;\n for (const result of results) {\n if (!('error' in result)) succeeded += 1;\n }\n\n return {\n results,\n summary: { total, succeeded, failed: total - succeeded },\n };\n}\n\n/** The minimum a pair plan must expose for the shared driver to route it. */\nexport interface PairPlan {\n readonly pair: { source: string; destination: string };\n readonly validDest: string;\n readonly pending: boolean;\n}\n\nexport type PairPlanResult<TPlan extends PairPlan> =\n | { status: 'fail'; failure: PairFailureItem }\n | { status: 'noop' }\n | { status: 'plan'; plan: TPlan };\n\n/** A discriminated union, so the fold below narrows without a generic cast. */\nexport type PairExecResult<TResult> = { readonly skipped: string } | { readonly value: TResult };\n\nexport interface PairBatchOutcome<TResult> {\n results: TResult[];\n skipped: string[];\n failures: PairFailureItem[];\n}\n\nexport function pairFailure(\n pair: { source: string; destination: string },\n error: unknown,\n): PairFailureItem {\n return {\n source: pair.source,\n destination: pair.destination,\n error: Problem.toPerFileError(error, ErrorCode.UNKNOWN, pair.source),\n };\n}\n\ninterface RunOverPairsOptions<TItem, TPlan extends PairPlan, TResult> {\n readonly op: 'copy' | 'move';\n readonly plan: (item: TItem) => Promise<PairPlanResult<TPlan>>;\n readonly execute: (\n plan: TPlan,\n pendingSorted: readonly string[],\n ) => Promise<PairExecResult<TResult>>;\n}\n\n/**\n * The source→destination sibling of `runOverPaths`: plan every pair, fail closed\n * on a duplicated destination, round-trip the overwrite confirmations as one\n * set, then execute what survived in parallel. `copy` and `move` differ only in\n * their `plan` and `execute` callbacks.\n */\nexport async function runOverPairs<TItem, TPlan extends PairPlan, TResult>(\n items: readonly TItem[],\n ctx: ToolCtx,\n opts: RunOverPairsOptions<TItem, TPlan, TResult>,\n): Promise<PairBatchOutcome<TResult> | InputRequiredResult> {\n const verb = opts.op === 'copy' ? 'Copy' : 'Move';\n\n const { results: planned, errors: planErrors } = await processInParallel(\n items,\n opts.plan,\n PARALLEL_CONCURRENCY,\n ctx.signal,\n );\n // plan callbacks are fail-closed (they return { status: 'fail' }, never\n // throw), so planErrors should always be empty. Surface the first rather\n // than silently dropping the item if a future plan callback violates that.\n const firstPlanError = planErrors[0];\n if (firstPlanError) throw firstPlanError.error;\n\n const failures: PairFailureItem[] = [];\n const candidates: TPlan[] = [];\n for (const { value } of planned) {\n if (value.status === 'fail') failures.push(value.failure);\n else if (value.status === 'plan') candidates.push(value.plan);\n // 'noop' (self-copy / self-move) is silently skipped.\n }\n\n // Two sources targeting the same destination in one batch would otherwise\n // collapse to a single shared overwrite confirmation and let the second\n // one silently clobber the first's freshly-written content. Fail closed:\n // only the first plan per destination proceeds; later ones targeting the\n // same destination are reported as a per-item failure.\n const seenDest = new Set<string>();\n const ready: TPlan[] = [];\n for (const plan of candidates) {\n const destKey = IS_CASE_INSENSITIVE_FS ? plan.validDest.toLowerCase() : plan.validDest;\n if (seenDest.has(destKey)) {\n failures.push(\n pairFailure(\n plan.pair,\n new FsError(\n ErrorCode.INVALID_INPUT,\n `${verb} cancelled: another entry in this batch already targets destination \"${plan.pair.destination}\"`,\n plan.pair.destination,\n ),\n ),\n );\n continue;\n }\n seenDest.add(destKey);\n ready.push(plan);\n }\n\n const pendingSorted = ready\n .filter((p) => p.pending)\n .map((p) => p.validDest)\n .sort();\n if (pendingSorted.length > 0) {\n // Round 1 returns input_required; a retry whose verified state does not\n // bind this overwrite set throws (R9) via `pendingRoundTrip`.\n const round = await pendingRoundTrip({\n op: opts.op,\n pending: pendingSorted,\n requestState: ctx.requestState,\n clientCapabilities: ctx.clientCapabilities,\n buildInputs: (dests) =>\n dests.map((dest, i) =>\n choiceInput(\n `confirm_${i}`,\n opts.op === 'move'\n ? `\"${dest}\" already exists. Overwrite it?`\n : `Destination \"${dest}\" already exists. Overwrite it?`,\n [\n { value: 'overwrite', title: 'Overwrite' },\n { value: 'skip', title: 'Skip' },\n ],\n ),\n ),\n });\n if (round !== undefined) return round;\n }\n\n const total = ready.length;\n let completed = 0;\n const tick = (): void => {\n completed += 1;\n ctx.onProgress?.({ current: completed, total });\n };\n const { results: execResults, errors: execErrors } = await processInParallel(\n ready,\n async (plan) => {\n try {\n return await opts.execute(plan, pendingSorted);\n } finally {\n tick();\n }\n },\n PARALLEL_CONCURRENCY,\n ctx.signal,\n );\n\n for (const { error, index } of execErrors) {\n rethrowIfAborted(error);\n const plan = ready[index];\n if (plan) failures.push(pairFailure(plan.pair, error));\n }\n\n const results: TResult[] = [];\n const skipped: string[] = [];\n for (const { value } of execResults) {\n if ('skipped' in value) skipped.push(value.skipped);\n else results.push(value.value);\n }\n\n return { results, skipped, failures };\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export declare const CREATE: import("./define.js").DefinedTool;
2
+ //# sourceMappingURL=create.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/tools/create.ts"],"names":[],"mappings":"AAqFA,eAAO,MAAM,MAAM,mCA4FjB,CAAC"}