@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
@@ -0,0 +1,356 @@
1
+ import { ProtocolErrorCode } from '@modelcontextprotocol/server';
2
+ import * as z from 'zod/v4';
3
+ export const ErrorCode = {
4
+ ACCESS_DENIED: 'ACCESS_DENIED',
5
+ NOT_FOUND: 'NOT_FOUND',
6
+ NOT_FILE: 'NOT_FILE',
7
+ NOT_DIRECTORY: 'NOT_DIRECTORY',
8
+ TOO_LARGE: 'TOO_LARGE',
9
+ TIMEOUT: 'TIMEOUT',
10
+ CANCELLED: 'CANCELLED',
11
+ INVALID_PATTERN: 'INVALID_PATTERN',
12
+ INVALID_INPUT: 'INVALID_INPUT',
13
+ PERMISSION_DENIED: 'PERMISSION_DENIED',
14
+ SYMLINK_NOT_ALLOWED: 'SYMLINK_NOT_ALLOWED',
15
+ VALIDATION_FAILED: 'VALIDATION_FAILED',
16
+ IO_ERROR: 'IO_ERROR',
17
+ UNKNOWN: 'UNKNOWN',
18
+ };
19
+ function build(code, message, opts = {}) {
20
+ return {
21
+ code,
22
+ message,
23
+ ...(opts.path !== undefined ? { path: opts.path } : {}),
24
+ ...(opts.suggestion !== undefined ? { suggestion: opts.suggestion } : {}),
25
+ ...(opts.details !== undefined ? { details: opts.details } : {}),
26
+ ...(opts.issues !== undefined ? { issues: opts.issues } : {}),
27
+ };
28
+ }
29
+ export const Problem = {
30
+ invalidInput: (msg, o) => build(ErrorCode.INVALID_INPUT, msg, o),
31
+ accessDenied: (msg, o) => build(ErrorCode.ACCESS_DENIED, msg, o),
32
+ timeout: (msg, o) => build(ErrorCode.TIMEOUT, msg, o),
33
+ cancelled: (msg, o) => build(ErrorCode.CANCELLED, msg, o),
34
+ ioError: (msg, o) => build(ErrorCode.IO_ERROR, msg, o),
35
+ unknown: (msg, o) => build(ErrorCode.UNKNOWN, msg, o),
36
+ fromUnknown(error, defaultCode, path) {
37
+ const problem = classify(error);
38
+ const shouldOverride = problem.code === ErrorCode.UNKNOWN || problem.code === ErrorCode.IO_ERROR;
39
+ const code = shouldOverride ? defaultCode : problem.code;
40
+ const baseSuggestion = problem.suggestion ?? resolveSuggestion({ code: problem.code, issues: problem.issues ?? [] });
41
+ const suggestion = (shouldOverride ? DEFAULT_SUGGESTIONS[code] : undefined) ?? baseSuggestion;
42
+ const resolvedPath = path ?? problem.path;
43
+ return build(code, problem.message, {
44
+ ...(resolvedPath !== undefined ? { path: resolvedPath } : {}),
45
+ ...(suggestion !== undefined ? { suggestion } : {}),
46
+ ...(problem.issues !== undefined && problem.issues.length > 0
47
+ ? { issues: problem.issues }
48
+ : {}),
49
+ });
50
+ },
51
+ toText(error, defaultCode) {
52
+ const resolved = Problem.fromUnknown(error, defaultCode);
53
+ return { code: resolved.code, text: formatDetailedError(resolved) };
54
+ },
55
+ toPerFileError(error, defaultCode = ErrorCode.UNKNOWN, path) {
56
+ const problem = Problem.fromUnknown(error, defaultCode, path);
57
+ return {
58
+ code: problem.code,
59
+ message: problem.message,
60
+ ...(problem.path !== undefined ? { path: problem.path } : {}),
61
+ ...(problem.suggestion !== undefined ? { suggestion: problem.suggestion } : {}),
62
+ };
63
+ },
64
+ };
65
+ const DEFAULT_SUGGESTIONS = {
66
+ [ErrorCode.ACCESS_DENIED]: 'Run list_roots to list allowed directories.',
67
+ [ErrorCode.NOT_FOUND]: 'Run list or find_files to verify the path.',
68
+ [ErrorCode.NOT_FILE]: 'Target is a directory, not a file.',
69
+ [ErrorCode.NOT_DIRECTORY]: 'Target is a file, not a directory.',
70
+ [ErrorCode.TOO_LARGE]: 'Use head/tail or line ranges to read partially.',
71
+ [ErrorCode.TIMEOUT]: 'Reduce scope, depth, or maxResults.',
72
+ [ErrorCode.INVALID_PATTERN]: 'Check syntax and escape special characters.',
73
+ [ErrorCode.PERMISSION_DENIED]: 'Check OS file permissions.',
74
+ [ErrorCode.SYMLINK_NOT_ALLOWED]: 'Symlink escapes allowed directories.',
75
+ };
76
+ function resolveSuggestion(p) {
77
+ for (const issue of p.issues ?? []) {
78
+ const fromRule = issue.params?.['suggestion'];
79
+ if (typeof fromRule === 'string')
80
+ return fromRule;
81
+ }
82
+ return DEFAULT_SUGGESTIONS[p.code];
83
+ }
84
+ export const ERRNO_MAP = {
85
+ ENOENT: ErrorCode.NOT_FOUND,
86
+ EACCES: ErrorCode.PERMISSION_DENIED,
87
+ EPERM: ErrorCode.PERMISSION_DENIED,
88
+ ENOTDIR: ErrorCode.NOT_DIRECTORY,
89
+ EISDIR: ErrorCode.NOT_FILE,
90
+ ELOOP: ErrorCode.SYMLINK_NOT_ALLOWED,
91
+ ENAMETOOLONG: ErrorCode.INVALID_INPUT,
92
+ ETIMEDOUT: ErrorCode.TIMEOUT,
93
+ EMFILE: ErrorCode.IO_ERROR,
94
+ ENFILE: ErrorCode.IO_ERROR,
95
+ EBUSY: ErrorCode.IO_ERROR,
96
+ ENOTEMPTY: ErrorCode.NOT_DIRECTORY,
97
+ EEXIST: ErrorCode.INVALID_INPUT,
98
+ EINVAL: ErrorCode.INVALID_INPUT,
99
+ };
100
+ const ERRNO_RE = /^E[A-Z]+$/;
101
+ // NOT_FOUND is in here (not just ENOENT) because a dangling symlink whose
102
+ // target sits inside an allowed root surfaces as an FsError NOT_FOUND. Skipping
103
+ // the entry is the point of a listing; rethrowing would fail the whole listing.
104
+ export const SKIPPABLE_FS_CODES = new Set([
105
+ ErrorCode.ACCESS_DENIED,
106
+ ErrorCode.NOT_FOUND,
107
+ // OS-level EACCES/EPERM on a symlink target during a listing is exactly as
108
+ // skippable as the other three codes.
109
+ ErrorCode.PERMISSION_DENIED,
110
+ ErrorCode.SYMLINK_NOT_ALLOWED,
111
+ ]);
112
+ export const SKIPPABLE_ERRNOS = new Set(['ENOENT', 'EACCES', 'ELOOP']);
113
+ function readErrnoCode(value) {
114
+ if (!(value instanceof Error))
115
+ return undefined;
116
+ const code = value.code;
117
+ if (typeof code !== 'string')
118
+ return undefined;
119
+ return code;
120
+ }
121
+ function isAbortSingle(value) {
122
+ if (!(value instanceof Error))
123
+ return false;
124
+ if (value.name === 'AbortError')
125
+ return true;
126
+ const code = readErrnoCode(value);
127
+ return code === 'ABORT_ERR';
128
+ }
129
+ function isTimeoutSingle(value) {
130
+ if (!(value instanceof Error))
131
+ return false;
132
+ if (value.name === 'TimeoutError')
133
+ return true;
134
+ return readErrnoCode(value) === 'ETIMEDOUT';
135
+ }
136
+ function readSignalSingle(value) {
137
+ if (isAbortSingle(value))
138
+ return { kind: 'abort' };
139
+ if (isTimeoutSingle(value))
140
+ return { kind: 'timeout' };
141
+ const code = readErrnoCode(value);
142
+ if (code !== undefined && ERRNO_RE.test(code)) {
143
+ const v = value;
144
+ return {
145
+ kind: 'errno',
146
+ errno: code,
147
+ ...(typeof v.syscall === 'string' ? { syscall: v.syscall } : {}),
148
+ ...(typeof v.path === 'string' ? { path: v.path } : {}),
149
+ };
150
+ }
151
+ return undefined;
152
+ }
153
+ function walkCauseChain(error) {
154
+ let current = error;
155
+ const visited = new Set();
156
+ let abortSeen = false;
157
+ let timeoutSeen = false;
158
+ let errnoSignal;
159
+ while (current !== undefined && current !== null && !visited.has(current)) {
160
+ const signal = readSignalSingle(current);
161
+ if (signal !== undefined) {
162
+ if (signal.kind === 'abort')
163
+ abortSeen = true;
164
+ else if (signal.kind === 'timeout')
165
+ timeoutSeen = true;
166
+ else if (signal.kind === 'errno' && errnoSignal === undefined) {
167
+ errnoSignal = signal;
168
+ }
169
+ }
170
+ visited.add(current);
171
+ current = current.cause;
172
+ }
173
+ if (abortSeen)
174
+ return { kind: 'abort' };
175
+ if (timeoutSeen)
176
+ return { kind: 'timeout' };
177
+ if (errnoSignal !== undefined)
178
+ return errnoSignal;
179
+ return { kind: 'unknown' };
180
+ }
181
+ function buildProblemFromSignal(signal, error) {
182
+ const message = formatUnknownErrorMessage(error);
183
+ switch (signal.kind) {
184
+ case 'abort':
185
+ return Problem.cancelled(message);
186
+ case 'timeout':
187
+ return Problem.timeout(message);
188
+ case 'errno': {
189
+ const code = ERRNO_MAP[signal.errno] ?? ErrorCode.IO_ERROR;
190
+ const details = {
191
+ errno: signal.errno,
192
+ ...(signal.syscall !== undefined ? { syscall: signal.syscall } : {}),
193
+ };
194
+ return build(code, message, {
195
+ ...(signal.path !== undefined ? { path: signal.path } : {}),
196
+ details,
197
+ });
198
+ }
199
+ case 'unknown':
200
+ return Problem.unknown(message);
201
+ default: {
202
+ const _exhaustive = signal;
203
+ return _exhaustive;
204
+ }
205
+ }
206
+ }
207
+ function toProblemIssue(issue) {
208
+ const base = {
209
+ path: issue.path,
210
+ code: issue.code,
211
+ message: issue.message,
212
+ };
213
+ const expected = issue.expected;
214
+ const received = issue.received;
215
+ const rawParams = issue.params;
216
+ const params = rawParams === undefined || rawParams === null
217
+ ? undefined
218
+ : typeof rawParams === 'object'
219
+ ? rawParams
220
+ : { value: rawParams };
221
+ return {
222
+ ...base,
223
+ ...(expected !== undefined ? { expected } : {}),
224
+ ...(received !== undefined ? { received } : {}),
225
+ ...(params !== undefined ? { params } : {}),
226
+ };
227
+ }
228
+ function zodErrorToProblem(err) {
229
+ const issues = err.issues.map(toProblemIssue);
230
+ const suggestion = resolveSuggestion({ code: ErrorCode.VALIDATION_FAILED, issues });
231
+ return build(ErrorCode.VALIDATION_FAILED, z.prettifyError(err), {
232
+ issues,
233
+ ...(suggestion !== undefined ? { suggestion } : {}),
234
+ });
235
+ }
236
+ export function isFsError(error) {
237
+ if (!(error instanceof Error) || error.name !== 'FsError')
238
+ return false;
239
+ if (!('problem' in error))
240
+ return false;
241
+ const p = error.problem;
242
+ if (p === null || typeof p !== 'object')
243
+ return false;
244
+ const c = p;
245
+ return typeof c['code'] === 'string' && typeof c['message'] === 'string';
246
+ }
247
+ /** FsError traces to a caller-supplied argument; anything else is server-side. */
248
+ export function fsErrorCode(error) {
249
+ return isFsError(error) ? ProtocolErrorCode.InvalidParams : ProtocolErrorCode.InternalError;
250
+ }
251
+ /**
252
+ * Structural discriminator for SDK error classes (`ProtocolError`, `SdkError`).
253
+ * Checks `name` + `code` properties rather than `instanceof` so discrimination
254
+ * survives cross-realm / multi-SDK-copy conditions where the prototype chain
255
+ * breaks. Mirrors the isFsError pattern.
256
+ */
257
+ export function hasErrorShape(error, name, code) {
258
+ if (!(error instanceof Error) || error.name !== name)
259
+ return false;
260
+ const c = error.code;
261
+ if (typeof c !== 'string' && typeof c !== 'number')
262
+ return false;
263
+ return code === undefined || c === code;
264
+ }
265
+ function classify(error) {
266
+ if (error === null || error === undefined) {
267
+ return Problem.unknown('Unknown error');
268
+ }
269
+ if (isFsError(error))
270
+ return error.problem;
271
+ if (error instanceof z.ZodError)
272
+ return zodErrorToProblem(error);
273
+ if (!(error instanceof Error)) {
274
+ return Problem.unknown(typeof error === 'string' ? error : '[non-Error thrown]');
275
+ }
276
+ const signal = walkCauseChain(error);
277
+ return buildProblemFromSignal(signal, error);
278
+ }
279
+ function isNativeError(error) {
280
+ return error instanceof Error;
281
+ }
282
+ export function isNodeError(error) {
283
+ if (!isNativeError(error))
284
+ return false;
285
+ if (!('code' in error))
286
+ return false;
287
+ const { code } = error;
288
+ return typeof code === 'string';
289
+ }
290
+ /** True when `error` is a Node errno error with code `ENOENT` (path not found). */
291
+ export function isNotFoundErrno(error) {
292
+ return isNodeError(error) && error.code === 'ENOENT';
293
+ }
294
+ function isAbortError(error) {
295
+ return classify(error).code === ErrorCode.CANCELLED;
296
+ }
297
+ export function rethrowIfAborted(error) {
298
+ if (isAbortError(error))
299
+ throw error;
300
+ }
301
+ export function formatUnknownErrorMessage(error) {
302
+ if (typeof error === 'string')
303
+ return error;
304
+ if (isNativeError(error))
305
+ return error.message;
306
+ try {
307
+ return JSON.stringify(error);
308
+ }
309
+ catch {
310
+ return `[non-serializable: ${Object.prototype.toString.call(error)}]`;
311
+ }
312
+ }
313
+ export function normalizeUnknownError(error) {
314
+ return isNativeError(error) ? error : new Error(formatUnknownErrorMessage(error));
315
+ }
316
+ function formatDetailedError(error) {
317
+ const lines = [`${error.code}: ${error.message}`];
318
+ if (error.path && !error.message.includes(error.path)) {
319
+ lines.push(error.path);
320
+ }
321
+ if (error.suggestion) {
322
+ lines.push(error.suggestion);
323
+ }
324
+ return lines.join('\n');
325
+ }
326
+ export class FsError extends Error {
327
+ problem;
328
+ constructor(code, message, path, details, cause) {
329
+ super(message, cause === undefined ? {} : { cause });
330
+ const suggestion = DEFAULT_SUGGESTIONS[code];
331
+ this.problem = {
332
+ code,
333
+ message,
334
+ ...(path !== undefined ? { path } : {}),
335
+ ...(details !== undefined ? { details: { extra: details } } : {}),
336
+ ...(suggestion !== undefined ? { suggestion } : {}),
337
+ };
338
+ this.name = 'FsError';
339
+ Object.setPrototypeOf(this, FsError.prototype);
340
+ }
341
+ get code() {
342
+ return this.problem.code;
343
+ }
344
+ get path() {
345
+ return this.problem.path;
346
+ }
347
+ get details() {
348
+ if (!this.problem.details)
349
+ return undefined;
350
+ const { extra, ...rest } = this.problem.details;
351
+ if (!extra)
352
+ return Object.keys(rest).length > 0 ? rest : undefined;
353
+ return { ...rest, ...extra };
354
+ }
355
+ }
356
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"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","sourcesContent":["import { ProtocolErrorCode } from '@modelcontextprotocol/server';\n\nimport * as z from 'zod/v4';\n\nexport const ErrorCode = {\n ACCESS_DENIED: 'ACCESS_DENIED',\n NOT_FOUND: 'NOT_FOUND',\n NOT_FILE: 'NOT_FILE',\n NOT_DIRECTORY: 'NOT_DIRECTORY',\n TOO_LARGE: 'TOO_LARGE',\n TIMEOUT: 'TIMEOUT',\n CANCELLED: 'CANCELLED',\n INVALID_PATTERN: 'INVALID_PATTERN',\n INVALID_INPUT: 'INVALID_INPUT',\n PERMISSION_DENIED: 'PERMISSION_DENIED',\n SYMLINK_NOT_ALLOWED: 'SYMLINK_NOT_ALLOWED',\n VALIDATION_FAILED: 'VALIDATION_FAILED',\n IO_ERROR: 'IO_ERROR',\n UNKNOWN: 'UNKNOWN',\n} as const;\n\nexport type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];\n\ninterface PerFileError {\n readonly code: ErrorCode;\n readonly message: string;\n readonly path?: string;\n readonly suggestion?: string;\n}\n\nexport interface Problem {\n readonly code: ErrorCode;\n readonly message: string;\n readonly path?: string;\n readonly issues?: readonly ProblemIssue[];\n readonly suggestion?: string;\n readonly details?: ProblemDetails;\n}\n\ninterface ProblemIssue {\n readonly path: readonly (string | number)[];\n readonly code: string;\n readonly message: string;\n readonly expected?: string;\n readonly received?: string;\n readonly params?: Readonly<Record<string, unknown>>;\n}\n\ninterface ProblemDetails {\n readonly errno?: string;\n readonly syscall?: string;\n readonly tool?: string;\n readonly extra?: Readonly<Record<string, unknown>>;\n}\n\ninterface ProblemFactoryOptions {\n path?: string;\n suggestion?: string;\n details?: ProblemDetails;\n issues?: readonly ProblemIssue[];\n}\n\nfunction build(code: ErrorCode, message: string, opts: ProblemFactoryOptions = {}): Problem {\n return {\n code,\n message,\n ...(opts.path !== undefined ? { path: opts.path } : {}),\n ...(opts.suggestion !== undefined ? { suggestion: opts.suggestion } : {}),\n ...(opts.details !== undefined ? { details: opts.details } : {}),\n ...(opts.issues !== undefined ? { issues: opts.issues } : {}),\n };\n}\n\nexport const Problem = {\n invalidInput: (msg: string, o?: ProblemFactoryOptions): Problem =>\n build(ErrorCode.INVALID_INPUT, msg, o),\n accessDenied: (msg: string, o?: ProblemFactoryOptions): Problem =>\n build(ErrorCode.ACCESS_DENIED, msg, o),\n timeout: (msg: string, o?: ProblemFactoryOptions): Problem => build(ErrorCode.TIMEOUT, msg, o),\n cancelled: (msg: string, o?: ProblemFactoryOptions): Problem =>\n build(ErrorCode.CANCELLED, msg, o),\n ioError: (msg: string, o?: ProblemFactoryOptions): Problem => build(ErrorCode.IO_ERROR, msg, o),\n unknown: (msg: string, o?: ProblemFactoryOptions): Problem => build(ErrorCode.UNKNOWN, msg, o),\n fromUnknown(error: unknown, defaultCode: ErrorCode, path?: string): Problem {\n const problem = classify(error);\n const shouldOverride =\n problem.code === ErrorCode.UNKNOWN || problem.code === ErrorCode.IO_ERROR;\n const code = shouldOverride ? defaultCode : problem.code;\n const baseSuggestion =\n problem.suggestion ?? resolveSuggestion({ code: problem.code, issues: problem.issues ?? [] });\n const suggestion = (shouldOverride ? DEFAULT_SUGGESTIONS[code] : undefined) ?? baseSuggestion;\n const resolvedPath = path ?? problem.path;\n return build(code, problem.message, {\n ...(resolvedPath !== undefined ? { path: resolvedPath } : {}),\n ...(suggestion !== undefined ? { suggestion } : {}),\n ...(problem.issues !== undefined && problem.issues.length > 0\n ? { issues: problem.issues }\n : {}),\n });\n },\n toText(error: unknown, defaultCode: ErrorCode): { code: ErrorCode; text: string } {\n const resolved = Problem.fromUnknown(error, defaultCode);\n return { code: resolved.code, text: formatDetailedError(resolved) };\n },\n toPerFileError(\n error: unknown,\n defaultCode: ErrorCode = ErrorCode.UNKNOWN,\n path?: string,\n ): PerFileError {\n const problem = Problem.fromUnknown(error, defaultCode, path);\n return {\n code: problem.code,\n message: problem.message,\n ...(problem.path !== undefined ? { path: problem.path } : {}),\n ...(problem.suggestion !== undefined ? { suggestion: problem.suggestion } : {}),\n };\n },\n} as const;\n\nconst DEFAULT_SUGGESTIONS: Readonly<Partial<Record<ErrorCode, string>>> = {\n [ErrorCode.ACCESS_DENIED]: 'Run list_roots to list allowed directories.',\n [ErrorCode.NOT_FOUND]: 'Run list or find_files to verify the path.',\n [ErrorCode.NOT_FILE]: 'Target is a directory, not a file.',\n [ErrorCode.NOT_DIRECTORY]: 'Target is a file, not a directory.',\n [ErrorCode.TOO_LARGE]: 'Use head/tail or line ranges to read partially.',\n [ErrorCode.TIMEOUT]: 'Reduce scope, depth, or maxResults.',\n [ErrorCode.INVALID_PATTERN]: 'Check syntax and escape special characters.',\n [ErrorCode.PERMISSION_DENIED]: 'Check OS file permissions.',\n [ErrorCode.SYMLINK_NOT_ALLOWED]: 'Symlink escapes allowed directories.',\n};\n\nfunction resolveSuggestion(p: Pick<Problem, 'code' | 'issues'>): string | undefined {\n for (const issue of p.issues ?? []) {\n const fromRule = issue.params?.['suggestion'];\n if (typeof fromRule === 'string') return fromRule;\n }\n return DEFAULT_SUGGESTIONS[p.code];\n}\n\nexport const ERRNO_MAP: Readonly<Record<string, ErrorCode>> = {\n ENOENT: ErrorCode.NOT_FOUND,\n EACCES: ErrorCode.PERMISSION_DENIED,\n EPERM: ErrorCode.PERMISSION_DENIED,\n ENOTDIR: ErrorCode.NOT_DIRECTORY,\n EISDIR: ErrorCode.NOT_FILE,\n ELOOP: ErrorCode.SYMLINK_NOT_ALLOWED,\n ENAMETOOLONG: ErrorCode.INVALID_INPUT,\n ETIMEDOUT: ErrorCode.TIMEOUT,\n EMFILE: ErrorCode.IO_ERROR,\n ENFILE: ErrorCode.IO_ERROR,\n EBUSY: ErrorCode.IO_ERROR,\n ENOTEMPTY: ErrorCode.NOT_DIRECTORY,\n EEXIST: ErrorCode.INVALID_INPUT,\n EINVAL: ErrorCode.INVALID_INPUT,\n};\n\nconst ERRNO_RE = /^E[A-Z]+$/;\n\n// NOT_FOUND is in here (not just ENOENT) because a dangling symlink whose\n// target sits inside an allowed root surfaces as an FsError NOT_FOUND. Skipping\n// the entry is the point of a listing; rethrowing would fail the whole listing.\nexport const SKIPPABLE_FS_CODES: ReadonlySet<ErrorCode> = new Set([\n ErrorCode.ACCESS_DENIED,\n ErrorCode.NOT_FOUND,\n // OS-level EACCES/EPERM on a symlink target during a listing is exactly as\n // skippable as the other three codes.\n ErrorCode.PERMISSION_DENIED,\n ErrorCode.SYMLINK_NOT_ALLOWED,\n]);\n\nexport const SKIPPABLE_ERRNOS: ReadonlySet<string> = new Set(['ENOENT', 'EACCES', 'ELOOP']);\n\ntype ClassificationSignal =\n | { kind: 'abort' }\n | { kind: 'timeout' }\n | { kind: 'errno'; errno: string; syscall?: string; path?: string }\n | { kind: 'unknown' };\n\nfunction readErrnoCode(value: unknown): string | undefined {\n if (!(value instanceof Error)) return undefined;\n const code = (value as { code?: unknown }).code;\n if (typeof code !== 'string') return undefined;\n return code;\n}\n\nfunction isAbortSingle(value: unknown): boolean {\n if (!(value instanceof Error)) return false;\n if (value.name === 'AbortError') return true;\n const code = readErrnoCode(value);\n return code === 'ABORT_ERR';\n}\n\nfunction isTimeoutSingle(value: unknown): boolean {\n if (!(value instanceof Error)) return false;\n if (value.name === 'TimeoutError') return true;\n return readErrnoCode(value) === 'ETIMEDOUT';\n}\n\nfunction readSignalSingle(value: unknown): ClassificationSignal | undefined {\n if (isAbortSingle(value)) return { kind: 'abort' };\n if (isTimeoutSingle(value)) return { kind: 'timeout' };\n const code = readErrnoCode(value);\n if (code !== undefined && ERRNO_RE.test(code)) {\n const v = value as NodeJS.ErrnoException;\n return {\n kind: 'errno',\n errno: code,\n ...(typeof v.syscall === 'string' ? { syscall: v.syscall } : {}),\n ...(typeof v.path === 'string' ? { path: v.path } : {}),\n };\n }\n return undefined;\n}\n\nfunction walkCauseChain(error: unknown): ClassificationSignal {\n let current: unknown = error;\n const visited = new Set<unknown>();\n let abortSeen = false;\n let timeoutSeen = false;\n let errnoSignal: ClassificationSignal | undefined;\n\n while (current !== undefined && current !== null && !visited.has(current)) {\n const signal = readSignalSingle(current);\n if (signal !== undefined) {\n if (signal.kind === 'abort') abortSeen = true;\n else if (signal.kind === 'timeout') timeoutSeen = true;\n else if (signal.kind === 'errno' && errnoSignal === undefined) {\n errnoSignal = signal;\n }\n }\n visited.add(current);\n current = (current as { cause?: unknown }).cause;\n }\n\n if (abortSeen) return { kind: 'abort' };\n if (timeoutSeen) return { kind: 'timeout' };\n if (errnoSignal !== undefined) return errnoSignal;\n return { kind: 'unknown' };\n}\n\nfunction buildProblemFromSignal(signal: ClassificationSignal, error: unknown): Problem {\n const message = formatUnknownErrorMessage(error);\n switch (signal.kind) {\n case 'abort':\n return Problem.cancelled(message);\n case 'timeout':\n return Problem.timeout(message);\n case 'errno': {\n const code = ERRNO_MAP[signal.errno] ?? ErrorCode.IO_ERROR;\n const details: ProblemDetails = {\n errno: signal.errno,\n ...(signal.syscall !== undefined ? { syscall: signal.syscall } : {}),\n };\n return build(code, message, {\n ...(signal.path !== undefined ? { path: signal.path } : {}),\n details,\n });\n }\n case 'unknown':\n return Problem.unknown(message);\n default: {\n const _exhaustive: never = signal;\n return _exhaustive;\n }\n }\n}\n\nfunction toProblemIssue(issue: z.core.$ZodIssue): ProblemIssue {\n const base: ProblemIssue = {\n path: issue.path as readonly (string | number)[],\n code: issue.code,\n message: issue.message,\n };\n const expected = (issue as { expected?: string }).expected;\n const received = (issue as { received?: string }).received;\n const rawParams = (issue as { params?: unknown }).params;\n const params =\n rawParams === undefined || rawParams === null\n ? undefined\n : typeof rawParams === 'object'\n ? (rawParams as Record<string, unknown>)\n : { value: rawParams };\n return {\n ...base,\n ...(expected !== undefined ? { expected } : {}),\n ...(received !== undefined ? { received } : {}),\n ...(params !== undefined ? { params } : {}),\n };\n}\n\nfunction zodErrorToProblem(err: z.ZodError): Problem {\n const issues = err.issues.map(toProblemIssue);\n const suggestion = resolveSuggestion({ code: ErrorCode.VALIDATION_FAILED, issues });\n return build(ErrorCode.VALIDATION_FAILED, z.prettifyError(err), {\n issues,\n ...(suggestion !== undefined ? { suggestion } : {}),\n });\n}\n\nexport function isFsError(error: unknown): error is FsError {\n if (!(error instanceof Error) || error.name !== 'FsError') return false;\n if (!('problem' in error)) return false;\n const p = (error as { problem?: unknown }).problem;\n if (p === null || typeof p !== 'object') return false;\n const c = p as Record<string, unknown>;\n return typeof c['code'] === 'string' && typeof c['message'] === 'string';\n}\n\n/** FsError traces to a caller-supplied argument; anything else is server-side. */\nexport function fsErrorCode(error: unknown): ProtocolErrorCode {\n return isFsError(error) ? ProtocolErrorCode.InvalidParams : ProtocolErrorCode.InternalError;\n}\n\n/**\n * Structural discriminator for SDK error classes (`ProtocolError`, `SdkError`).\n * Checks `name` + `code` properties rather than `instanceof` so discrimination\n * survives cross-realm / multi-SDK-copy conditions where the prototype chain\n * breaks. Mirrors the isFsError pattern.\n */\nexport function hasErrorShape(\n error: unknown,\n name: string,\n code?: string | number,\n): error is Error & { code: string | number } {\n if (!(error instanceof Error) || error.name !== name) return false;\n const c = (error as { code?: unknown }).code;\n if (typeof c !== 'string' && typeof c !== 'number') return false;\n return code === undefined || c === code;\n}\n\nfunction classify(error: unknown): Problem {\n if (error === null || error === undefined) {\n return Problem.unknown('Unknown error');\n }\n if (isFsError(error)) return error.problem;\n if (error instanceof z.ZodError) return zodErrorToProblem(error);\n if (!(error instanceof Error)) {\n return Problem.unknown(typeof error === 'string' ? error : '[non-Error thrown]');\n }\n const signal = walkCauseChain(error);\n return buildProblemFromSignal(signal, error);\n}\n\nfunction isNativeError(error: unknown): error is Error {\n return error instanceof Error;\n}\n\nexport function isNodeError(error: unknown): error is NodeJS.ErrnoException {\n if (!isNativeError(error)) return false;\n if (!('code' in error)) return false;\n const { code } = error as { code?: unknown };\n return typeof code === 'string';\n}\n\n/** True when `error` is a Node errno error with code `ENOENT` (path not found). */\nexport function isNotFoundErrno(error: unknown): error is NodeJS.ErrnoException {\n return isNodeError(error) && error.code === 'ENOENT';\n}\n\nfunction isAbortError(error: unknown): boolean {\n return classify(error).code === ErrorCode.CANCELLED;\n}\n\nexport function rethrowIfAborted(error: unknown): void {\n if (isAbortError(error)) throw error;\n}\n\nexport function formatUnknownErrorMessage(error: unknown): string {\n if (typeof error === 'string') return error;\n if (isNativeError(error)) return error.message;\n try {\n return JSON.stringify(error);\n } catch {\n return `[non-serializable: ${Object.prototype.toString.call(error)}]`;\n }\n}\n\nexport function normalizeUnknownError(error: unknown): Error {\n return isNativeError(error) ? error : new Error(formatUnknownErrorMessage(error));\n}\n\nfunction formatDetailedError(\n error: Pick<Problem, 'code' | 'message' | 'path' | 'suggestion'>,\n): string {\n const lines: string[] = [`${error.code}: ${error.message}`];\n if (error.path && !error.message.includes(error.path)) {\n lines.push(error.path);\n }\n if (error.suggestion) {\n lines.push(error.suggestion);\n }\n return lines.join('\\n');\n}\n\nexport class FsError extends Error {\n readonly problem: Problem;\n\n constructor(\n code: ErrorCode,\n message: string,\n path?: string,\n details?: Record<string, unknown>,\n cause?: unknown,\n ) {\n super(message, cause === undefined ? {} : { cause });\n const suggestion = DEFAULT_SUGGESTIONS[code];\n this.problem = {\n code,\n message,\n ...(path !== undefined ? { path } : {}),\n ...(details !== undefined ? { details: { extra: details } } : {}),\n ...(suggestion !== undefined ? { suggestion } : {}),\n };\n this.name = 'FsError';\n Object.setPrototypeOf(this, FsError.prototype);\n }\n\n get code(): ErrorCode {\n return this.problem.code;\n }\n\n get path(): string | undefined {\n return this.problem.path;\n }\n\n get details(): Record<string, unknown> | undefined {\n if (!this.problem.details) return undefined;\n const { extra, ...rest } = this.problem.details;\n if (!extra) return Object.keys(rest).length > 0 ? rest : undefined;\n return { ...rest, ...extra };\n }\n}\n"]}
@@ -0,0 +1,24 @@
1
+ import type { ContentBlock } from '@modelcontextprotocol/server';
2
+ export declare const FILESYSTEM_FILE_URI_TEMPLATE = "filesystem-mcp://file/{+path}";
3
+ /**
4
+ * The `{+path}` template-variable form of a path — what `completion/complete`
5
+ * must return, since a client expands a suggestion into the template verbatim.
6
+ * Unescaped, a '#' or '?' in a filename truncates the URI into a fragment or
7
+ * query (silently naming a different path) and a '%' makes the decode throw.
8
+ * Separators are restored so the value still reads as a path.
9
+ */
10
+ export declare function encodeFileUriPath(validPath: string): string;
11
+ /** Inverse of {@link encodeFileUriPath}; `undefined` on invalid percent-encoding. */
12
+ export declare function decodeFileUriPath(encoded: string): string | undefined;
13
+ export declare function buildFileResourceUri(validPath: string): string;
14
+ /**
15
+ * The link block for a URI already built by `buildFileResourceUri`. Callers that
16
+ * hold the URI must use this rather than rebuilding from a path: a path that
17
+ * differs only in case (the drive letter, on Windows) yields a *different* URI
18
+ * string, and watchers key on that string — a link and a `resourceUri` that
19
+ * disagree hand the client two subscriptions for one file.
20
+ */
21
+ export declare function buildFileResourceLinkFor(uri: string, name: string, mimeType: string, size: number, annotations?: Record<string, unknown>): ContentBlock;
22
+ export declare function buildFileResourceLink(validPath: string, mimeType: string, size: number, annotations?: Record<string, unknown>): ContentBlock;
23
+ export declare function extractPath(uri: string): string | undefined;
24
+ //# sourceMappingURL=file-uri.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-uri.d.ts","sourceRoot":"","sources":["../../src/core/file-uri.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAOjE,eAAO,MAAM,4BAA4B,kCAAkC,CAAC;AAE5E;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAG3D;AAED,qFAAqF;AACrF,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAMrE;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,WAAW,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAuC,GACzE,YAAY,CAEd;AAED,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,WAAW,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAuC,GACzE,YAAY,CAQd;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQ3D"}
@@ -0,0 +1,52 @@
1
+ import { basename } from 'node:path';
2
+ // Single owner of the `filesystem-mcp://file/` URI scheme: the template string,
3
+ // the path→URI encoder, and the URI→path decoder.
4
+ export const FILESYSTEM_FILE_URI_TEMPLATE = 'filesystem-mcp://file/{+path}';
5
+ /**
6
+ * The `{+path}` template-variable form of a path — what `completion/complete`
7
+ * must return, since a client expands a suggestion into the template verbatim.
8
+ * Unescaped, a '#' or '?' in a filename truncates the URI into a fragment or
9
+ * query (silently naming a different path) and a '%' makes the decode throw.
10
+ * Separators are restored so the value still reads as a path.
11
+ */
12
+ export function encodeFileUriPath(validPath) {
13
+ const posix = validPath.replace(/\\/g, '/');
14
+ return encodeURIComponent(posix).replace(/%2F/gi, '/');
15
+ }
16
+ /** Inverse of {@link encodeFileUriPath}; `undefined` on invalid percent-encoding. */
17
+ export function decodeFileUriPath(encoded) {
18
+ try {
19
+ return decodeURIComponent(encoded);
20
+ }
21
+ catch {
22
+ return undefined;
23
+ }
24
+ }
25
+ export function buildFileResourceUri(validPath) {
26
+ return `filesystem-mcp://file/${encodeFileUriPath(validPath)}`;
27
+ }
28
+ /**
29
+ * The link block for a URI already built by `buildFileResourceUri`. Callers that
30
+ * hold the URI must use this rather than rebuilding from a path: a path that
31
+ * differs only in case (the drive letter, on Windows) yields a *different* URI
32
+ * string, and watchers key on that string — a link and a `resourceUri` that
33
+ * disagree hand the client two subscriptions for one file.
34
+ */
35
+ export function buildFileResourceLinkFor(uri, name, mimeType, size, annotations = { audience: ['user', 'assistant'] }) {
36
+ return { type: 'resource_link', uri, name, mimeType, size, annotations };
37
+ }
38
+ export function buildFileResourceLink(validPath, mimeType, size, annotations = { audience: ['user', 'assistant'] }) {
39
+ return buildFileResourceLinkFor(buildFileResourceUri(validPath), basename(validPath), mimeType, size, annotations);
40
+ }
41
+ export function extractPath(uri) {
42
+ try {
43
+ const url = new URL(uri);
44
+ if (url.protocol !== 'filesystem-mcp:' || url.host !== 'file')
45
+ return undefined;
46
+ return decodeFileUriPath(url.pathname.slice(1));
47
+ }
48
+ catch {
49
+ return undefined;
50
+ }
51
+ }
52
+ //# sourceMappingURL=file-uri.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-uri.js","sourceRoot":"","sources":["../../src/core/file-uri.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,gFAAgF;AAChF,kDAAkD;AAElD,MAAM,CAAC,MAAM,4BAA4B,GAAG,+BAA+B,CAAC;AAE5E;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,SAAiB;IACjD,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC5C,OAAO,kBAAkB,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;AACzD,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,IAAI,CAAC;QACH,OAAO,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,SAAiB;IACpD,OAAO,yBAAyB,iBAAiB,CAAC,SAAS,CAAC,EAAE,CAAC;AACjE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,wBAAwB,CACtC,GAAW,EACX,IAAY,EACZ,QAAgB,EAChB,IAAY,EACZ,cAAuC,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE;IAE1E,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,SAAiB,EACjB,QAAgB,EAChB,IAAY,EACZ,cAAuC,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE;IAE1E,OAAO,wBAAwB,CAC7B,oBAAoB,CAAC,SAAS,CAAC,EAC/B,QAAQ,CAAC,SAAS,CAAC,EACnB,QAAQ,EACR,IAAI,EACJ,WAAW,CACZ,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACzB,IAAI,GAAG,CAAC,QAAQ,KAAK,iBAAiB,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM;YAAE,OAAO,SAAS,CAAC;QAChF,OAAO,iBAAiB,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC","sourcesContent":["import type { ContentBlock } from '@modelcontextprotocol/server';\n\nimport { basename } from 'node:path';\n\n// Single owner of the `filesystem-mcp://file/` URI scheme: the template string,\n// the path→URI encoder, and the URI→path decoder.\n\nexport const FILESYSTEM_FILE_URI_TEMPLATE = 'filesystem-mcp://file/{+path}';\n\n/**\n * The `{+path}` template-variable form of a path — what `completion/complete`\n * must return, since a client expands a suggestion into the template verbatim.\n * Unescaped, a '#' or '?' in a filename truncates the URI into a fragment or\n * query (silently naming a different path) and a '%' makes the decode throw.\n * Separators are restored so the value still reads as a path.\n */\nexport function encodeFileUriPath(validPath: string): string {\n const posix = validPath.replace(/\\\\/g, '/');\n return encodeURIComponent(posix).replace(/%2F/gi, '/');\n}\n\n/** Inverse of {@link encodeFileUriPath}; `undefined` on invalid percent-encoding. */\nexport function decodeFileUriPath(encoded: string): string | undefined {\n try {\n return decodeURIComponent(encoded);\n } catch {\n return undefined;\n }\n}\n\nexport function buildFileResourceUri(validPath: string): string {\n return `filesystem-mcp://file/${encodeFileUriPath(validPath)}`;\n}\n\n/**\n * The link block for a URI already built by `buildFileResourceUri`. Callers that\n * hold the URI must use this rather than rebuilding from a path: a path that\n * differs only in case (the drive letter, on Windows) yields a *different* URI\n * string, and watchers key on that string — a link and a `resourceUri` that\n * disagree hand the client two subscriptions for one file.\n */\nexport function buildFileResourceLinkFor(\n uri: string,\n name: string,\n mimeType: string,\n size: number,\n annotations: Record<string, unknown> = { audience: ['user', 'assistant'] },\n): ContentBlock {\n return { type: 'resource_link', uri, name, mimeType, size, annotations };\n}\n\nexport function buildFileResourceLink(\n validPath: string,\n mimeType: string,\n size: number,\n annotations: Record<string, unknown> = { audience: ['user', 'assistant'] },\n): ContentBlock {\n return buildFileResourceLinkFor(\n buildFileResourceUri(validPath),\n basename(validPath),\n mimeType,\n size,\n annotations,\n );\n}\n\nexport function extractPath(uri: string): string | undefined {\n try {\n const url = new URL(uri);\n if (url.protocol !== 'filesystem-mcp:' || url.host !== 'file') return undefined;\n return decodeFileUriPath(url.pathname.slice(1));\n } catch {\n return undefined;\n }\n}\n"]}
@@ -0,0 +1,38 @@
1
+ export interface ProgressCtx {
2
+ label: string;
3
+ subject?: string;
4
+ scope?: string;
5
+ current?: number;
6
+ total?: number;
7
+ detail?: string;
8
+ error?: string;
9
+ }
10
+ export type Phase = 'start' | 'tick' | 'done' | 'fail';
11
+ export declare function plainMessage(phase: Phase, ctx: ProgressCtx): string;
12
+ export declare function formatBytes(bytes: number): string;
13
+ export declare function formatCount(count: number, singular: string, plural?: string): string;
14
+ /**
15
+ * Short label for a path in summary text. `basename` returns '' for a root
16
+ * (`C:\`, `/`) and for a trailing-slash path, which rendered as a bare
17
+ * separator in the per-path summaries, so fall back to the full path.
18
+ */
19
+ export declare function pathLabel(path: string): string;
20
+ /**
21
+ * Join a per-path summary roster, capped. A 1000-path delete would otherwise
22
+ * name every entry in the text block that `structuredContent` already carries
23
+ * in full.
24
+ */
25
+ export declare function joinRoster(items: readonly string[], separator?: string): string;
26
+ export declare function truncateProgressPattern(pattern: string, maxLength?: number): string;
27
+ export declare function padEndVisible(s: string, width: number): string;
28
+ export declare const cliFmt: {
29
+ bold: (t: string) => string;
30
+ dim: (t: string) => string;
31
+ cyan: (t: string) => string;
32
+ yellow: (t: string) => string;
33
+ flag: (t: string) => string;
34
+ placeholder: (t: string) => string;
35
+ section: (t: string) => string;
36
+ bool: (v: boolean) => string;
37
+ };
38
+ //# sourceMappingURL=fmt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fmt.d.ts","sourceRoot":"","sources":["../../src/core/fmt.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAuCvD,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,WAAW,GAAG,MAAM,CAGnE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAcjD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAiB,GAAG,MAAM,CAE5F;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAKD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,SAAQ,GAAG,MAAM,CAI9E;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,SAAK,GAAG,MAAM,CAE/E;AAUD,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAG9D;AASD,eAAO,MAAM,MAAM;cACP,MAAM;aACP,MAAM;cACL,MAAM;gBACJ,MAAM;cACR,MAAM;qBACC,MAAM;iBACV,MAAM;cACT,OAAO;CAClB,CAAC"}
@@ -0,0 +1,109 @@
1
+ import { basename } from 'node:path';
2
+ import { stripVTControlCharacters, styleText } from 'node:util';
3
+ import { GIB, KIB, MIB } from './util.js';
4
+ function buildBody(ctx, phase) {
5
+ const items = [];
6
+ if (ctx.subject) {
7
+ items.push(ctx.subject);
8
+ }
9
+ switch (phase) {
10
+ case 'start':
11
+ if (ctx.scope) {
12
+ items.push(ctx.scope);
13
+ }
14
+ break;
15
+ case 'tick':
16
+ if (ctx.current !== undefined && ctx.total !== undefined) {
17
+ items.push(`${ctx.current}/${ctx.total}`);
18
+ }
19
+ else if (ctx.current !== undefined) {
20
+ items.push(String(ctx.current));
21
+ }
22
+ break;
23
+ case 'done':
24
+ if (ctx.scope) {
25
+ items.push(ctx.scope);
26
+ }
27
+ if (ctx.detail) {
28
+ items.push(ctx.detail);
29
+ }
30
+ break;
31
+ case 'fail':
32
+ if (ctx.error) {
33
+ items.push(ctx.error);
34
+ }
35
+ break;
36
+ }
37
+ return items.join(' · ');
38
+ }
39
+ export function plainMessage(phase, ctx) {
40
+ const body = buildBody(ctx, phase);
41
+ return body ? `${ctx.label}: ${body}` : `${ctx.label}:`;
42
+ }
43
+ export function formatBytes(bytes) {
44
+ if (!Number.isFinite(bytes) || bytes < 0) {
45
+ return '0 B';
46
+ }
47
+ if (bytes < KIB) {
48
+ return `${bytes} B`;
49
+ }
50
+ if (bytes < MIB) {
51
+ return `${(bytes / KIB).toFixed(1)} KB`;
52
+ }
53
+ if (bytes < GIB) {
54
+ return `${(bytes / MIB).toFixed(1)} MB`;
55
+ }
56
+ return `${(bytes / GIB).toFixed(1)} GB`;
57
+ }
58
+ export function formatCount(count, singular, plural = `${singular}s`) {
59
+ return `${String(count)} ${count === 1 ? singular : plural}`;
60
+ }
61
+ /**
62
+ * Short label for a path in summary text. `basename` returns '' for a root
63
+ * (`C:\`, `/`) and for a trailing-slash path, which rendered as a bare
64
+ * separator in the per-path summaries, so fall back to the full path.
65
+ */
66
+ export function pathLabel(path) {
67
+ return basename(path) || path;
68
+ }
69
+ /** Names past this point are noise in a summary line; structuredContent holds them all. */
70
+ const MAX_ROSTER_ITEMS = 20;
71
+ /**
72
+ * Join a per-path summary roster, capped. A 1000-path delete would otherwise
73
+ * name every entry in the text block that `structuredContent` already carries
74
+ * in full.
75
+ */
76
+ export function joinRoster(items, separator = ' · ') {
77
+ if (items.length <= MAX_ROSTER_ITEMS)
78
+ return items.join(separator);
79
+ const shown = items.slice(0, MAX_ROSTER_ITEMS).join(separator);
80
+ return `${shown}${separator}+${String(items.length - MAX_ROSTER_ITEMS)} more`;
81
+ }
82
+ export function truncateProgressPattern(pattern, maxLength = 40) {
83
+ return pattern.length <= maxLength ? pattern : `${pattern.slice(0, maxLength)}…`;
84
+ }
85
+ // ---------------------------------------------------------------------------
86
+ // CLI color helpers
87
+ // ---------------------------------------------------------------------------
88
+ function isColorEnabled(stream = process.stdout) {
89
+ return stream.isTTY === true && !process.env['NO_COLOR'];
90
+ }
91
+ export function padEndVisible(s, width) {
92
+ const visible = stripVTControlCharacters(s).length;
93
+ return visible >= width ? s : s + ' '.repeat(width - visible);
94
+ }
95
+ /** Same palette as above, but only when the target stream wants color. */
96
+ function tint(format, text, stream) {
97
+ return isColorEnabled(stream) ? styleText(format, text) : text;
98
+ }
99
+ export const cliFmt = {
100
+ bold: (t) => tint('bold', t),
101
+ dim: (t) => tint('dim', t),
102
+ cyan: (t) => tint('cyan', t),
103
+ yellow: (t) => tint('yellow', t),
104
+ flag: (t) => tint('green', t),
105
+ placeholder: (t) => tint('yellow', t),
106
+ section: (t) => tint(['cyan', 'bold'], t),
107
+ bool: (v) => (v ? tint('green', 'true') : tint('red', 'false')),
108
+ };
109
+ //# sourceMappingURL=fmt.js.map