@j0hanz/filesystem-context-mcp 1.0.10 → 1.1.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.
- package/README.md +18 -5
- package/dist/__tests__/schemas/validators.test.js +32 -5
- package/dist/__tests__/schemas/validators.test.js.map +1 -1
- package/dist/config/types.d.ts +27 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/constants.d.ts +6 -6
- package/dist/lib/constants.d.ts.map +1 -1
- package/dist/lib/constants.js +24 -41
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/errors.d.ts +2 -0
- package/dist/lib/errors.d.ts.map +1 -1
- package/dist/lib/errors.js +13 -31
- package/dist/lib/errors.js.map +1 -1
- package/dist/lib/file-operations.d.ts.map +1 -1
- package/dist/lib/file-operations.js +124 -84
- package/dist/lib/file-operations.js.map +1 -1
- package/dist/lib/formatters.d.ts +1 -12
- package/dist/lib/formatters.d.ts.map +1 -1
- package/dist/lib/formatters.js +11 -15
- package/dist/lib/formatters.js.map +1 -1
- package/dist/lib/fs-helpers.d.ts.map +1 -1
- package/dist/lib/fs-helpers.js +25 -48
- package/dist/lib/fs-helpers.js.map +1 -1
- package/dist/lib/image-parsing.d.ts.map +1 -1
- package/dist/lib/image-parsing.js +0 -6
- package/dist/lib/image-parsing.js.map +1 -1
- package/dist/lib/path-utils.d.ts.map +1 -1
- package/dist/lib/path-utils.js +0 -2
- package/dist/lib/path-utils.js.map +1 -1
- package/dist/lib/path-validation.d.ts.map +1 -1
- package/dist/lib/path-validation.js +39 -22
- package/dist/lib/path-validation.js.map +1 -1
- package/dist/lib/search-helpers.d.ts +3 -0
- package/dist/lib/search-helpers.d.ts.map +1 -1
- package/dist/lib/search-helpers.js +29 -65
- package/dist/lib/search-helpers.js.map +1 -1
- package/dist/schemas/outputs.d.ts +14 -14
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1 -15
- package/dist/server.js.map +1 -1
- package/dist/tools/analyze-directory.d.ts.map +1 -1
- package/dist/tools/analyze-directory.js +6 -6
- package/dist/tools/analyze-directory.js.map +1 -1
- package/dist/tools/list-allowed-dirs.d.ts.map +1 -1
- package/dist/tools/list-allowed-dirs.js.map +1 -1
- package/dist/tools/list-directory.js +5 -5
- package/dist/tools/list-directory.js.map +1 -1
- package/dist/tools/read-file.d.ts.map +1 -1
- package/dist/tools/read-file.js +4 -4
- package/dist/tools/read-file.js.map +1 -1
- package/dist/tools/read-multiple-files.d.ts.map +1 -1
- package/dist/tools/read-multiple-files.js +2 -3
- package/dist/tools/read-multiple-files.js.map +1 -1
- package/dist/tools/search-content.d.ts.map +1 -1
- package/dist/tools/search-content.js +5 -10
- package/dist/tools/search-content.js.map +1 -1
- package/dist/tools/search-files.d.ts.map +1 -1
- package/dist/tools/search-files.js +5 -5
- package/dist/tools/search-files.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
// Path validation and security module - the SECURITY BOUNDARY of this server.
|
|
2
|
-
// All filesystem operations MUST call validateExistingPath() before accessing any path.
|
|
3
1
|
import * as fs from 'node:fs/promises';
|
|
4
2
|
import { fileURLToPath } from 'node:url';
|
|
5
3
|
import { ErrorCode, McpError } from './errors.js';
|
|
@@ -20,15 +18,51 @@ function isPathWithinAllowedDirectories(normalizedPath) {
|
|
|
20
18
|
const candidate = normalizeForComparison(normalizedPath);
|
|
21
19
|
return allowedDirectories.some((allowedDir) => {
|
|
22
20
|
const allowed = normalizeForComparison(allowedDir);
|
|
23
|
-
// Exact match or is a child path
|
|
24
21
|
return (candidate === allowed || candidate.startsWith(allowed + PATH_SEPARATOR));
|
|
25
22
|
});
|
|
26
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
|
+
]);
|
|
27
48
|
async function validateExistingPathDetailsInternal(requestedPath) {
|
|
28
|
-
// Validate input is not empty or only whitespace
|
|
29
49
|
if (!requestedPath || requestedPath.trim().length === 0) {
|
|
30
50
|
throw new McpError(ErrorCode.E_INVALID_INPUT, 'Path cannot be empty or whitespace', requestedPath);
|
|
31
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
|
+
}
|
|
32
66
|
const normalizedRequested = normalizePath(requestedPath);
|
|
33
67
|
if (!isPathWithinAllowedDirectories(normalizedRequested)) {
|
|
34
68
|
throw new McpError(ErrorCode.E_ACCESS_DENIED, `Access denied: Path '${requestedPath}' is outside allowed directories`, requestedPath, { normalizedPath: normalizedRequested });
|
|
@@ -38,7 +72,6 @@ async function validateExistingPathDetailsInternal(requestedPath) {
|
|
|
38
72
|
realPath = await fs.realpath(normalizedRequested);
|
|
39
73
|
}
|
|
40
74
|
catch (error) {
|
|
41
|
-
// Distinguish between different error types for better error messages
|
|
42
75
|
const nodeError = error;
|
|
43
76
|
if (nodeError.code === 'ENOENT') {
|
|
44
77
|
throw new McpError(ErrorCode.E_NOT_FOUND, `Path does not exist: ${requestedPath}`, requestedPath, { originalCode: nodeError.code }, error);
|
|
@@ -52,7 +85,6 @@ async function validateExistingPathDetailsInternal(requestedPath) {
|
|
|
52
85
|
if (nodeError.code === 'ENAMETOOLONG') {
|
|
53
86
|
throw new McpError(ErrorCode.E_INVALID_INPUT, `Path name too long: ${requestedPath}`, requestedPath, { originalCode: nodeError.code }, error);
|
|
54
87
|
}
|
|
55
|
-
// Generic fallback for other errors
|
|
56
88
|
throw new McpError(ErrorCode.E_NOT_FOUND, `Path is not accessible: ${requestedPath}`, requestedPath, { originalCode: nodeError.code, originalMessage: nodeError.message }, error);
|
|
57
89
|
}
|
|
58
90
|
const normalizedReal = normalizePath(realPath);
|
|
@@ -63,18 +95,7 @@ async function validateExistingPathDetailsInternal(requestedPath) {
|
|
|
63
95
|
: 'No allowed directories configured. Use CLI arguments or MCP roots protocol.';
|
|
64
96
|
throw new McpError(ErrorCode.E_ACCESS_DENIED, `Access denied: Path '${requestedPath}' is outside allowed directories.\n\n${suggestion}`, requestedPath, { resolvedPath: realPath, normalizedResolvedPath: normalizedReal });
|
|
65
97
|
}
|
|
66
|
-
|
|
67
|
-
// Note: lstat runs after the allowed-directory string check above.
|
|
68
|
-
let isSymlink = false;
|
|
69
|
-
try {
|
|
70
|
-
const lstats = await fs.lstat(normalizedRequested);
|
|
71
|
-
isSymlink = lstats.isSymbolicLink();
|
|
72
|
-
}
|
|
73
|
-
catch {
|
|
74
|
-
// If lstat fails but realpath succeeded, treat as non-symlink.
|
|
75
|
-
// This can happen on some platforms/filesystems; safe default.
|
|
76
|
-
isSymlink = false;
|
|
77
|
-
}
|
|
98
|
+
const isSymlink = normalizedRequested !== normalizedReal;
|
|
78
99
|
return {
|
|
79
100
|
requestedPath: normalizedRequested,
|
|
80
101
|
resolvedPath: normalizedReal,
|
|
@@ -88,21 +109,17 @@ export async function validateExistingPath(requestedPath) {
|
|
|
88
109
|
const details = await validateExistingPathDetailsInternal(requestedPath);
|
|
89
110
|
return details.resolvedPath;
|
|
90
111
|
}
|
|
91
|
-
// Extract valid directory paths from MCP Root objects (file:// URIs only)
|
|
92
112
|
export async function getValidRootDirectories(roots) {
|
|
93
113
|
const validDirs = [];
|
|
94
114
|
for (const root of roots) {
|
|
95
|
-
// Only accept file:// URIs
|
|
96
115
|
if (!root.uri.startsWith('file://')) {
|
|
97
116
|
continue;
|
|
98
117
|
}
|
|
99
118
|
try {
|
|
100
119
|
const dirPath = fileURLToPath(root.uri);
|
|
101
120
|
const normalizedPath = normalizePath(dirPath);
|
|
102
|
-
// Verify the directory exists and is accessible
|
|
103
121
|
const stats = await fs.stat(normalizedPath);
|
|
104
122
|
if (stats.isDirectory()) {
|
|
105
|
-
// Resolve symlinks to get the real path
|
|
106
123
|
try {
|
|
107
124
|
const realPath = await fs.realpath(normalizedPath);
|
|
108
125
|
validDirs.push(normalizePath(realPath));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path-validation.js","sourceRoot":"","sources":["../../src/lib/path-validation.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"path-validation.js","sourceRoot":"","sources":["../../src/lib/path-validation.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,5 +9,8 @@ export declare function scanFileForContent(filePath: string, regex: RegExp, opti
|
|
|
9
9
|
contextLines: number;
|
|
10
10
|
deadlineMs?: number;
|
|
11
11
|
currentMatchCount: number;
|
|
12
|
+
isLiteral?: boolean;
|
|
13
|
+
searchString?: string;
|
|
14
|
+
caseSensitive?: boolean;
|
|
12
15
|
}): Promise<ScanFileResult>;
|
|
13
16
|
//# sourceMappingURL=search-helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-helpers.d.ts","sourceRoot":"","sources":["../../src/lib/search-helpers.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"search-helpers.d.ts","sourceRoot":"","sources":["../../src/lib/search-helpers.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAGV,cAAc,EACf,MAAM,oBAAoB,CAAC;AA4E5B,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAuB5D;AAsBD,wBAAgB,oBAAoB,CAClC,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GACpD,MAAM,CAYR;AAED,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;IACP,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,GACA,OAAO,CAAC,cAAc,CAAC,CAkFzB"}
|
|
@@ -1,58 +1,25 @@
|
|
|
1
1
|
import * as readline from 'node:readline';
|
|
2
2
|
import { createReadStream } from 'node:fs';
|
|
3
3
|
import { MAX_LINE_CONTENT_LENGTH, REGEX_MATCH_TIMEOUT_MS, } from './constants.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
count = 0;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
push(line) {
|
|
15
|
-
// Defensive truncation (should already be handled by caller)
|
|
16
|
-
const truncatedLine = line.length > MAX_LINE_CONTENT_LENGTH
|
|
17
|
-
? line.substring(0, MAX_LINE_CONTENT_LENGTH)
|
|
18
|
-
: line;
|
|
19
|
-
this.buffer[this.writeIndex] = truncatedLine;
|
|
20
|
-
this.writeIndex = (this.writeIndex + 1) % this.capacity;
|
|
21
|
-
if (this.count < this.capacity)
|
|
22
|
-
this.count++;
|
|
23
|
-
}
|
|
24
|
-
toArray() {
|
|
25
|
-
if (this.count === 0)
|
|
26
|
-
return [];
|
|
27
|
-
if (this.count < this.capacity) {
|
|
28
|
-
return this.buffer.slice(0, this.count);
|
|
29
|
-
}
|
|
30
|
-
// Buffer is full - return in correct order with single allocation
|
|
31
|
-
// Avoids multiple spread/slice allocations for better GC performance
|
|
32
|
-
const result = new Array(this.capacity);
|
|
33
|
-
let writeIdx = 0;
|
|
34
|
-
for (let i = this.writeIndex; i < this.capacity; i++) {
|
|
35
|
-
result[writeIdx++] = this.buffer[i] ?? '';
|
|
36
|
-
}
|
|
37
|
-
for (let i = 0; i < this.writeIndex; i++) {
|
|
38
|
-
result[writeIdx++] = this.buffer[i] ?? '';
|
|
39
|
-
}
|
|
40
|
-
return result;
|
|
41
|
-
}
|
|
42
|
-
clear() {
|
|
43
|
-
this.count = 0;
|
|
44
|
-
this.writeIndex = 0;
|
|
4
|
+
function countLiteralMatches(line, searchString, caseSensitive) {
|
|
5
|
+
if (line.length === 0 || searchString.length === 0)
|
|
6
|
+
return 0;
|
|
7
|
+
const haystack = caseSensitive ? line : line.toLowerCase();
|
|
8
|
+
const needle = caseSensitive ? searchString : searchString.toLowerCase();
|
|
9
|
+
let count = 0;
|
|
10
|
+
let pos = 0;
|
|
11
|
+
while ((pos = haystack.indexOf(needle, pos)) !== -1) {
|
|
12
|
+
count++;
|
|
13
|
+
pos += needle.length;
|
|
45
14
|
}
|
|
15
|
+
return count;
|
|
46
16
|
}
|
|
47
|
-
// Count regex matches with timeout protection (returns -1 on timeout)
|
|
48
17
|
function countRegexMatches(line, regex, timeoutMs = REGEX_MATCH_TIMEOUT_MS) {
|
|
49
|
-
// Safety check for empty line
|
|
50
18
|
if (line.length === 0)
|
|
51
19
|
return 0;
|
|
52
20
|
regex.lastIndex = 0;
|
|
53
21
|
let count = 0;
|
|
54
22
|
const deadline = Date.now() + timeoutMs;
|
|
55
|
-
// Hard cap prevents issues with extremely long lines (e.g., minified JS)
|
|
56
23
|
const maxIterations = Math.min(line.length * 2, 10000);
|
|
57
24
|
let iterations = 0;
|
|
58
25
|
let lastIndex = 0;
|
|
@@ -60,12 +27,10 @@ function countRegexMatches(line, regex, timeoutMs = REGEX_MATCH_TIMEOUT_MS) {
|
|
|
60
27
|
while ((match = regex.exec(line)) !== null) {
|
|
61
28
|
count++;
|
|
62
29
|
iterations++;
|
|
63
|
-
// Prevent infinite loops on zero-width matches
|
|
64
30
|
if (match[0] === '') {
|
|
65
31
|
const { lastIndex: newIndex } = regex;
|
|
66
32
|
regex.lastIndex++;
|
|
67
33
|
lastIndex = newIndex + 1;
|
|
68
|
-
// Prevent advancing beyond string length
|
|
69
34
|
if (regex.lastIndex > line.length)
|
|
70
35
|
break;
|
|
71
36
|
}
|
|
@@ -77,11 +42,10 @@ function countRegexMatches(line, regex, timeoutMs = REGEX_MATCH_TIMEOUT_MS) {
|
|
|
77
42
|
}
|
|
78
43
|
lastIndex = currentIndex;
|
|
79
44
|
}
|
|
80
|
-
// Hybrid timeout check for both fast and slow regex patterns
|
|
81
45
|
const shouldCheckTimeout = (count > 0 && count % 10 === 0) ||
|
|
82
46
|
(iterations > 0 && iterations % 50 === 0);
|
|
83
47
|
if (shouldCheckTimeout && Date.now() > deadline) {
|
|
84
|
-
return -1;
|
|
48
|
+
return -1;
|
|
85
49
|
}
|
|
86
50
|
// Safety check for runaway regex
|
|
87
51
|
if (iterations > maxIterations) {
|
|
@@ -90,18 +54,14 @@ function countRegexMatches(line, regex, timeoutMs = REGEX_MATCH_TIMEOUT_MS) {
|
|
|
90
54
|
}
|
|
91
55
|
return count;
|
|
92
56
|
}
|
|
93
|
-
// Check if regex is simple enough to be safe without full ReDoS check
|
|
94
57
|
export function isSimpleSafePattern(pattern) {
|
|
95
|
-
// Validate input
|
|
96
58
|
if (typeof pattern !== 'string' || pattern.length === 0) {
|
|
97
59
|
return false;
|
|
98
60
|
}
|
|
99
|
-
// Patterns with nested quantifiers are the main ReDoS concern
|
|
100
61
|
const nestedQuantifierPattern = /[+*?}]\s*\)\s*[+*?{]/;
|
|
101
62
|
if (nestedQuantifierPattern.test(pattern)) {
|
|
102
63
|
return false;
|
|
103
64
|
}
|
|
104
|
-
// Check for high repetition counts that safe-regex2 would flag (default limit is 25)
|
|
105
65
|
const highRepetitionPattern = /\{(\d+)(?:,\d*)?\}/g;
|
|
106
66
|
let match;
|
|
107
67
|
while ((match = highRepetitionPattern.exec(pattern)) !== null) {
|
|
@@ -109,14 +69,12 @@ export function isSimpleSafePattern(pattern) {
|
|
|
109
69
|
if (countStr === undefined)
|
|
110
70
|
continue;
|
|
111
71
|
const count = parseInt(countStr, 10);
|
|
112
|
-
// Check for NaN and high values
|
|
113
72
|
if (Number.isNaN(count) || count >= 25) {
|
|
114
73
|
return false;
|
|
115
74
|
}
|
|
116
75
|
}
|
|
117
76
|
return true;
|
|
118
77
|
}
|
|
119
|
-
// Process pending matches to add context-after lines
|
|
120
78
|
function updatePendingMatches(pendingMatches, trimmedLine) {
|
|
121
79
|
for (const pending of pendingMatches) {
|
|
122
80
|
if (pending.afterNeeded > 0) {
|
|
@@ -125,16 +83,13 @@ function updatePendingMatches(pendingMatches, trimmedLine) {
|
|
|
125
83
|
pending.afterNeeded--;
|
|
126
84
|
}
|
|
127
85
|
}
|
|
128
|
-
// Remove completed pending matches from the front
|
|
129
86
|
while (pendingMatches.length > 0 && pendingMatches[0]?.afterNeeded === 0) {
|
|
130
87
|
pendingMatches.shift();
|
|
131
88
|
}
|
|
132
89
|
}
|
|
133
|
-
// Trim and truncate line content for storage
|
|
134
90
|
function prepareTrimmedLine(line) {
|
|
135
91
|
return line.trim().substring(0, MAX_LINE_CONTENT_LENGTH);
|
|
136
92
|
}
|
|
137
|
-
// Prepare final search pattern with optional literal escaping and word boundaries
|
|
138
93
|
export function prepareSearchPattern(searchPattern, options) {
|
|
139
94
|
let finalPattern = searchPattern;
|
|
140
95
|
if (options.isLiteral) {
|
|
@@ -146,7 +101,7 @@ export function prepareSearchPattern(searchPattern, options) {
|
|
|
146
101
|
return finalPattern;
|
|
147
102
|
}
|
|
148
103
|
export async function scanFileForContent(filePath, regex, options) {
|
|
149
|
-
const { maxResults, contextLines, deadlineMs, currentMatchCount } = options;
|
|
104
|
+
const { maxResults, contextLines, deadlineMs, currentMatchCount, isLiteral, searchString, caseSensitive, } = options;
|
|
150
105
|
const matches = [];
|
|
151
106
|
let linesSkippedDueToRegexTimeout = 0;
|
|
152
107
|
let fileHadMatches = false;
|
|
@@ -156,7 +111,7 @@ export async function scanFileForContent(filePath, regex, options) {
|
|
|
156
111
|
crlfDelay: Infinity,
|
|
157
112
|
});
|
|
158
113
|
let lineNumber = 0;
|
|
159
|
-
const
|
|
114
|
+
const contextBuffer = [];
|
|
160
115
|
const pendingMatches = [];
|
|
161
116
|
try {
|
|
162
117
|
for await (const line of rl) {
|
|
@@ -167,10 +122,16 @@ export async function scanFileForContent(filePath, regex, options) {
|
|
|
167
122
|
break;
|
|
168
123
|
const trimmedLine = prepareTrimmedLine(line);
|
|
169
124
|
updatePendingMatches(pendingMatches, trimmedLine);
|
|
170
|
-
const matchCount =
|
|
125
|
+
const matchCount = isLiteral && searchString
|
|
126
|
+
? countLiteralMatches(line, searchString, caseSensitive ?? false)
|
|
127
|
+
: countRegexMatches(line, regex);
|
|
171
128
|
if (matchCount < 0) {
|
|
172
129
|
linesSkippedDueToRegexTimeout++;
|
|
173
|
-
|
|
130
|
+
if (contextLines > 0) {
|
|
131
|
+
contextBuffer.push(trimmedLine);
|
|
132
|
+
if (contextBuffer.length > contextLines)
|
|
133
|
+
contextBuffer.shift();
|
|
134
|
+
}
|
|
174
135
|
continue;
|
|
175
136
|
}
|
|
176
137
|
if (matchCount > 0) {
|
|
@@ -181,9 +142,8 @@ export async function scanFileForContent(filePath, regex, options) {
|
|
|
181
142
|
content: trimmedLine,
|
|
182
143
|
matchCount,
|
|
183
144
|
};
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
newMatch.contextBefore = contextBefore;
|
|
145
|
+
if (contextBuffer.length > 0) {
|
|
146
|
+
newMatch.contextBefore = [...contextBuffer];
|
|
187
147
|
}
|
|
188
148
|
matches.push(newMatch);
|
|
189
149
|
if (contextLines > 0) {
|
|
@@ -193,7 +153,11 @@ export async function scanFileForContent(filePath, regex, options) {
|
|
|
193
153
|
});
|
|
194
154
|
}
|
|
195
155
|
}
|
|
196
|
-
|
|
156
|
+
if (contextLines > 0) {
|
|
157
|
+
contextBuffer.push(trimmedLine);
|
|
158
|
+
if (contextBuffer.length > contextLines)
|
|
159
|
+
contextBuffer.shift();
|
|
160
|
+
}
|
|
197
161
|
}
|
|
198
162
|
}
|
|
199
163
|
finally {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-helpers.js","sourceRoot":"","sources":["../../src/lib/search-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"search-helpers.js","sourceRoot":"","sources":["../../src/lib/search-helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -111,13 +111,13 @@ export declare const SearchFilesOutputSchema: {
|
|
|
111
111
|
size: z.ZodOptional<z.ZodNumber>;
|
|
112
112
|
modified: z.ZodOptional<z.ZodString>;
|
|
113
113
|
}, "strip", z.ZodTypeAny, {
|
|
114
|
-
path: string;
|
|
115
114
|
type: "file" | "directory" | "symlink" | "other";
|
|
115
|
+
path: string;
|
|
116
116
|
size?: number | undefined;
|
|
117
117
|
modified?: string | undefined;
|
|
118
118
|
}, {
|
|
119
|
-
path: string;
|
|
120
119
|
type: "file" | "directory" | "symlink" | "other";
|
|
120
|
+
path: string;
|
|
121
121
|
size?: number | undefined;
|
|
122
122
|
modified?: string | undefined;
|
|
123
123
|
}>, "many">>;
|
|
@@ -197,13 +197,13 @@ export declare const ReadMultipleFilesOutputSchema: {
|
|
|
197
197
|
succeeded: z.ZodNumber;
|
|
198
198
|
failed: z.ZodNumber;
|
|
199
199
|
}, "strip", z.ZodTypeAny, {
|
|
200
|
-
failed: number;
|
|
201
200
|
total: number;
|
|
202
201
|
succeeded: number;
|
|
203
|
-
}, {
|
|
204
202
|
failed: number;
|
|
203
|
+
}, {
|
|
205
204
|
total: number;
|
|
206
205
|
succeeded: number;
|
|
206
|
+
failed: number;
|
|
207
207
|
}>>;
|
|
208
208
|
error: z.ZodOptional<z.ZodObject<{
|
|
209
209
|
code: z.ZodString;
|
|
@@ -237,27 +237,27 @@ export declare const GetFileInfoOutputSchema: {
|
|
|
237
237
|
mimeType: z.ZodOptional<z.ZodString>;
|
|
238
238
|
symlinkTarget: z.ZodOptional<z.ZodString>;
|
|
239
239
|
}, "strip", z.ZodTypeAny, {
|
|
240
|
-
path: string;
|
|
241
240
|
name: string;
|
|
242
|
-
type: "file" | "directory" | "symlink" | "other";
|
|
243
241
|
size: number;
|
|
244
242
|
modified: string;
|
|
243
|
+
type: "file" | "directory" | "symlink" | "other";
|
|
244
|
+
path: string;
|
|
245
245
|
permissions: string;
|
|
246
|
-
mimeType?: string | undefined;
|
|
247
246
|
created?: string | undefined;
|
|
248
247
|
accessed?: string | undefined;
|
|
248
|
+
mimeType?: string | undefined;
|
|
249
249
|
symlinkTarget?: string | undefined;
|
|
250
250
|
isHidden?: boolean | undefined;
|
|
251
251
|
}, {
|
|
252
|
-
path: string;
|
|
253
252
|
name: string;
|
|
254
|
-
type: "file" | "directory" | "symlink" | "other";
|
|
255
253
|
size: number;
|
|
256
254
|
modified: string;
|
|
255
|
+
type: "file" | "directory" | "symlink" | "other";
|
|
256
|
+
path: string;
|
|
257
257
|
permissions: string;
|
|
258
|
-
mimeType?: string | undefined;
|
|
259
258
|
created?: string | undefined;
|
|
260
259
|
accessed?: string | undefined;
|
|
260
|
+
mimeType?: string | undefined;
|
|
261
261
|
symlinkTarget?: string | undefined;
|
|
262
262
|
isHidden?: boolean | undefined;
|
|
263
263
|
}>>;
|
|
@@ -364,21 +364,21 @@ export declare const AnalyzeDirectoryOutputSchema: {
|
|
|
364
364
|
path: z.ZodString;
|
|
365
365
|
size: z.ZodNumber;
|
|
366
366
|
}, "strip", z.ZodTypeAny, {
|
|
367
|
-
path: string;
|
|
368
367
|
size: number;
|
|
369
|
-
}, {
|
|
370
368
|
path: string;
|
|
369
|
+
}, {
|
|
371
370
|
size: number;
|
|
371
|
+
path: string;
|
|
372
372
|
}>, "many">>;
|
|
373
373
|
recentlyModified: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
374
374
|
path: z.ZodString;
|
|
375
375
|
modified: z.ZodString;
|
|
376
376
|
}, "strip", z.ZodTypeAny, {
|
|
377
|
-
path: string;
|
|
378
377
|
modified: string;
|
|
379
|
-
}, {
|
|
380
378
|
path: string;
|
|
379
|
+
}, {
|
|
381
380
|
modified: string;
|
|
381
|
+
path: string;
|
|
382
382
|
}>, "many">>;
|
|
383
383
|
summary: z.ZodOptional<z.ZodObject<{
|
|
384
384
|
truncated: z.ZodOptional<z.ZodBoolean>;
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKpE,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKpE,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAiExE,wBAAsB,SAAS,IAAI,OAAO,CAAC,eAAe,CAAC,CAkC1D;AAsBD,wBAAgB,YAAY,CAAC,OAAO,GAAE,aAAkB,GAAG,SAAS,CAmBnE;AAED,wBAAsB,WAAW,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BlE"}
|
package/dist/server.js
CHANGED
|
@@ -5,25 +5,20 @@ import { fileURLToPath } from 'node:url';
|
|
|
5
5
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
6
6
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
7
7
|
import { RootsListChangedNotificationSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
8
|
-
import { setMcpServerInstance } from './lib/mcp-logger.js';
|
|
9
8
|
import { normalizePath } from './lib/path-utils.js';
|
|
10
9
|
import { getAllowedDirectories, getValidRootDirectories, setAllowedDirectories, } from './lib/path-validation.js';
|
|
11
10
|
import { registerAllTools } from './tools/index.js';
|
|
12
|
-
// Get version from package.json
|
|
13
11
|
const require = createRequire(import.meta.url);
|
|
14
12
|
const packageJson = require('../package.json');
|
|
15
13
|
const SERVER_VERSION = packageJson.version;
|
|
16
|
-
// Load server instructions
|
|
17
14
|
const currentDir = path.dirname(fileURLToPath(import.meta.url));
|
|
18
15
|
let serverInstructions = '';
|
|
19
16
|
try {
|
|
20
17
|
serverInstructions = await fs.readFile(path.join(currentDir, 'instructions.md'), 'utf-8');
|
|
21
18
|
}
|
|
22
19
|
catch (error) {
|
|
23
|
-
// Instructions file not found or unreadable
|
|
24
20
|
console.error('[WARNING] Failed to load instructions.md:', error instanceof Error ? error.message : String(error));
|
|
25
21
|
}
|
|
26
|
-
// Reserved device names on Windows that should be rejected
|
|
27
22
|
const RESERVED_DEVICE_NAMES = new Set([
|
|
28
23
|
'CON',
|
|
29
24
|
'PRN',
|
|
@@ -49,11 +44,9 @@ const RESERVED_DEVICE_NAMES = new Set([
|
|
|
49
44
|
'LPT9',
|
|
50
45
|
]);
|
|
51
46
|
function validateCliPath(inputPath) {
|
|
52
|
-
// Check for null bytes (path injection)
|
|
53
47
|
if (inputPath.includes('\0')) {
|
|
54
48
|
throw new Error('Path contains null bytes');
|
|
55
49
|
}
|
|
56
|
-
// Check for reserved device names on Windows
|
|
57
50
|
if (process.platform === 'win32') {
|
|
58
51
|
const basename = path.basename(inputPath).split('.')[0]?.toUpperCase();
|
|
59
52
|
if (basename && RESERVED_DEVICE_NAMES.has(basename)) {
|
|
@@ -63,13 +56,11 @@ function validateCliPath(inputPath) {
|
|
|
63
56
|
}
|
|
64
57
|
export async function parseArgs() {
|
|
65
58
|
const args = process.argv.slice(2);
|
|
66
|
-
// Check for --allow-cwd flag
|
|
67
59
|
const allowCwdIndex = args.indexOf('--allow-cwd');
|
|
68
60
|
const allowCwd = allowCwdIndex !== -1;
|
|
69
61
|
if (allowCwd) {
|
|
70
62
|
args.splice(allowCwdIndex, 1);
|
|
71
63
|
}
|
|
72
|
-
// Allow empty args - will fall back to CWD or roots protocol
|
|
73
64
|
if (args.length === 0) {
|
|
74
65
|
return { allowedDirs: [], allowCwd };
|
|
75
66
|
}
|
|
@@ -93,7 +84,6 @@ export async function parseArgs() {
|
|
|
93
84
|
}
|
|
94
85
|
return { allowedDirs: validatedDirs, allowCwd };
|
|
95
86
|
}
|
|
96
|
-
// Store server options for use in startServer
|
|
97
87
|
let serverOptions = {};
|
|
98
88
|
async function updateRootsFromClient(server) {
|
|
99
89
|
try {
|
|
@@ -108,7 +98,7 @@ async function updateRootsFromClient(server) {
|
|
|
108
98
|
}
|
|
109
99
|
}
|
|
110
100
|
catch {
|
|
111
|
-
//
|
|
101
|
+
// Roots protocol may not be supported
|
|
112
102
|
}
|
|
113
103
|
}
|
|
114
104
|
export function createServer(options = {}) {
|
|
@@ -131,14 +121,10 @@ export async function startServer(server) {
|
|
|
131
121
|
await updateRootsFromClient(server);
|
|
132
122
|
});
|
|
133
123
|
await server.connect(transport);
|
|
134
|
-
// Set server instance for MCP logging support
|
|
135
|
-
setMcpServerInstance(server);
|
|
136
|
-
// Update allowed directories from roots protocol
|
|
137
124
|
await updateRootsFromClient(server);
|
|
138
125
|
const dirs = getAllowedDirectories();
|
|
139
126
|
if (dirs.length === 0) {
|
|
140
127
|
if (serverOptions.allowCwd) {
|
|
141
|
-
// Fall back to current working directory only if explicitly allowed
|
|
142
128
|
const cwd = normalizePath(process.cwd());
|
|
143
129
|
setAllowedDirectories([cwd]);
|
|
144
130
|
console.error('No directories specified. Using current working directory:');
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,kCAAkC,EAAE,MAAM,oCAAoC,CAAC;AAIxF,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyze-directory.d.ts","sourceRoot":"","sources":["../../src/tools/analyze-directory.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAazE,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"analyze-directory.d.ts","sourceRoot":"","sources":["../../src/tools/analyze-directory.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAazE,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAsEpE"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as pathModule from 'node:path';
|
|
2
2
|
import { createErrorResponse, ErrorCode } from '../lib/errors.js';
|
|
3
3
|
import { analyzeDirectory } from '../lib/file-operations.js';
|
|
4
4
|
import { formatDirectoryAnalysis, formatOperationSummary, } from '../lib/formatters.js';
|
|
@@ -17,9 +17,9 @@ export function registerAnalyzeDirectoryTool(server) {
|
|
|
17
17
|
idempotentHint: true,
|
|
18
18
|
openWorldHint: true,
|
|
19
19
|
},
|
|
20
|
-
}, async ({ path, maxDepth, topN, excludePatterns, includeHidden }) => {
|
|
20
|
+
}, async ({ path: dirPath, maxDepth, topN, excludePatterns, includeHidden, }) => {
|
|
21
21
|
try {
|
|
22
|
-
const result = await analyzeDirectory(
|
|
22
|
+
const result = await analyzeDirectory(dirPath, {
|
|
23
23
|
maxDepth,
|
|
24
24
|
topN,
|
|
25
25
|
excludePatterns,
|
|
@@ -33,11 +33,11 @@ export function registerAnalyzeDirectoryTool(server) {
|
|
|
33
33
|
totalSize: result.analysis.totalSize,
|
|
34
34
|
fileTypes: result.analysis.fileTypes,
|
|
35
35
|
largestFiles: result.analysis.largestFiles.map((f) => ({
|
|
36
|
-
path:
|
|
36
|
+
path: pathModule.relative(result.analysis.path, f.path),
|
|
37
37
|
size: f.size,
|
|
38
38
|
})),
|
|
39
39
|
recentlyModified: result.analysis.recentlyModified.map((f) => ({
|
|
40
|
-
path:
|
|
40
|
+
path: pathModule.relative(result.analysis.path, f.path),
|
|
41
41
|
modified: f.modified.toISOString(),
|
|
42
42
|
})),
|
|
43
43
|
summary: {
|
|
@@ -58,7 +58,7 @@ export function registerAnalyzeDirectoryTool(server) {
|
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
60
|
catch (error) {
|
|
61
|
-
return createErrorResponse(error, ErrorCode.E_NOT_DIRECTORY,
|
|
61
|
+
return createErrorResponse(error, ErrorCode.E_NOT_DIRECTORY, dirPath);
|
|
62
62
|
}
|
|
63
63
|
});
|
|
64
64
|
}
|