@j0hanz/filesystem-context-mcp 1.1.0 → 1.2.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 (285) hide show
  1. package/README.md +106 -29
  2. package/dist/__tests__/lib/errors.test.js +3 -23
  3. package/dist/__tests__/lib/errors.test.js.map +1 -1
  4. package/dist/__tests__/lib/file-operations.test.js +34 -0
  5. package/dist/__tests__/lib/file-operations.test.js.map +1 -1
  6. package/dist/__tests__/lib/path-validation.test.js +8 -0
  7. package/dist/__tests__/lib/path-validation.test.js.map +1 -1
  8. package/dist/__tests__/schemas/validators.test.js +101 -122
  9. package/dist/__tests__/schemas/validators.test.js.map +1 -1
  10. package/dist/__tests__/security/filesystem-boundary.test.js +1 -1
  11. package/dist/__tests__/security/filesystem-boundary.test.js.map +1 -1
  12. package/dist/config/types.d.ts +1 -85
  13. package/dist/config/types.d.ts.map +1 -1
  14. package/dist/config/types.js +0 -2
  15. package/dist/config/types.js.map +1 -1
  16. package/dist/index.js +3 -3
  17. package/dist/index.js.map +1 -1
  18. package/dist/instructions.md +1 -2
  19. package/dist/lib/constants.d.ts +3 -1
  20. package/dist/lib/constants.d.ts.map +1 -1
  21. package/dist/lib/constants.js +66 -258
  22. package/dist/lib/constants.js.map +1 -1
  23. package/dist/lib/errors.d.ts +25 -3
  24. package/dist/lib/errors.d.ts.map +1 -1
  25. package/dist/lib/errors.js +4 -94
  26. package/dist/lib/errors.js.map +1 -1
  27. package/dist/lib/file-operations/analyze-directory.d.ts +8 -0
  28. package/dist/lib/file-operations/analyze-directory.d.ts.map +1 -0
  29. package/dist/lib/file-operations/analyze-directory.js +117 -0
  30. package/dist/lib/file-operations/analyze-directory.js.map +1 -0
  31. package/dist/lib/file-operations/directory-items.d.ts +20 -0
  32. package/dist/lib/file-operations/directory-items.d.ts.map +1 -0
  33. package/dist/lib/file-operations/directory-items.js +85 -0
  34. package/dist/lib/file-operations/directory-items.js.map +1 -0
  35. package/dist/lib/file-operations/directory-iteration.d.ts +17 -0
  36. package/dist/lib/file-operations/directory-iteration.d.ts.map +1 -0
  37. package/dist/lib/file-operations/directory-iteration.js +55 -0
  38. package/dist/lib/file-operations/directory-iteration.js.map +1 -0
  39. package/dist/lib/file-operations/directory-tree.d.ts +9 -0
  40. package/dist/lib/file-operations/directory-tree.d.ts.map +1 -0
  41. package/dist/lib/file-operations/directory-tree.js +175 -0
  42. package/dist/lib/file-operations/directory-tree.js.map +1 -0
  43. package/dist/lib/file-operations/file-info.d.ts +3 -0
  44. package/dist/lib/file-operations/file-info.d.ts.map +1 -0
  45. package/dist/lib/file-operations/file-info.js +56 -0
  46. package/dist/lib/file-operations/file-info.js.map +1 -0
  47. package/dist/lib/file-operations/list-directory.d.ts +10 -0
  48. package/dist/lib/file-operations/list-directory.d.ts.map +1 -0
  49. package/dist/lib/file-operations/list-directory.js +189 -0
  50. package/dist/lib/file-operations/list-directory.js.map +1 -0
  51. package/dist/lib/file-operations/read-media-file.d.ts +5 -0
  52. package/dist/lib/file-operations/read-media-file.d.ts.map +1 -0
  53. package/dist/lib/file-operations/read-media-file.js +31 -0
  54. package/dist/lib/file-operations/read-media-file.js.map +1 -0
  55. package/dist/lib/file-operations/read-multiple-files.d.ts +16 -0
  56. package/dist/lib/file-operations/read-multiple-files.d.ts.map +1 -0
  57. package/dist/lib/file-operations/read-multiple-files.js +98 -0
  58. package/dist/lib/file-operations/read-multiple-files.js.map +1 -0
  59. package/dist/lib/file-operations/search-content.d.ts +16 -0
  60. package/dist/lib/file-operations/search-content.d.ts.map +1 -0
  61. package/dist/lib/file-operations/search-content.js +431 -0
  62. package/dist/lib/file-operations/search-content.js.map +1 -0
  63. package/dist/lib/file-operations/search-files.d.ts +9 -0
  64. package/dist/lib/file-operations/search-files.d.ts.map +1 -0
  65. package/dist/lib/file-operations/search-files.js +139 -0
  66. package/dist/lib/file-operations/search-files.js.map +1 -0
  67. package/dist/lib/file-operations/sorting.d.ts +12 -0
  68. package/dist/lib/file-operations/sorting.d.ts.map +1 -0
  69. package/dist/lib/file-operations/sorting.js +24 -0
  70. package/dist/lib/file-operations/sorting.js.map +1 -0
  71. package/dist/lib/file-operations.d.ts +9 -57
  72. package/dist/lib/file-operations.d.ts.map +1 -1
  73. package/dist/lib/file-operations.js +9 -773
  74. package/dist/lib/file-operations.js.map +1 -1
  75. package/dist/lib/fs-helpers/binary-detect.d.ts +3 -0
  76. package/dist/lib/fs-helpers/binary-detect.d.ts.map +1 -0
  77. package/dist/lib/fs-helpers/binary-detect.js +54 -0
  78. package/dist/lib/fs-helpers/binary-detect.js.map +1 -0
  79. package/dist/lib/fs-helpers/concurrency.d.ts +11 -0
  80. package/dist/lib/fs-helpers/concurrency.d.ts.map +1 -0
  81. package/dist/lib/fs-helpers/concurrency.js +95 -0
  82. package/dist/lib/fs-helpers/concurrency.js.map +1 -0
  83. package/dist/lib/fs-helpers/fs-utils.d.ts +5 -0
  84. package/dist/lib/fs-helpers/fs-utils.d.ts.map +1 -0
  85. package/dist/lib/fs-helpers/fs-utils.js +13 -0
  86. package/dist/lib/fs-helpers/fs-utils.js.map +1 -0
  87. package/dist/lib/fs-helpers/readers/head-file.d.ts +2 -0
  88. package/dist/lib/fs-helpers/readers/head-file.d.ts.map +1 -0
  89. package/dist/lib/fs-helpers/readers/head-file.js +73 -0
  90. package/dist/lib/fs-helpers/readers/head-file.js.map +1 -0
  91. package/dist/lib/fs-helpers/readers/line-range.d.ts +7 -0
  92. package/dist/lib/fs-helpers/readers/line-range.d.ts.map +1 -0
  93. package/dist/lib/fs-helpers/readers/line-range.js +46 -0
  94. package/dist/lib/fs-helpers/readers/line-range.js.map +1 -0
  95. package/dist/lib/fs-helpers/readers/read-file.d.ts +16 -0
  96. package/dist/lib/fs-helpers/readers/read-file.d.ts.map +1 -0
  97. package/dist/lib/fs-helpers/readers/read-file.js +87 -0
  98. package/dist/lib/fs-helpers/readers/read-file.js.map +1 -0
  99. package/dist/lib/fs-helpers/readers/tail-file.d.ts +2 -0
  100. package/dist/lib/fs-helpers/readers/tail-file.d.ts.map +1 -0
  101. package/dist/lib/fs-helpers/readers/tail-file.js +98 -0
  102. package/dist/lib/fs-helpers/readers/tail-file.js.map +1 -0
  103. package/dist/lib/fs-helpers/readers/utf8.d.ts +3 -0
  104. package/dist/lib/fs-helpers/readers/utf8.d.ts.map +1 -0
  105. package/dist/lib/fs-helpers/readers/utf8.js +22 -0
  106. package/dist/lib/fs-helpers/readers/utf8.js.map +1 -0
  107. package/dist/lib/fs-helpers/readers.d.ts +4 -0
  108. package/dist/lib/fs-helpers/readers.d.ts.map +1 -0
  109. package/dist/lib/fs-helpers/readers.js +4 -0
  110. package/dist/lib/fs-helpers/readers.js.map +1 -0
  111. package/dist/lib/fs-helpers.d.ts +4 -25
  112. package/dist/lib/fs-helpers.d.ts.map +1 -1
  113. package/dist/lib/fs-helpers.js +4 -327
  114. package/dist/lib/fs-helpers.js.map +1 -1
  115. package/dist/lib/path-validation/allowed-directories.d.ts +9 -0
  116. package/dist/lib/path-validation/allowed-directories.d.ts.map +1 -0
  117. package/dist/lib/path-validation/allowed-directories.js +94 -0
  118. package/dist/lib/path-validation/allowed-directories.js.map +1 -0
  119. package/dist/lib/path-validation/errors.d.ts +5 -0
  120. package/dist/lib/path-validation/errors.d.ts.map +1 -0
  121. package/dist/lib/path-validation/errors.js +33 -0
  122. package/dist/lib/path-validation/errors.js.map +1 -0
  123. package/dist/lib/path-validation/roots.d.ts +3 -0
  124. package/dist/lib/path-validation/roots.d.ts.map +1 -0
  125. package/dist/lib/path-validation/roots.js +49 -0
  126. package/dist/lib/path-validation/roots.js.map +1 -0
  127. package/dist/lib/path-validation/validators.d.ts +9 -0
  128. package/dist/lib/path-validation/validators.d.ts.map +1 -0
  129. package/dist/lib/path-validation/validators.js +70 -0
  130. package/dist/lib/path-validation/validators.js.map +1 -0
  131. package/dist/lib/path-validation.d.ts +3 -7
  132. package/dist/lib/path-validation.d.ts.map +1 -1
  133. package/dist/lib/path-validation.js +3 -141
  134. package/dist/lib/path-validation.js.map +1 -1
  135. package/dist/schemas/input-helpers.d.ts +8 -0
  136. package/dist/schemas/input-helpers.d.ts.map +1 -0
  137. package/dist/schemas/input-helpers.js +44 -0
  138. package/dist/schemas/input-helpers.js.map +1 -0
  139. package/dist/schemas/inputs.d.ts +8 -5
  140. package/dist/schemas/inputs.d.ts.map +1 -1
  141. package/dist/schemas/inputs.js +41 -64
  142. package/dist/schemas/inputs.js.map +1 -1
  143. package/dist/schemas/output-helpers.d.ts +24 -0
  144. package/dist/schemas/output-helpers.d.ts.map +1 -0
  145. package/dist/schemas/output-helpers.js +13 -0
  146. package/dist/schemas/output-helpers.js.map +1 -0
  147. package/dist/schemas/outputs.d.ts +476 -42
  148. package/dist/schemas/outputs.d.ts.map +1 -1
  149. package/dist/schemas/outputs.js +26 -41
  150. package/dist/schemas/outputs.js.map +1 -1
  151. package/dist/server.d.ts +9 -1
  152. package/dist/server.d.ts.map +1 -1
  153. package/dist/server.js +28 -42
  154. package/dist/server.js.map +1 -1
  155. package/dist/tools/analyze-directory.d.ts.map +1 -1
  156. package/dist/tools/analyze-directory.js +115 -53
  157. package/dist/tools/analyze-directory.js.map +1 -1
  158. package/dist/tools/directory-tree.d.ts.map +1 -1
  159. package/dist/tools/directory-tree.js +86 -49
  160. package/dist/tools/directory-tree.js.map +1 -1
  161. package/dist/tools/get-file-info.d.ts.map +1 -1
  162. package/dist/tools/get-file-info.js +71 -37
  163. package/dist/tools/get-file-info.js.map +1 -1
  164. package/dist/tools/list-allowed-dirs.d.ts.map +1 -1
  165. package/dist/tools/list-allowed-dirs.js +48 -35
  166. package/dist/tools/list-allowed-dirs.js.map +1 -1
  167. package/dist/tools/list-directory.d.ts.map +1 -1
  168. package/dist/tools/list-directory.js +129 -58
  169. package/dist/tools/list-directory.js.map +1 -1
  170. package/dist/tools/read-file.d.ts.map +1 -1
  171. package/dist/tools/read-file.js +70 -56
  172. package/dist/tools/read-file.js.map +1 -1
  173. package/dist/tools/read-media-file.d.ts.map +1 -1
  174. package/dist/tools/read-media-file.js +39 -41
  175. package/dist/tools/read-media-file.js.map +1 -1
  176. package/dist/tools/read-multiple-files.d.ts.map +1 -1
  177. package/dist/tools/read-multiple-files.js +58 -50
  178. package/dist/tools/read-multiple-files.js.map +1 -1
  179. package/dist/tools/search-content.d.ts.map +1 -1
  180. package/dist/tools/search-content.js +146 -89
  181. package/dist/tools/search-content.js.map +1 -1
  182. package/dist/tools/search-files.d.ts.map +1 -1
  183. package/dist/tools/search-files.js +121 -50
  184. package/dist/tools/search-files.js.map +1 -1
  185. package/dist/tools/tool-response.d.ts +9 -0
  186. package/dist/tools/tool-response.d.ts.map +1 -0
  187. package/dist/tools/tool-response.js +7 -0
  188. package/dist/tools/tool-response.js.map +1 -0
  189. package/package.json +2 -1
  190. package/dist/__tests__/errors.test.d.ts +0 -2
  191. package/dist/__tests__/errors.test.d.ts.map +0 -1
  192. package/dist/__tests__/errors.test.js +0 -88
  193. package/dist/__tests__/errors.test.js.map +0 -1
  194. package/dist/__tests__/file-operations.test.d.ts +0 -2
  195. package/dist/__tests__/file-operations.test.d.ts.map +0 -1
  196. package/dist/__tests__/file-operations.test.js +0 -230
  197. package/dist/__tests__/file-operations.test.js.map +0 -1
  198. package/dist/__tests__/lib/formatters.test.d.ts +0 -2
  199. package/dist/__tests__/lib/formatters.test.d.ts.map +0 -1
  200. package/dist/__tests__/lib/formatters.test.js +0 -248
  201. package/dist/__tests__/lib/formatters.test.js.map +0 -1
  202. package/dist/__tests__/lib/image-parsing.test.d.ts +0 -2
  203. package/dist/__tests__/lib/image-parsing.test.d.ts.map +0 -1
  204. package/dist/__tests__/lib/image-parsing.test.js +0 -262
  205. package/dist/__tests__/lib/image-parsing.test.js.map +0 -1
  206. package/dist/__tests__/path-validation.test.d.ts +0 -2
  207. package/dist/__tests__/path-validation.test.d.ts.map +0 -1
  208. package/dist/__tests__/path-validation.test.js +0 -92
  209. package/dist/__tests__/path-validation.test.js.map +0 -1
  210. package/dist/lib/directory-helpers.d.ts +0 -4
  211. package/dist/lib/directory-helpers.d.ts.map +0 -1
  212. package/dist/lib/directory-helpers.js +0 -36
  213. package/dist/lib/directory-helpers.js.map +0 -1
  214. package/dist/lib/formatters.d.ts +0 -10
  215. package/dist/lib/formatters.d.ts.map +0 -1
  216. package/dist/lib/formatters.js +0 -202
  217. package/dist/lib/formatters.js.map +0 -1
  218. package/dist/lib/image-parsing.d.ts +0 -4
  219. package/dist/lib/image-parsing.d.ts.map +0 -1
  220. package/dist/lib/image-parsing.js +0 -124
  221. package/dist/lib/image-parsing.js.map +0 -1
  222. package/dist/lib/mcp-logger.d.ts +0 -11
  223. package/dist/lib/mcp-logger.d.ts.map +0 -1
  224. package/dist/lib/mcp-logger.js +0 -49
  225. package/dist/lib/mcp-logger.js.map +0 -1
  226. package/dist/lib/roots-utils.d.ts +0 -7
  227. package/dist/lib/roots-utils.d.ts.map +0 -1
  228. package/dist/lib/roots-utils.js +0 -39
  229. package/dist/lib/roots-utils.js.map +0 -1
  230. package/dist/lib/search-helpers.d.ts +0 -16
  231. package/dist/lib/search-helpers.d.ts.map +0 -1
  232. package/dist/lib/search-helpers.js +0 -169
  233. package/dist/lib/search-helpers.js.map +0 -1
  234. package/dist/lib/sorting.d.ts +0 -12
  235. package/dist/lib/sorting.d.ts.map +0 -1
  236. package/dist/lib/sorting.js +0 -41
  237. package/dist/lib/sorting.js.map +0 -1
  238. package/dist/lib/types.d.ts +0 -6
  239. package/dist/lib/types.d.ts.map +0 -1
  240. package/dist/lib/types.js +0 -2
  241. package/dist/lib/types.js.map +0 -1
  242. package/dist/prompts/analyze-codebase.d.ts +0 -3
  243. package/dist/prompts/analyze-codebase.d.ts.map +0 -1
  244. package/dist/prompts/analyze-codebase.js +0 -144
  245. package/dist/prompts/analyze-codebase.js.map +0 -1
  246. package/dist/prompts/filesystem-query.d.ts +0 -3
  247. package/dist/prompts/filesystem-query.d.ts.map +0 -1
  248. package/dist/prompts/filesystem-query.js +0 -168
  249. package/dist/prompts/filesystem-query.js.map +0 -1
  250. package/dist/prompts/find-duplicates.d.ts +0 -3
  251. package/dist/prompts/find-duplicates.d.ts.map +0 -1
  252. package/dist/prompts/find-duplicates.js +0 -77
  253. package/dist/prompts/find-duplicates.js.map +0 -1
  254. package/dist/prompts/index.d.ts +0 -3
  255. package/dist/prompts/index.d.ts.map +0 -1
  256. package/dist/prompts/index.js +0 -13
  257. package/dist/prompts/index.js.map +0 -1
  258. package/dist/prompts/project-overview.d.ts +0 -3
  259. package/dist/prompts/project-overview.d.ts.map +0 -1
  260. package/dist/prompts/project-overview.js +0 -122
  261. package/dist/prompts/project-overview.js.map +0 -1
  262. package/dist/prompts/search-and-replace.d.ts +0 -3
  263. package/dist/prompts/search-and-replace.d.ts.map +0 -1
  264. package/dist/prompts/search-and-replace.js +0 -130
  265. package/dist/prompts/search-and-replace.js.map +0 -1
  266. package/dist/prompts/shared.d.ts +0 -11
  267. package/dist/prompts/shared.d.ts.map +0 -1
  268. package/dist/prompts/shared.js +0 -32
  269. package/dist/prompts/shared.js.map +0 -1
  270. package/dist/resources/index.d.ts +0 -3
  271. package/dist/resources/index.d.ts.map +0 -1
  272. package/dist/resources/index.js +0 -54
  273. package/dist/resources/index.js.map +0 -1
  274. package/dist/schemas/validators.d.ts +0 -12
  275. package/dist/schemas/validators.d.ts.map +0 -1
  276. package/dist/schemas/validators.js +0 -35
  277. package/dist/schemas/validators.js.map +0 -1
  278. package/dist/utils/index.d.ts +0 -2
  279. package/dist/utils/index.d.ts.map +0 -1
  280. package/dist/utils/index.js +0 -2
  281. package/dist/utils/index.js.map +0 -1
  282. package/dist/utils/response-helpers.d.ts +0 -22
  283. package/dist/utils/response-helpers.d.ts.map +0 -1
  284. package/dist/utils/response-helpers.js +0 -24
  285. package/dist/utils/response-helpers.js.map +0 -1
@@ -0,0 +1,94 @@
1
+ import * as fs from 'node:fs/promises';
2
+ import * as path from 'node:path';
3
+ import { normalizePath } from '../path-utils.js';
4
+ const PATH_SEPARATOR = process.platform === 'win32' ? '\\' : '/';
5
+ let allowedDirectories = [];
6
+ export const RESERVED_DEVICE_NAMES = new Set([
7
+ 'CON',
8
+ 'PRN',
9
+ 'AUX',
10
+ 'NUL',
11
+ 'COM1',
12
+ 'COM2',
13
+ 'COM3',
14
+ 'COM4',
15
+ 'COM5',
16
+ 'COM6',
17
+ 'COM7',
18
+ 'COM8',
19
+ 'COM9',
20
+ 'LPT1',
21
+ 'LPT2',
22
+ 'LPT3',
23
+ 'LPT4',
24
+ 'LPT5',
25
+ 'LPT6',
26
+ 'LPT7',
27
+ 'LPT8',
28
+ 'LPT9',
29
+ ]);
30
+ export function normalizeForComparison(p) {
31
+ return process.platform === 'win32' ? p.toLowerCase() : p;
32
+ }
33
+ function stripTrailingSeparator(normalized) {
34
+ return normalized.endsWith(PATH_SEPARATOR)
35
+ ? normalized.slice(0, -1)
36
+ : normalized;
37
+ }
38
+ export function normalizeAllowedDirectory(dir) {
39
+ const normalized = normalizePath(dir);
40
+ if (normalized.length === 0)
41
+ return '';
42
+ const { root } = path.parse(normalized);
43
+ const isRoot = normalizeForComparison(root) === normalizeForComparison(normalized);
44
+ if (isRoot)
45
+ return root;
46
+ return stripTrailingSeparator(normalized);
47
+ }
48
+ export function setAllowedDirectories(dirs) {
49
+ const normalized = dirs
50
+ .map(normalizeAllowedDirectory)
51
+ .filter((d) => d.length > 0);
52
+ allowedDirectories = [...new Set(normalized)];
53
+ }
54
+ export function getAllowedDirectories() {
55
+ return [...allowedDirectories];
56
+ }
57
+ export function isPathWithinAllowedDirectories(normalizedPath) {
58
+ const candidate = normalizeForComparison(normalizedPath);
59
+ return allowedDirectories.some((allowedDir) => {
60
+ const allowed = normalizeForComparison(allowedDir);
61
+ const root = normalizeForComparison(path.parse(allowedDir).root);
62
+ if (allowed === root) {
63
+ return candidate.startsWith(allowed);
64
+ }
65
+ return (candidate === allowed || candidate.startsWith(allowed + PATH_SEPARATOR));
66
+ });
67
+ }
68
+ export async function expandAllowedDirectories(dirs) {
69
+ const expanded = [];
70
+ for (const dir of dirs) {
71
+ const normalized = normalizeAllowedDirectory(dir);
72
+ if (!normalized)
73
+ continue;
74
+ expanded.push(normalized);
75
+ try {
76
+ const realPath = await fs.realpath(normalized);
77
+ const normalizedReal = normalizeAllowedDirectory(realPath);
78
+ if (normalizedReal &&
79
+ normalizeForComparison(normalizedReal) !==
80
+ normalizeForComparison(normalized)) {
81
+ expanded.push(normalizedReal);
82
+ }
83
+ }
84
+ catch {
85
+ // Keep normalized path if realpath fails
86
+ }
87
+ }
88
+ return [...new Set(expanded)];
89
+ }
90
+ export async function setAllowedDirectoriesResolved(dirs) {
91
+ const expanded = await expandAllowedDirectories(dirs);
92
+ setAllowedDirectories(expanded);
93
+ }
94
+ //# sourceMappingURL=allowed-directories.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"allowed-directories.js","sourceRoot":"","sources":["../../../src/lib/path-validation/allowed-directories.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { McpError } from '../errors.js';
2
+ export declare function buildAllowedDirectoriesHint(): string;
3
+ export declare function toMcpError(requestedPath: string, error: unknown): McpError;
4
+ export declare function toAccessDeniedWithHint(requestedPath: string, resolvedPath: string, normalizedResolved: string): McpError;
5
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/lib/path-validation/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,QAAQ,EAAE,MAAM,cAAc,CAAC;AAanD,wBAAgB,2BAA2B,IAAI,MAAM,CAKpD;AAED,wBAAgB,UAAU,CAAC,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,QAAQ,CAmD1E;AAED,wBAAgB,sBAAsB,CACpC,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,kBAAkB,EAAE,MAAM,GACzB,QAAQ,CAQV"}
@@ -0,0 +1,33 @@
1
+ import { ErrorCode, McpError } from '../errors.js';
2
+ import { getAllowedDirectories } from './allowed-directories.js';
3
+ function createMcpError(code, message, requestedPath, details, cause) {
4
+ return new McpError(code, message, requestedPath, details, cause);
5
+ }
6
+ export function buildAllowedDirectoriesHint() {
7
+ const allowedDirs = getAllowedDirectories();
8
+ return allowedDirs.length > 0
9
+ ? `Allowed directories:\n${allowedDirs.map((d) => ` - ${d}`).join('\n')}`
10
+ : 'No allowed directories configured. Use CLI arguments or MCP roots protocol.';
11
+ }
12
+ export function toMcpError(requestedPath, error) {
13
+ const nodeError = error;
14
+ const { code } = nodeError;
15
+ if (code === 'ENOENT') {
16
+ return createMcpError(ErrorCode.E_NOT_FOUND, `Path does not exist: ${requestedPath}`, requestedPath, { originalCode: code }, error);
17
+ }
18
+ if (code === 'EACCES' || code === 'EPERM') {
19
+ return createMcpError(ErrorCode.E_PERMISSION_DENIED, `Permission denied accessing path: ${requestedPath}`, requestedPath, { originalCode: code }, error);
20
+ }
21
+ if (code === 'ELOOP') {
22
+ return createMcpError(ErrorCode.E_SYMLINK_NOT_ALLOWED, `Too many symbolic links in path (possible circular reference): ${requestedPath}`, requestedPath, { originalCode: code }, error);
23
+ }
24
+ if (code === 'ENAMETOOLONG') {
25
+ return createMcpError(ErrorCode.E_INVALID_INPUT, `Path name too long: ${requestedPath}`, requestedPath, { originalCode: code }, error);
26
+ }
27
+ return createMcpError(ErrorCode.E_NOT_FOUND, `Path is not accessible: ${requestedPath}`, requestedPath, { originalCode: code, originalMessage: nodeError.message }, error);
28
+ }
29
+ export function toAccessDeniedWithHint(requestedPath, resolvedPath, normalizedResolved) {
30
+ const suggestion = buildAllowedDirectoriesHint();
31
+ return new McpError(ErrorCode.E_ACCESS_DENIED, `Access denied: Path '${requestedPath}' is outside allowed directories.\n\n${suggestion}`, requestedPath, { resolvedPath, normalizedResolvedPath: normalizedResolved });
32
+ }
33
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/lib/path-validation/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,SAAS,cAAc,CACrB,IAAe,EACf,OAAe,EACf,aAAqB,EACrB,OAAgC,EAChC,KAAc;IAEd,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,2BAA2B;IACzC,MAAM,WAAW,GAAG,qBAAqB,EAAE,CAAC;IAC5C,OAAO,WAAW,CAAC,MAAM,GAAG,CAAC;QAC3B,CAAC,CAAC,yBAAyB,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;QAC1E,CAAC,CAAC,6EAA6E,CAAC;AACpF,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,aAAqB,EAAE,KAAc;IAC9D,MAAM,SAAS,GAAG,KAA8B,CAAC;IACjD,MAAM,EAAE,IAAI,EAAE,GAAG,SAAS,CAAC;IAE3B,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,OAAO,cAAc,CACnB,SAAS,CAAC,WAAW,EACrB,wBAAwB,aAAa,EAAE,EACvC,aAAa,EACb,EAAE,YAAY,EAAE,IAAI,EAAE,EACtB,KAAK,CACN,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QAC1C,OAAO,cAAc,CACnB,SAAS,CAAC,mBAAmB,EAC7B,qCAAqC,aAAa,EAAE,EACpD,aAAa,EACb,EAAE,YAAY,EAAE,IAAI,EAAE,EACtB,KAAK,CACN,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QACrB,OAAO,cAAc,CACnB,SAAS,CAAC,qBAAqB,EAC/B,kEAAkE,aAAa,EAAE,EACjF,aAAa,EACb,EAAE,YAAY,EAAE,IAAI,EAAE,EACtB,KAAK,CACN,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,KAAK,cAAc,EAAE,CAAC;QAC5B,OAAO,cAAc,CACnB,SAAS,CAAC,eAAe,EACzB,uBAAuB,aAAa,EAAE,EACtC,aAAa,EACb,EAAE,YAAY,EAAE,IAAI,EAAE,EACtB,KAAK,CACN,CAAC;IACJ,CAAC;IAED,OAAO,cAAc,CACnB,SAAS,CAAC,WAAW,EACrB,2BAA2B,aAAa,EAAE,EAC1C,aAAa,EACb,EAAE,YAAY,EAAE,IAAI,EAAE,eAAe,EAAE,SAAS,CAAC,OAAO,EAAE,EAC1D,KAAK,CACN,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,aAAqB,EACrB,YAAoB,EACpB,kBAA0B;IAE1B,MAAM,UAAU,GAAG,2BAA2B,EAAE,CAAC;IACjD,OAAO,IAAI,QAAQ,CACjB,SAAS,CAAC,eAAe,EACzB,wBAAwB,aAAa,wCAAwC,UAAU,EAAE,EACzF,aAAa,EACb,EAAE,YAAY,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,CAC7D,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Root } from '@modelcontextprotocol/sdk/types.js';
2
+ export declare function getValidRootDirectories(roots: Root[]): Promise<string[]>;
3
+ //# sourceMappingURL=roots.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roots.d.ts","sourceRoot":"","sources":["../../../src/lib/path-validation/roots.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AA2C/D,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,IAAI,EAAE,GACZ,OAAO,CAAC,MAAM,EAAE,CAAC,CAcnB"}
@@ -0,0 +1,49 @@
1
+ import * as fs from 'node:fs/promises';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { normalizePath } from '../path-utils.js';
4
+ import { normalizeForComparison } from './allowed-directories.js';
5
+ function isFileRoot(root) {
6
+ return root.uri.startsWith('file://');
7
+ }
8
+ async function maybeAddRealPath(normalizedPath, validDirs) {
9
+ try {
10
+ const realPath = await fs.realpath(normalizedPath);
11
+ const normalizedReal = normalizePath(realPath);
12
+ if (normalizeForComparison(normalizedReal) !==
13
+ normalizeForComparison(normalizedPath)) {
14
+ validDirs.push(normalizedReal);
15
+ }
16
+ }
17
+ catch {
18
+ // If realpath fails, use the normalized path only
19
+ }
20
+ }
21
+ async function resolveRootDirectory(root) {
22
+ try {
23
+ const dirPath = fileURLToPath(root.uri);
24
+ const normalizedPath = normalizePath(dirPath);
25
+ const stats = await fs.stat(normalizedPath);
26
+ if (!stats.isDirectory()) {
27
+ console.error(`Skipping root (not a directory): ${normalizedPath}`);
28
+ return null;
29
+ }
30
+ return normalizedPath;
31
+ }
32
+ catch {
33
+ return null;
34
+ }
35
+ }
36
+ export async function getValidRootDirectories(roots) {
37
+ const validDirs = [];
38
+ for (const root of roots) {
39
+ if (!isFileRoot(root))
40
+ continue;
41
+ const normalizedPath = await resolveRootDirectory(root);
42
+ if (!normalizedPath)
43
+ continue;
44
+ validDirs.push(normalizedPath);
45
+ await maybeAddRealPath(normalizedPath, validDirs);
46
+ }
47
+ return validDirs;
48
+ }
49
+ //# sourceMappingURL=roots.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roots.js","sourceRoot":"","sources":["../../../src/lib/path-validation/roots.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAIzC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAElE,SAAS,UAAU,CAAC,IAAU;IAC5B,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;AACxC,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,cAAsB,EACtB,SAAmB;IAEnB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;QACnD,MAAM,cAAc,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;QAC/C,IACE,sBAAsB,CAAC,cAAc,CAAC;YACtC,sBAAsB,CAAC,cAAc,CAAC,EACtC,CAAC;YACD,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,kDAAkD;IACpD,CAAC;AACH,CAAC;AAED,KAAK,UAAU,oBAAoB,CAAC,IAAU;IAC5C,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACxC,MAAM,cAAc,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;QAC9C,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC5C,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACzB,OAAO,CAAC,KAAK,CAAC,oCAAoC,cAAc,EAAE,CAAC,CAAC;YACpE,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,cAAc,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,KAAa;IAEb,MAAM,SAAS,GAAa,EAAE,CAAC;IAE/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAS;QAEhC,MAAM,cAAc,GAAG,MAAM,oBAAoB,CAAC,IAAI,CAAC,CAAC;QACxD,IAAI,CAAC,cAAc;YAAE,SAAS;QAE9B,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC/B,MAAM,gBAAgB,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC;IACpD,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,9 @@
1
+ interface ValidatedPathDetails {
2
+ requestedPath: string;
3
+ resolvedPath: string;
4
+ isSymlink: boolean;
5
+ }
6
+ export declare function validateExistingPathDetailed(requestedPath: string): Promise<ValidatedPathDetails>;
7
+ export declare function validateExistingPath(requestedPath: string): Promise<string>;
8
+ export {};
9
+ //# sourceMappingURL=validators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../../../src/lib/path-validation/validators.ts"],"names":[],"mappings":"AAWA,UAAU,oBAAoB;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;CACpB;AAgGD,wBAAsB,4BAA4B,CAChD,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,oBAAoB,CAAC,CAE/B;AAED,wBAAsB,oBAAoB,CACxC,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,CAAC,CAGjB"}
@@ -0,0 +1,70 @@
1
+ import * as fs from 'node:fs/promises';
2
+ import { ErrorCode, McpError } from '../errors.js';
3
+ import { normalizePath } from '../path-utils.js';
4
+ import { isPathWithinAllowedDirectories, normalizeForComparison, RESERVED_DEVICE_NAMES, } from './allowed-directories.js';
5
+ import { toAccessDeniedWithHint, toMcpError } from './errors.js';
6
+ function ensureNonEmptyPath(requestedPath) {
7
+ if (!requestedPath || requestedPath.trim().length === 0) {
8
+ throw new McpError(ErrorCode.E_INVALID_INPUT, 'Path cannot be empty or whitespace', requestedPath);
9
+ }
10
+ }
11
+ function ensureNoNullBytes(requestedPath) {
12
+ if (requestedPath.includes('\0')) {
13
+ throw new McpError(ErrorCode.E_INVALID_INPUT, 'Path contains null bytes', requestedPath);
14
+ }
15
+ }
16
+ function ensureNoReservedWindowsNames(requestedPath) {
17
+ if (process.platform !== 'win32')
18
+ return;
19
+ const segments = requestedPath.split(/[\\/]/);
20
+ for (const segment of segments) {
21
+ const baseName = segment.split('.')[0]?.toUpperCase();
22
+ if (baseName && RESERVED_DEVICE_NAMES.has(baseName)) {
23
+ throw new McpError(ErrorCode.E_INVALID_INPUT, `Windows reserved device name not allowed: ${baseName}`, requestedPath);
24
+ }
25
+ }
26
+ }
27
+ function ensureWithinAllowedDirectories(normalizedPath, requestedPath, details) {
28
+ if (isPathWithinAllowedDirectories(normalizedPath))
29
+ return;
30
+ throw new McpError(ErrorCode.E_ACCESS_DENIED, `Access denied: Path '${requestedPath}' is outside allowed directories`, requestedPath, details);
31
+ }
32
+ function validateRequestedPath(requestedPath) {
33
+ ensureNonEmptyPath(requestedPath);
34
+ ensureNoNullBytes(requestedPath);
35
+ ensureNoReservedWindowsNames(requestedPath);
36
+ return normalizePath(requestedPath);
37
+ }
38
+ async function resolveRealPath(requestedPath, normalizedRequested) {
39
+ try {
40
+ return await fs.realpath(normalizedRequested);
41
+ }
42
+ catch (error) {
43
+ throw toMcpError(requestedPath, error);
44
+ }
45
+ }
46
+ async function validateExistingPathDetailsInternal(requestedPath) {
47
+ const normalizedRequested = validateRequestedPath(requestedPath);
48
+ ensureWithinAllowedDirectories(normalizedRequested, requestedPath, {
49
+ normalizedPath: normalizedRequested,
50
+ });
51
+ const realPath = await resolveRealPath(requestedPath, normalizedRequested);
52
+ const normalizedReal = normalizePath(realPath);
53
+ if (!isPathWithinAllowedDirectories(normalizedReal)) {
54
+ throw toAccessDeniedWithHint(requestedPath, realPath, normalizedReal);
55
+ }
56
+ return {
57
+ requestedPath: normalizedRequested,
58
+ resolvedPath: normalizedReal,
59
+ isSymlink: normalizeForComparison(normalizedRequested) !==
60
+ normalizeForComparison(normalizedReal),
61
+ };
62
+ }
63
+ export async function validateExistingPathDetailed(requestedPath) {
64
+ return validateExistingPathDetailsInternal(requestedPath);
65
+ }
66
+ export async function validateExistingPath(requestedPath) {
67
+ const details = await validateExistingPathDetailsInternal(requestedPath);
68
+ return details.resolvedPath;
69
+ }
70
+ //# sourceMappingURL=validators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validators.js","sourceRoot":"","sources":["../../../src/lib/path-validation/validators.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,4 @@
1
- import type { Root } from '@modelcontextprotocol/sdk/types.js';
2
- import type { ValidatedPathDetails } from '../config/types.js';
3
- export declare function setAllowedDirectories(dirs: string[]): void;
4
- export declare function getAllowedDirectories(): string[];
5
- export declare function validateExistingPathDetailed(requestedPath: string): Promise<ValidatedPathDetails>;
6
- export declare function validateExistingPath(requestedPath: string): Promise<string>;
7
- export declare function getValidRootDirectories(roots: Root[]): Promise<string[]>;
1
+ export { getAllowedDirectories, setAllowedDirectories, setAllowedDirectoriesResolved, expandAllowedDirectories, RESERVED_DEVICE_NAMES, } from './path-validation/allowed-directories.js';
2
+ export { validateExistingPath, validateExistingPathDetailed, } from './path-validation/validators.js';
3
+ export { getValidRootDirectories } from './path-validation/roots.js';
8
4
  //# sourceMappingURL=path-validation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"path-validation.d.ts","sourceRoot":"","sources":["../../src/lib/path-validation.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAE/D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAM/D,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAG1D;AAED,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAEhD;AAoKD,wBAAsB,4BAA4B,CAChD,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,oBAAoB,CAAC,CAE/B;AAED,wBAAsB,oBAAoB,CACxC,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,CAAC,CAGjB;AAED,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,IAAI,EAAE,GACZ,OAAO,CAAC,MAAM,EAAE,CAAC,CA8BnB"}
1
+ {"version":3,"file":"path-validation.d.ts","sourceRoot":"","sources":["../../src/lib/path-validation.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,6BAA6B,EAC7B,wBAAwB,EACxB,qBAAqB,GACtB,MAAM,0CAA0C,CAAC;AAClD,OAAO,EACL,oBAAoB,EACpB,4BAA4B,GAC7B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC"}
@@ -1,142 +1,4 @@
1
- import * as fs from 'node:fs/promises';
2
- import { fileURLToPath } from 'node:url';
3
- import { ErrorCode, McpError } from './errors.js';
4
- import { normalizePath } from './path-utils.js';
5
- let allowedDirectories = [];
6
- export function setAllowedDirectories(dirs) {
7
- const normalized = dirs.map(normalizePath).filter((d) => d.length > 0);
8
- allowedDirectories = [...new Set(normalized)];
9
- }
10
- export function getAllowedDirectories() {
11
- return [...allowedDirectories];
12
- }
13
- const PATH_SEPARATOR = process.platform === 'win32' ? '\\' : '/';
14
- function normalizeForComparison(p) {
15
- return process.platform === 'win32' ? p.toLowerCase() : p;
16
- }
17
- function isPathWithinAllowedDirectories(normalizedPath) {
18
- const candidate = normalizeForComparison(normalizedPath);
19
- return allowedDirectories.some((allowedDir) => {
20
- const allowed = normalizeForComparison(allowedDir);
21
- return (candidate === allowed || candidate.startsWith(allowed + PATH_SEPARATOR));
22
- });
23
- }
24
- const RESERVED_DEVICE_NAMES = new Set([
25
- 'CON',
26
- 'PRN',
27
- 'AUX',
28
- 'NUL',
29
- 'COM1',
30
- 'COM2',
31
- 'COM3',
32
- 'COM4',
33
- 'COM5',
34
- 'COM6',
35
- 'COM7',
36
- 'COM8',
37
- 'COM9',
38
- 'LPT1',
39
- 'LPT2',
40
- 'LPT3',
41
- 'LPT4',
42
- 'LPT5',
43
- 'LPT6',
44
- 'LPT7',
45
- 'LPT8',
46
- 'LPT9',
47
- ]);
48
- async function validateExistingPathDetailsInternal(requestedPath) {
49
- if (!requestedPath || requestedPath.trim().length === 0) {
50
- throw new McpError(ErrorCode.E_INVALID_INPUT, 'Path cannot be empty or whitespace', requestedPath);
51
- }
52
- // Check for null bytes (path truncation attack prevention)
53
- if (requestedPath.includes('\0')) {
54
- throw new McpError(ErrorCode.E_INVALID_INPUT, 'Path contains null bytes', requestedPath);
55
- }
56
- // Check for Windows reserved device names
57
- if (process.platform === 'win32') {
58
- const segments = requestedPath.split(/[\\/]/);
59
- for (const segment of segments) {
60
- const baseName = segment.split('.')[0]?.toUpperCase();
61
- if (baseName && RESERVED_DEVICE_NAMES.has(baseName)) {
62
- throw new McpError(ErrorCode.E_INVALID_INPUT, `Windows reserved device name not allowed: ${baseName}`, requestedPath);
63
- }
64
- }
65
- }
66
- const normalizedRequested = normalizePath(requestedPath);
67
- if (!isPathWithinAllowedDirectories(normalizedRequested)) {
68
- throw new McpError(ErrorCode.E_ACCESS_DENIED, `Access denied: Path '${requestedPath}' is outside allowed directories`, requestedPath, { normalizedPath: normalizedRequested });
69
- }
70
- let realPath;
71
- try {
72
- realPath = await fs.realpath(normalizedRequested);
73
- }
74
- catch (error) {
75
- const nodeError = error;
76
- if (nodeError.code === 'ENOENT') {
77
- throw new McpError(ErrorCode.E_NOT_FOUND, `Path does not exist: ${requestedPath}`, requestedPath, { originalCode: nodeError.code }, error);
78
- }
79
- if (nodeError.code === 'EACCES' || nodeError.code === 'EPERM') {
80
- throw new McpError(ErrorCode.E_PERMISSION_DENIED, `Permission denied accessing path: ${requestedPath}`, requestedPath, { originalCode: nodeError.code }, error);
81
- }
82
- if (nodeError.code === 'ELOOP') {
83
- throw new McpError(ErrorCode.E_SYMLINK_NOT_ALLOWED, `Too many symbolic links in path (possible circular reference): ${requestedPath}`, requestedPath, { originalCode: nodeError.code }, error);
84
- }
85
- if (nodeError.code === 'ENAMETOOLONG') {
86
- throw new McpError(ErrorCode.E_INVALID_INPUT, `Path name too long: ${requestedPath}`, requestedPath, { originalCode: nodeError.code }, error);
87
- }
88
- throw new McpError(ErrorCode.E_NOT_FOUND, `Path is not accessible: ${requestedPath}`, requestedPath, { originalCode: nodeError.code, originalMessage: nodeError.message }, error);
89
- }
90
- const normalizedReal = normalizePath(realPath);
91
- if (!isPathWithinAllowedDirectories(normalizedReal)) {
92
- const allowedDirs = getAllowedDirectories();
93
- const suggestion = allowedDirs.length > 0
94
- ? `Allowed directories:\n${allowedDirs.map((d) => ` - ${d}`).join('\n')}`
95
- : 'No allowed directories configured. Use CLI arguments or MCP roots protocol.';
96
- throw new McpError(ErrorCode.E_ACCESS_DENIED, `Access denied: Path '${requestedPath}' is outside allowed directories.\n\n${suggestion}`, requestedPath, { resolvedPath: realPath, normalizedResolvedPath: normalizedReal });
97
- }
98
- const isSymlink = normalizedRequested !== normalizedReal;
99
- return {
100
- requestedPath: normalizedRequested,
101
- resolvedPath: normalizedReal,
102
- isSymlink,
103
- };
104
- }
105
- export async function validateExistingPathDetailed(requestedPath) {
106
- return validateExistingPathDetailsInternal(requestedPath);
107
- }
108
- export async function validateExistingPath(requestedPath) {
109
- const details = await validateExistingPathDetailsInternal(requestedPath);
110
- return details.resolvedPath;
111
- }
112
- export async function getValidRootDirectories(roots) {
113
- const validDirs = [];
114
- for (const root of roots) {
115
- if (!root.uri.startsWith('file://')) {
116
- continue;
117
- }
118
- try {
119
- const dirPath = fileURLToPath(root.uri);
120
- const normalizedPath = normalizePath(dirPath);
121
- const stats = await fs.stat(normalizedPath);
122
- if (stats.isDirectory()) {
123
- try {
124
- const realPath = await fs.realpath(normalizedPath);
125
- validDirs.push(normalizePath(realPath));
126
- }
127
- catch {
128
- // If realpath fails, use the normalized path
129
- validDirs.push(normalizedPath);
130
- }
131
- }
132
- else {
133
- console.error(`Skipping root (not a directory): ${normalizedPath}`);
134
- }
135
- }
136
- catch {
137
- continue;
138
- }
139
- }
140
- return validDirs;
141
- }
1
+ export { getAllowedDirectories, setAllowedDirectories, setAllowedDirectoriesResolved, expandAllowedDirectories, RESERVED_DEVICE_NAMES, } from './path-validation/allowed-directories.js';
2
+ export { validateExistingPath, validateExistingPathDetailed, } from './path-validation/validators.js';
3
+ export { getValidRootDirectories } from './path-validation/roots.js';
142
4
  //# sourceMappingURL=path-validation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"path-validation.js","sourceRoot":"","sources":["../../src/lib/path-validation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"path-validation.js","sourceRoot":"","sources":["../../src/lib/path-validation.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,6BAA6B,EAC7B,wBAAwB,EACxB,qBAAqB,GACtB,MAAM,0CAA0C,CAAC;AAClD,OAAO,EACL,oBAAoB,EACpB,4BAA4B,GAC7B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { z } from 'zod';
2
+ export declare function isSafeGlobPattern(value: string): boolean;
3
+ export declare const EncodingSchema: z.ZodDefault<z.ZodOptional<z.ZodEnum<["utf-8", "utf8", "ascii", "base64", "hex", "latin1"]>>>;
4
+ export declare const ReadFileMaxSizeSchema: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
5
+ export declare const ReadMultipleFilesMaxSizeSchema: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
6
+ export declare const ExcludePatternsSchema: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodEffects<z.ZodString, string, string>, "many">>>;
7
+ export declare const BasicExcludePatternsSchema: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
8
+ //# sourceMappingURL=input-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-helpers.d.ts","sourceRoot":"","sources":["../../src/schemas/input-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAaxD;AAED,eAAO,MAAM,cAAc,+FAIC,CAAC;AAU7B,eAAO,MAAM,qBAAqB,0CAEjC,CAAC;AAEF,eAAO,MAAM,8BAA8B,0CAE1C,CAAC;AAEF,eAAO,MAAM,qBAAqB,4FAWpB,CAAC;AAEf,eAAO,MAAM,0BAA0B,8DAIzB,CAAC"}
@@ -0,0 +1,44 @@
1
+ import { z } from 'zod';
2
+ import { MAX_TEXT_FILE_SIZE } from '../lib/constants.js';
3
+ export function isSafeGlobPattern(value) {
4
+ if (value.length === 0)
5
+ return false;
6
+ const absolutePattern = /^([/\\]|[A-Za-z]:[/\\]|\\\\)/u;
7
+ if (absolutePattern.test(value)) {
8
+ return false;
9
+ }
10
+ if (/[\\/]\.\.(?:[/\\]|$)/u.test(value) || value.startsWith('..')) {
11
+ return false;
12
+ }
13
+ return true;
14
+ }
15
+ export const EncodingSchema = z
16
+ .enum(['utf-8', 'utf8', 'ascii', 'base64', 'hex', 'latin1'])
17
+ .optional()
18
+ .default('utf-8')
19
+ .describe('File encoding');
20
+ const MaxTextFileSizeSchema = z
21
+ .number()
22
+ .int('maxSize must be an integer')
23
+ .min(1, 'maxSize must be at least 1 byte')
24
+ .max(100 * 1024 * 1024, 'maxSize cannot exceed 100MB')
25
+ .optional()
26
+ .default(MAX_TEXT_FILE_SIZE);
27
+ export const ReadFileMaxSizeSchema = MaxTextFileSizeSchema.describe('Maximum file size in bytes (default 10MB)');
28
+ export const ReadMultipleFilesMaxSizeSchema = MaxTextFileSizeSchema.describe('Maximum file size in bytes per file (default 10MB)');
29
+ export const ExcludePatternsSchema = z
30
+ .array(z
31
+ .string()
32
+ .max(500, 'Individual exclude pattern is too long')
33
+ .refine((val) => !val.includes('**/**/**'), {
34
+ message: 'Pattern too deeply nested (max 2 levels of **)',
35
+ }))
36
+ .max(100, 'Too many exclude patterns (max 100)')
37
+ .optional()
38
+ .default([]);
39
+ export const BasicExcludePatternsSchema = z
40
+ .array(z.string().max(500, 'Individual exclude pattern is too long'))
41
+ .max(100, 'Too many exclude patterns (max 100)')
42
+ .optional()
43
+ .default([]);
44
+ //# sourceMappingURL=input-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-helpers.js","sourceRoot":"","sources":["../../src/schemas/input-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAEzD,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAErC,MAAM,eAAe,GAAG,+BAA+B,CAAC;IACxD,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAClE,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC;KAC5B,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;KAC3D,QAAQ,EAAE;KACV,OAAO,CAAC,OAAO,CAAC;KAChB,QAAQ,CAAC,eAAe,CAAC,CAAC;AAE7B,MAAM,qBAAqB,GAAG,CAAC;KAC5B,MAAM,EAAE;KACR,GAAG,CAAC,4BAA4B,CAAC;KACjC,GAAG,CAAC,CAAC,EAAE,iCAAiC,CAAC;KACzC,GAAG,CAAC,GAAG,GAAG,IAAI,GAAG,IAAI,EAAE,6BAA6B,CAAC;KACrD,QAAQ,EAAE;KACV,OAAO,CAAC,kBAAkB,CAAC,CAAC;AAE/B,MAAM,CAAC,MAAM,qBAAqB,GAAG,qBAAqB,CAAC,QAAQ,CACjE,2CAA2C,CAC5C,CAAC;AAEF,MAAM,CAAC,MAAM,8BAA8B,GAAG,qBAAqB,CAAC,QAAQ,CAC1E,oDAAoD,CACrD,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC;KACnC,KAAK,CACJ,CAAC;KACE,MAAM,EAAE;KACR,GAAG,CAAC,GAAG,EAAE,wCAAwC,CAAC;KAClD,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE;IAC1C,OAAO,EAAE,gDAAgD;CAC1D,CAAC,CACL;KACA,GAAG,CAAC,GAAG,EAAE,qCAAqC,CAAC;KAC/C,QAAQ,EAAE;KACV,OAAO,CAAC,EAAE,CAAC,CAAC;AAEf,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC;KACxC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,wCAAwC,CAAC,CAAC;KACpE,GAAG,CAAC,GAAG,EAAE,qCAAqC,CAAC;KAC/C,QAAQ,EAAE;KACV,OAAO,CAAC,EAAE,CAAC,CAAC"}
@@ -12,13 +12,15 @@ export declare const SearchFilesInputSchema: {
12
12
  path: z.ZodString;
13
13
  pattern: z.ZodEffects<z.ZodString, string, string>;
14
14
  excludePatterns: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodEffects<z.ZodString, string, string>, "many">>>;
15
- maxResults: z.ZodOptional<z.ZodNumber>;
15
+ maxResults: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
16
16
  sortBy: z.ZodDefault<z.ZodOptional<z.ZodEnum<["name", "size", "modified", "path"]>>>;
17
17
  maxDepth: z.ZodOptional<z.ZodNumber>;
18
+ maxFilesScanned: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
19
+ timeoutMs: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
18
20
  };
19
21
  export declare const ReadFileInputSchema: {
20
22
  path: z.ZodString;
21
- encoding: z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodEnum<["utf-8", "utf8", "ascii", "base64", "hex", "latin1"]>>>, "base64" | "ascii" | "utf8" | "utf-8" | "latin1" | "hex", "base64" | "ascii" | "utf8" | "utf-8" | "latin1" | "hex" | undefined>;
23
+ encoding: z.ZodDefault<z.ZodOptional<z.ZodEnum<["utf-8", "utf8", "ascii", "base64", "hex", "latin1"]>>>;
22
24
  maxSize: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
23
25
  lineStart: z.ZodOptional<z.ZodNumber>;
24
26
  lineEnd: z.ZodOptional<z.ZodNumber>;
@@ -39,14 +41,15 @@ export declare const GetFileInfoInputSchema: {
39
41
  export declare const SearchContentInputSchema: {
40
42
  path: z.ZodString;
41
43
  pattern: z.ZodString;
42
- filePattern: z.ZodDefault<z.ZodOptional<z.ZodString>>;
44
+ filePattern: z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodString>>, string, string | undefined>;
43
45
  excludePatterns: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodEffects<z.ZodString, string, string>, "many">>>;
44
46
  caseSensitive: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
45
47
  maxResults: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
46
48
  maxFileSize: z.ZodOptional<z.ZodNumber>;
47
- maxFilesScanned: z.ZodOptional<z.ZodNumber>;
48
- timeoutMs: z.ZodOptional<z.ZodNumber>;
49
+ maxFilesScanned: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
50
+ timeoutMs: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
49
51
  skipBinary: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
52
+ includeHidden: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
50
53
  contextLines: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
51
54
  wholeWord: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
52
55
  isLiteral: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
@@ -1 +1 @@
1
- {"version":3,"file":"inputs.d.ts","sourceRoot":"","sources":["../../src/schemas/inputs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAWxB,eAAO,MAAM,wBAAwB;;;;;;;;CA4CpC,CAAC;AAEF,eAAO,MAAM,sBAAsB;;;;;;;CA6DlC,CAAC;AA2DF,eAAO,MAAM,mBAAmB;;;;;;;;CAA2B,CAAC;AAgD5D,eAAO,MAAM,4BAA4B;;;;;;;CAAoC,CAAC;AAE9E,eAAO,MAAM,sBAAsB;;CAKlC,CAAC;AAEF,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;CA+FpC,CAAC;AAEF,eAAO,MAAM,2BAA2B;;;;;;CAgCvC,CAAC;AAEF,eAAO,MAAM,wBAAwB;;;;;;;CAoCpC,CAAC;AAEF,eAAO,MAAM,wBAAwB;;;CAapC,CAAC"}
1
+ {"version":3,"file":"inputs.d.ts","sourceRoot":"","sources":["../../src/schemas/inputs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAoBxB,eAAO,MAAM,wBAAwB;;;;;;;;CA4CpC,CAAC;AAEF,eAAO,MAAM,sBAAsB;;;;;;;;;CAqElC,CAAC;AA2CF,eAAO,MAAM,mBAAmB;;;;;;;;CAA2B,CAAC;AAqC5D,eAAO,MAAM,4BAA4B;;;;;;;CAAoC,CAAC;AAE9E,eAAO,MAAM,sBAAsB;;CAKlC,CAAC;AAEF,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;CAgGpC,CAAC;AAEF,eAAO,MAAM,2BAA2B;;;;;;CA6BvC,CAAC;AAEF,eAAO,MAAM,wBAAwB;;;;;;;CAiCpC,CAAC;AAEF,eAAO,MAAM,wBAAwB;;;CAapC,CAAC"}