@j0hanz/filesystem-mcp 1.14.0 → 1.15.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/LICENSE +21 -0
- package/README.md +143 -71
- package/dist/cli.js +2 -2
- package/dist/completions.js +54 -51
- package/dist/config.d.ts +13 -13
- package/dist/config.js +12 -12
- package/dist/index.js +1 -1
- package/dist/lib/abort.d.ts +7 -0
- package/dist/lib/abort.js +81 -0
- package/dist/lib/constants.d.ts +3 -1
- package/dist/lib/constants.js +8 -2
- package/dist/lib/errors.d.ts +7 -3
- package/dist/lib/errors.js +59 -39
- package/dist/lib/file-operations/core.d.ts +3 -3
- package/dist/lib/file-operations/core.js +23 -20
- package/dist/lib/file-operations/metadata.d.ts +2 -2
- package/dist/lib/file-operations/metadata.js +60 -19
- package/dist/lib/file-operations/search.js +83 -84
- package/dist/lib/file-operations/traversal.js +13 -15
- package/dist/lib/fs-helpers.d.ts +3 -10
- package/dist/lib/fs-helpers.js +20 -98
- package/dist/lib/globs.js +1 -1
- package/dist/lib/logger.d.ts +28 -0
- package/dist/lib/logger.js +91 -0
- package/dist/lib/observability.d.ts +7 -0
- package/dist/lib/observability.js +19 -9
- package/dist/lib/paths.js +55 -55
- package/dist/lib/resource-store.js +4 -4
- package/dist/lib/utils.d.ts +0 -12
- package/dist/lib/utils.js +0 -13
- package/dist/resources/generated-instructions.js +40 -31
- package/dist/resources/tool-catalog.js +32 -26
- package/dist/resources/tool-info.js +34 -29
- package/dist/resources/workflows.js +39 -18
- package/dist/resources.d.ts +1 -1
- package/dist/resources.js +4 -4
- package/dist/schemas.d.ts +66 -66
- package/dist/schemas.js +21 -44
- package/dist/server/bootstrap.d.ts +12 -11
- package/dist/server/bootstrap.js +95 -86
- package/dist/server/roots-manager.d.ts +5 -2
- package/dist/server/roots-manager.js +8 -6
- package/dist/server/task-store.d.ts +10 -0
- package/dist/server/task-store.js +73 -0
- package/dist/tools/apply-patch.js +26 -18
- package/dist/tools/calculate-hash.js +11 -22
- package/dist/tools/create-directory.js +10 -8
- package/dist/tools/delete-file.js +17 -15
- package/dist/tools/diff-files.js +15 -15
- package/dist/tools/edit-file.js +7 -4
- package/dist/tools/list-directory.js +6 -6
- package/dist/tools/move-file.js +98 -81
- package/dist/tools/read-multiple.js +4 -4
- package/dist/tools/read.js +5 -5
- package/dist/tools/replace-in-files.js +20 -23
- package/dist/tools/roots.js +1 -1
- package/dist/tools/search-content.js +32 -41
- package/dist/tools/search-files.js +54 -41
- package/dist/tools/shared.d.ts +3 -0
- package/dist/tools/shared.js +70 -28
- package/dist/tools/stat-many.js +11 -7
- package/dist/tools/stat.js +4 -4
- package/dist/tools/task-support.d.ts +10 -9
- package/dist/tools/task-support.js +94 -23
- package/dist/tools/tree.js +3 -3
- package/dist/tools/write-file.js +10 -7
- package/package.json +9 -9
|
@@ -63,14 +63,14 @@ export function buildCoreContextPack() {
|
|
|
63
63
|
const annotations = e.annotations ? ` ${e.annotations.join(' ')}` : '';
|
|
64
64
|
return `| \`${e.name}\` | ${e.description}${annotations} |`;
|
|
65
65
|
});
|
|
66
|
-
return
|
|
66
|
+
return `## Tool Summary\n\n| Tool | Purpose |\n|------|---------|\n${rows.join('\n')}`;
|
|
67
67
|
}
|
|
68
68
|
export function getSharedConstraints() {
|
|
69
69
|
return [
|
|
70
|
-
'
|
|
71
|
-
'Sensitive paths are
|
|
72
|
-
`
|
|
73
|
-
'
|
|
70
|
+
'Operate within allowed roots only (negotiated at startup via CLI).',
|
|
71
|
+
'Sensitive file paths (e.g. .env, *.pem, *id_rsa*) are denied by default.',
|
|
72
|
+
`Enforced limits: max file size ${Math.floor(MAX_TEXT_FILE_SIZE / 1024 / 1024)} MB, file search cap ${MAX_SEARCH_RESULTS} results, content search cap ${DEFAULT_SEARCH_CONTENT_RESULTS} matches.`,
|
|
73
|
+
'When a response includes `resourceUri`, call `resources/read` immediately — cached results expire on server restart.',
|
|
74
74
|
];
|
|
75
75
|
}
|
|
76
76
|
function formatTaskSupportLabel(taskSupport) {
|
|
@@ -86,6 +86,14 @@ function formatTaskSupportLabel(taskSupport) {
|
|
|
86
86
|
function toJsonSchemaObject(schema, io = 'output') {
|
|
87
87
|
return z.toJSONSchema(schema, { io });
|
|
88
88
|
}
|
|
89
|
+
function summarizeArrayType(schema) {
|
|
90
|
+
if (Array.isArray(schema.prefixItems) && schema.prefixItems.length > 0) {
|
|
91
|
+
const itemTypes = schema.prefixItems.map(summarizeSchemaType).join(', ');
|
|
92
|
+
return `tuple<${itemTypes}>`;
|
|
93
|
+
}
|
|
94
|
+
const itemType = schema.items ? summarizeSchemaType(schema.items) : 'unknown';
|
|
95
|
+
return `array<${itemType}>`;
|
|
96
|
+
}
|
|
89
97
|
function summarizeSchemaType(schema) {
|
|
90
98
|
if (Array.isArray(schema.enum) && schema.enum.length > 0) {
|
|
91
99
|
return `enum(${schema.enum.map((value) => JSON.stringify(value)).join(', ')})`;
|
|
@@ -100,14 +108,7 @@ function summarizeSchemaType(schema) {
|
|
|
100
108
|
return schema.oneOf.map(summarizeSchemaType).join(' | ');
|
|
101
109
|
}
|
|
102
110
|
if (schema.type === 'array') {
|
|
103
|
-
|
|
104
|
-
const itemTypes = schema.prefixItems.map(summarizeSchemaType).join(', ');
|
|
105
|
-
return `tuple<${itemTypes}>`;
|
|
106
|
-
}
|
|
107
|
-
const itemType = schema.items
|
|
108
|
-
? summarizeSchemaType(schema.items)
|
|
109
|
-
: 'unknown';
|
|
110
|
-
return `array<${itemType}>`;
|
|
111
|
+
return summarizeArrayType(schema);
|
|
111
112
|
}
|
|
112
113
|
if (schema.type === 'object' && schema.additionalProperties === false) {
|
|
113
114
|
return 'object (strict)';
|
|
@@ -117,16 +118,23 @@ function summarizeSchemaType(schema) {
|
|
|
117
118
|
}
|
|
118
119
|
return 'unknown';
|
|
119
120
|
}
|
|
121
|
+
function formatFieldLabel(label) {
|
|
122
|
+
return label
|
|
123
|
+
.split('_')
|
|
124
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
125
|
+
.join(' ');
|
|
126
|
+
}
|
|
120
127
|
function buildSchemaFieldLines(label, schema) {
|
|
128
|
+
const heading = `**${formatFieldLabel(label)}:**`;
|
|
121
129
|
if (!schema) {
|
|
122
|
-
return [
|
|
130
|
+
return [heading, '- none'];
|
|
123
131
|
}
|
|
124
132
|
const io = label === 'input_fields' ? 'input' : 'output';
|
|
125
133
|
const jsonSchema = toJsonSchemaObject(schema, io);
|
|
126
134
|
const properties = jsonSchema.properties ?? {};
|
|
127
135
|
const required = new Set(jsonSchema.required ?? []);
|
|
128
136
|
const fieldNames = Object.keys(properties);
|
|
129
|
-
const lines = [
|
|
137
|
+
const lines = [heading];
|
|
130
138
|
if (typeof jsonSchema.description === 'string' &&
|
|
131
139
|
jsonSchema.description.length > 0) {
|
|
132
140
|
lines.push(`- Schema constraints: ${jsonSchema.description}`);
|
|
@@ -135,7 +143,7 @@ function buildSchemaFieldLines(label, schema) {
|
|
|
135
143
|
lines.push('- Unknown fields are rejected (`additionalProperties: false`).');
|
|
136
144
|
}
|
|
137
145
|
if (fieldNames.length === 0) {
|
|
138
|
-
lines.push('- object with no fields'
|
|
146
|
+
lines.push('- object with no fields');
|
|
139
147
|
return lines;
|
|
140
148
|
}
|
|
141
149
|
lines.push(...fieldNames.map((fieldName) => {
|
|
@@ -147,7 +155,7 @@ function buildSchemaFieldLines(label, schema) {
|
|
|
147
155
|
? fieldSchema.description
|
|
148
156
|
: 'No description.';
|
|
149
157
|
return `- ${fieldName} (${type}, ${requiredLabel}): ${description}`;
|
|
150
|
-
})
|
|
158
|
+
}));
|
|
151
159
|
return lines;
|
|
152
160
|
}
|
|
153
161
|
export function buildToolInfo(name) {
|
|
@@ -165,37 +173,34 @@ export function buildToolInfo(name) {
|
|
|
165
173
|
if (contract.annotations?.openWorldHint)
|
|
166
174
|
annotationLines.push('- openWorldHint: true');
|
|
167
175
|
const lines = [
|
|
168
|
-
|
|
169
|
-
|
|
176
|
+
`---`,
|
|
177
|
+
`# ${entry.name}`,
|
|
170
178
|
'',
|
|
171
|
-
|
|
172
|
-
|
|
179
|
+
`**Title:** ${entry.title}`,
|
|
180
|
+
`**Description:** ${entry.description}`,
|
|
173
181
|
'',
|
|
174
|
-
'
|
|
182
|
+
'**Execution:**',
|
|
175
183
|
`- taskSupport: ${formatTaskSupportLabel(contract.taskSupport)}`,
|
|
176
|
-
'</execution>',
|
|
177
184
|
'',
|
|
178
185
|
...buildSchemaFieldLines('input_fields', contract.inputSchema),
|
|
179
186
|
'',
|
|
180
187
|
...buildSchemaFieldLines('output_fields', contract.outputSchema),
|
|
181
188
|
];
|
|
182
189
|
if (annotationLines.length > 0) {
|
|
183
|
-
lines.push('', '
|
|
190
|
+
lines.push('', '**Behavior:**', ...annotationLines);
|
|
184
191
|
}
|
|
185
192
|
if (entry.nuances && entry.nuances.length > 0) {
|
|
186
|
-
lines.push('', '
|
|
193
|
+
lines.push('', '**Usage Notes:**');
|
|
187
194
|
for (const nuance of entry.nuances) {
|
|
188
195
|
lines.push(`- ${nuance}`);
|
|
189
196
|
}
|
|
190
|
-
lines.push('</nuances>');
|
|
191
197
|
}
|
|
192
198
|
if (entry.gotchas && entry.gotchas.length > 0) {
|
|
193
|
-
lines.push('', '
|
|
199
|
+
lines.push('', '**Warnings:**');
|
|
194
200
|
for (const gotcha of entry.gotchas) {
|
|
195
201
|
lines.push(`- ${gotcha}`);
|
|
196
202
|
}
|
|
197
|
-
lines.push('</gotchas>');
|
|
198
203
|
}
|
|
199
|
-
lines.push('
|
|
204
|
+
lines.push('---');
|
|
200
205
|
return lines.join('\n');
|
|
201
206
|
}
|
|
@@ -18,22 +18,43 @@ export function buildWorkflowGuide() {
|
|
|
18
18
|
'rm',
|
|
19
19
|
'mkdir',
|
|
20
20
|
]));
|
|
21
|
-
return
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
1.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
1. \`
|
|
37
|
-
|
|
38
|
-
|
|
21
|
+
return `## Workflows
|
|
22
|
+
|
|
23
|
+
### A: Explore — Discover directory layout or file content
|
|
24
|
+
|
|
25
|
+
**Tools:** ${exploreTools}
|
|
26
|
+
|
|
27
|
+
1. Start with \`roots\` to identify allowed directories.
|
|
28
|
+
2. Use \`ls\` or \`tree\` to map structure, then \`stat\` or \`read\` for details.
|
|
29
|
+
|
|
30
|
+
> Resolve paths before acting. Never assume a path exists.
|
|
31
|
+
|
|
32
|
+
### B: Search — Find files by name or content
|
|
33
|
+
|
|
34
|
+
**Tools:** ${searchTools}
|
|
35
|
+
|
|
36
|
+
1. Use \`find\` for file name/glob matching.
|
|
37
|
+
2. Use \`grep\` for content search (supports regex).
|
|
38
|
+
3. Use \`read\` to inspect matched files.
|
|
39
|
+
|
|
40
|
+
> Use \`grep\` for content, \`find\` for filenames. Do not conflate them.
|
|
41
|
+
|
|
42
|
+
### C: Edit — Modify files or directory layout
|
|
43
|
+
|
|
44
|
+
**Tools:** ${editTools}
|
|
45
|
+
|
|
46
|
+
1. Use \`edit\` for targeted single-file changes (exact text match → replace).
|
|
47
|
+
2. Use \`search_and_replace\` for bulk changes across multiple files.
|
|
48
|
+
3. Use \`mv\`, \`rm\`, \`mkdir\` for structural changes.
|
|
49
|
+
|
|
50
|
+
> Confirm destructive operations (\`write\`, \`mv\`, \`rm\`, bulk replace) before executing.
|
|
51
|
+
|
|
52
|
+
### D: Patch — Generate and apply unified diffs
|
|
53
|
+
|
|
54
|
+
1. Generate: \`diff_files(original, modified)\`.
|
|
55
|
+
2. Validate: \`apply_patch(patch, dryRun: true)\`.
|
|
56
|
+
3. Apply: \`apply_patch(patch)\`.
|
|
57
|
+
|
|
58
|
+
> Multi-file patches: set \`path\` to the base directory. Results are reported per file.
|
|
59
|
+
`;
|
|
39
60
|
}
|
package/dist/resources.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import type { ResourceStore } from './lib/resource-store.js';
|
|
3
3
|
import { type IconInfo } from './tools/shared.js';
|
|
4
4
|
export declare function registerInstructionResource(server: McpServer, instructions: string, iconInfo?: IconInfo): void;
|
package/dist/resources.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
1
|
+
import { ResourceTemplate, } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import { ErrorCode, McpError } from './lib/errors.js';
|
|
3
3
|
import { globalMetrics } from './lib/observability.js';
|
|
4
4
|
import { buildToolCatalog } from './resources/tool-catalog.js';
|
|
@@ -104,7 +104,7 @@ export function registerResultResources(server, store, iconInfo) {
|
|
|
104
104
|
}, iconInfo), (uri, variables) => {
|
|
105
105
|
const { id } = variables;
|
|
106
106
|
if (typeof id !== 'string' || id.length === 0) {
|
|
107
|
-
throw new McpError(ErrorCode.
|
|
107
|
+
throw new McpError(ErrorCode.NOT_FOUND, 'Cached result expired. Re-run the tool to regenerate.');
|
|
108
108
|
}
|
|
109
109
|
const entry = store.getText(uri.toString());
|
|
110
110
|
return {
|
|
@@ -130,11 +130,11 @@ export function registerToolInfoResource(server, iconInfo) {
|
|
|
130
130
|
}, iconInfo), (uri, variables) => {
|
|
131
131
|
const { name } = variables;
|
|
132
132
|
if (typeof name !== 'string' || name.length === 0) {
|
|
133
|
-
throw new McpError(ErrorCode.
|
|
133
|
+
throw new McpError(ErrorCode.INVALID_INPUT, 'Tool name is required');
|
|
134
134
|
}
|
|
135
135
|
const content = buildToolInfo(name);
|
|
136
136
|
if (content === undefined) {
|
|
137
|
-
throw new McpError(ErrorCode.
|
|
137
|
+
throw new McpError(ErrorCode.INVALID_INPUT, `Tool not found: ${name}`);
|
|
138
138
|
}
|
|
139
139
|
return {
|
|
140
140
|
contents: [
|
package/dist/schemas.d.ts
CHANGED
|
@@ -22,9 +22,9 @@ export declare const ListDirectoryInputSchema: z.ZodObject<{
|
|
|
22
22
|
maxDepth: z.ZodOptional<z.ZodInt>;
|
|
23
23
|
maxEntries: z.ZodDefault<z.ZodOptional<z.ZodInt>>;
|
|
24
24
|
sortBy: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
|
|
25
|
-
name: "name";
|
|
26
|
-
size: "size";
|
|
27
25
|
type: "type";
|
|
26
|
+
size: "size";
|
|
27
|
+
name: "name";
|
|
28
28
|
modified: "modified";
|
|
29
29
|
}>>>;
|
|
30
30
|
pattern: z.ZodOptional<z.ZodString>;
|
|
@@ -39,8 +39,8 @@ export declare const SearchFilesInputSchema: z.ZodObject<{
|
|
|
39
39
|
includeIgnored: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
40
40
|
includeHidden: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
41
41
|
sortBy: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
|
|
42
|
-
name: "name";
|
|
43
42
|
size: "size";
|
|
43
|
+
name: "name";
|
|
44
44
|
path: "path";
|
|
45
45
|
modified: "modified";
|
|
46
46
|
}>>>;
|
|
@@ -208,18 +208,18 @@ export declare const ReadMultipleFilesOutputSchema: z.ZodObject<{
|
|
|
208
208
|
}>>;
|
|
209
209
|
error: z.ZodOptional<z.ZodObject<{
|
|
210
210
|
code: z.ZodEnum<{
|
|
211
|
-
readonly
|
|
212
|
-
readonly
|
|
213
|
-
readonly
|
|
214
|
-
readonly
|
|
215
|
-
readonly
|
|
216
|
-
readonly
|
|
217
|
-
readonly
|
|
218
|
-
readonly
|
|
219
|
-
readonly
|
|
220
|
-
readonly
|
|
221
|
-
readonly
|
|
222
|
-
readonly
|
|
211
|
+
readonly ACCESS_DENIED: "ACCESS_DENIED";
|
|
212
|
+
readonly NOT_FOUND: "NOT_FOUND";
|
|
213
|
+
readonly NOT_FILE: "NOT_FILE";
|
|
214
|
+
readonly NOT_DIRECTORY: "NOT_DIRECTORY";
|
|
215
|
+
readonly TOO_LARGE: "TOO_LARGE";
|
|
216
|
+
readonly TIMEOUT: "TIMEOUT";
|
|
217
|
+
readonly CANCELLED: "CANCELLED";
|
|
218
|
+
readonly INVALID_PATTERN: "INVALID_PATTERN";
|
|
219
|
+
readonly INVALID_INPUT: "INVALID_INPUT";
|
|
220
|
+
readonly PERMISSION_DENIED: "PERMISSION_DENIED";
|
|
221
|
+
readonly SYMLINK_NOT_ALLOWED: "SYMLINK_NOT_ALLOWED";
|
|
222
|
+
readonly UNKNOWN: "UNKNOWN";
|
|
223
223
|
}>;
|
|
224
224
|
message: z.ZodString;
|
|
225
225
|
path: z.ZodOptional<z.ZodString>;
|
|
@@ -279,18 +279,18 @@ export declare const GetMultipleFileInfoOutputSchema: z.ZodObject<{
|
|
|
279
279
|
}, z.core.$strict>>;
|
|
280
280
|
error: z.ZodOptional<z.ZodObject<{
|
|
281
281
|
code: z.ZodEnum<{
|
|
282
|
-
readonly
|
|
283
|
-
readonly
|
|
284
|
-
readonly
|
|
285
|
-
readonly
|
|
286
|
-
readonly
|
|
287
|
-
readonly
|
|
288
|
-
readonly
|
|
289
|
-
readonly
|
|
290
|
-
readonly
|
|
291
|
-
readonly
|
|
292
|
-
readonly
|
|
293
|
-
readonly
|
|
282
|
+
readonly ACCESS_DENIED: "ACCESS_DENIED";
|
|
283
|
+
readonly NOT_FOUND: "NOT_FOUND";
|
|
284
|
+
readonly NOT_FILE: "NOT_FILE";
|
|
285
|
+
readonly NOT_DIRECTORY: "NOT_DIRECTORY";
|
|
286
|
+
readonly TOO_LARGE: "TOO_LARGE";
|
|
287
|
+
readonly TIMEOUT: "TIMEOUT";
|
|
288
|
+
readonly CANCELLED: "CANCELLED";
|
|
289
|
+
readonly INVALID_PATTERN: "INVALID_PATTERN";
|
|
290
|
+
readonly INVALID_INPUT: "INVALID_INPUT";
|
|
291
|
+
readonly PERMISSION_DENIED: "PERMISSION_DENIED";
|
|
292
|
+
readonly SYMLINK_NOT_ALLOWED: "SYMLINK_NOT_ALLOWED";
|
|
293
|
+
readonly UNKNOWN: "UNKNOWN";
|
|
294
294
|
}>;
|
|
295
295
|
message: z.ZodString;
|
|
296
296
|
path: z.ZodOptional<z.ZodString>;
|
|
@@ -354,18 +354,18 @@ export declare const MoveFileOutputSchema: z.ZodObject<{
|
|
|
354
354
|
source: z.ZodString;
|
|
355
355
|
error: z.ZodObject<{
|
|
356
356
|
code: z.ZodEnum<{
|
|
357
|
-
readonly
|
|
358
|
-
readonly
|
|
359
|
-
readonly
|
|
360
|
-
readonly
|
|
361
|
-
readonly
|
|
362
|
-
readonly
|
|
363
|
-
readonly
|
|
364
|
-
readonly
|
|
365
|
-
readonly
|
|
366
|
-
readonly
|
|
367
|
-
readonly
|
|
368
|
-
readonly
|
|
357
|
+
readonly ACCESS_DENIED: "ACCESS_DENIED";
|
|
358
|
+
readonly NOT_FOUND: "NOT_FOUND";
|
|
359
|
+
readonly NOT_FILE: "NOT_FILE";
|
|
360
|
+
readonly NOT_DIRECTORY: "NOT_DIRECTORY";
|
|
361
|
+
readonly TOO_LARGE: "TOO_LARGE";
|
|
362
|
+
readonly TIMEOUT: "TIMEOUT";
|
|
363
|
+
readonly CANCELLED: "CANCELLED";
|
|
364
|
+
readonly INVALID_PATTERN: "INVALID_PATTERN";
|
|
365
|
+
readonly INVALID_INPUT: "INVALID_INPUT";
|
|
366
|
+
readonly PERMISSION_DENIED: "PERMISSION_DENIED";
|
|
367
|
+
readonly SYMLINK_NOT_ALLOWED: "SYMLINK_NOT_ALLOWED";
|
|
368
|
+
readonly UNKNOWN: "UNKNOWN";
|
|
369
369
|
}>;
|
|
370
370
|
message: z.ZodString;
|
|
371
371
|
path: z.ZodOptional<z.ZodString>;
|
|
@@ -431,18 +431,18 @@ export declare const ApplyPatchOutputSchema: z.ZodObject<{
|
|
|
431
431
|
linesRemoved: z.ZodOptional<z.ZodInt>;
|
|
432
432
|
error: z.ZodOptional<z.ZodObject<{
|
|
433
433
|
code: z.ZodEnum<{
|
|
434
|
-
readonly
|
|
435
|
-
readonly
|
|
436
|
-
readonly
|
|
437
|
-
readonly
|
|
438
|
-
readonly
|
|
439
|
-
readonly
|
|
440
|
-
readonly
|
|
441
|
-
readonly
|
|
442
|
-
readonly
|
|
443
|
-
readonly
|
|
444
|
-
readonly
|
|
445
|
-
readonly
|
|
434
|
+
readonly ACCESS_DENIED: "ACCESS_DENIED";
|
|
435
|
+
readonly NOT_FOUND: "NOT_FOUND";
|
|
436
|
+
readonly NOT_FILE: "NOT_FILE";
|
|
437
|
+
readonly NOT_DIRECTORY: "NOT_DIRECTORY";
|
|
438
|
+
readonly TOO_LARGE: "TOO_LARGE";
|
|
439
|
+
readonly TIMEOUT: "TIMEOUT";
|
|
440
|
+
readonly CANCELLED: "CANCELLED";
|
|
441
|
+
readonly INVALID_PATTERN: "INVALID_PATTERN";
|
|
442
|
+
readonly INVALID_INPUT: "INVALID_INPUT";
|
|
443
|
+
readonly PERMISSION_DENIED: "PERMISSION_DENIED";
|
|
444
|
+
readonly SYMLINK_NOT_ALLOWED: "SYMLINK_NOT_ALLOWED";
|
|
445
|
+
readonly UNKNOWN: "UNKNOWN";
|
|
446
446
|
}>;
|
|
447
447
|
message: z.ZodString;
|
|
448
448
|
path: z.ZodOptional<z.ZodString>;
|
|
@@ -458,9 +458,9 @@ export declare const SearchAndReplaceInputSchema: z.ZodObject<{
|
|
|
458
458
|
isRegex: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
459
459
|
caseSensitive: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
460
460
|
dryRun: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
461
|
-
includeHidden: z.ZodOptional<z.ZodBoolean
|
|
462
|
-
includeIgnored: z.ZodOptional<z.ZodBoolean
|
|
463
|
-
returnDiff: z.ZodOptional<z.ZodBoolean
|
|
461
|
+
includeHidden: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
462
|
+
includeIgnored: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
463
|
+
returnDiff: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
464
464
|
maxFiles: z.ZodOptional<z.ZodInt>;
|
|
465
465
|
}, z.core.$strict>;
|
|
466
466
|
export declare const SearchAndReplaceOutputSchema: z.ZodObject<{
|
|
@@ -473,18 +473,18 @@ export declare const SearchAndReplaceOutputSchema: z.ZodObject<{
|
|
|
473
473
|
path: z.ZodString;
|
|
474
474
|
error: z.ZodObject<{
|
|
475
475
|
code: z.ZodEnum<{
|
|
476
|
-
readonly
|
|
477
|
-
readonly
|
|
478
|
-
readonly
|
|
479
|
-
readonly
|
|
480
|
-
readonly
|
|
481
|
-
readonly
|
|
482
|
-
readonly
|
|
483
|
-
readonly
|
|
484
|
-
readonly
|
|
485
|
-
readonly
|
|
486
|
-
readonly
|
|
487
|
-
readonly
|
|
476
|
+
readonly ACCESS_DENIED: "ACCESS_DENIED";
|
|
477
|
+
readonly NOT_FOUND: "NOT_FOUND";
|
|
478
|
+
readonly NOT_FILE: "NOT_FILE";
|
|
479
|
+
readonly NOT_DIRECTORY: "NOT_DIRECTORY";
|
|
480
|
+
readonly TOO_LARGE: "TOO_LARGE";
|
|
481
|
+
readonly TIMEOUT: "TIMEOUT";
|
|
482
|
+
readonly CANCELLED: "CANCELLED";
|
|
483
|
+
readonly INVALID_PATTERN: "INVALID_PATTERN";
|
|
484
|
+
readonly INVALID_INPUT: "INVALID_INPUT";
|
|
485
|
+
readonly PERMISSION_DENIED: "PERMISSION_DENIED";
|
|
486
|
+
readonly SYMLINK_NOT_ALLOWED: "SYMLINK_NOT_ALLOWED";
|
|
487
|
+
readonly UNKNOWN: "UNKNOWN";
|
|
488
488
|
}>;
|
|
489
489
|
message: z.ZodString;
|
|
490
490
|
path: z.ZodOptional<z.ZodString>;
|
package/dist/schemas.js
CHANGED
|
@@ -20,6 +20,13 @@ const PathSchemaBase = z
|
|
|
20
20
|
.max(MAX_PATH_LENGTH, `Path too long (max ${MAX_PATH_LENGTH} chars)`);
|
|
21
21
|
const OptionalPathSchema = PathSchemaBase.optional();
|
|
22
22
|
const RequiredPathSchema = PathSchemaBase.min(1, 'Path required');
|
|
23
|
+
const SafeGlobPatternSchema = z
|
|
24
|
+
.string()
|
|
25
|
+
.min(1, 'Pattern required')
|
|
26
|
+
.max(1000, 'Max 1000 chars')
|
|
27
|
+
.refine((val) => isSafeGlobPattern(val), {
|
|
28
|
+
error: 'Invalid glob or unsafe path (absolute/.. forbidden)',
|
|
29
|
+
});
|
|
23
30
|
const FileTypeSchema = z.enum(['file', 'directory', 'symlink', 'other']);
|
|
24
31
|
const ListDirectorySortSchema = z.enum(['name', 'size', 'modified', 'type']);
|
|
25
32
|
const SearchFilesSortSchema = z.enum(['name', 'size', 'modified', 'path']);
|
|
@@ -37,7 +44,7 @@ const TreeEntrySchema = z.lazy(() => z.strictObject({
|
|
|
37
44
|
children: z.array(TreeEntrySchema).optional().describe('Children'),
|
|
38
45
|
}));
|
|
39
46
|
const ErrorSchema = z.strictObject({
|
|
40
|
-
code: z.enum(ErrorCode).describe('Error code (e.g.
|
|
47
|
+
code: z.enum(ErrorCode).describe('Error code (e.g. NOT_FOUND)'),
|
|
41
48
|
message: z.string().describe('Human-readable message'),
|
|
42
49
|
path: z.string().optional().describe('Relevant path'),
|
|
43
50
|
suggestion: z.string().optional().describe('Fix suggestion'),
|
|
@@ -126,15 +133,7 @@ export const ListDirectoryInputSchema = z.strictObject({
|
|
|
126
133
|
sortBy: ListDirectorySortSchema.optional()
|
|
127
134
|
.default('name')
|
|
128
135
|
.describe('Sort field (name, size, modified, type)'),
|
|
129
|
-
pattern:
|
|
130
|
-
.string()
|
|
131
|
-
.min(1, 'Pattern required')
|
|
132
|
-
.max(1000, 'Max 1000 chars')
|
|
133
|
-
.refine((val) => isSafeGlobPattern(val), {
|
|
134
|
-
error: 'Invalid glob or unsafe path (absolute/.. forbidden)',
|
|
135
|
-
})
|
|
136
|
-
.optional()
|
|
137
|
-
.describe('Optional glob pattern filter (e.g. "**/*.ts")'),
|
|
136
|
+
pattern: SafeGlobPatternSchema.optional().describe('Optional glob pattern filter (e.g. "**/*.ts")'),
|
|
138
137
|
includeSymlinkTargets: defaultFalseBoolean('Resolve and include symlink targets in results'),
|
|
139
138
|
cursor: z
|
|
140
139
|
.string()
|
|
@@ -146,14 +145,7 @@ export const ListAllowedDirectoriesInputSchema = z
|
|
|
146
145
|
.describe('No input parameters.');
|
|
147
146
|
export const SearchFilesInputSchema = z.strictObject({
|
|
148
147
|
path: OptionalPathSchema.describe(DESC_PATH_ROOT),
|
|
149
|
-
pattern:
|
|
150
|
-
.string()
|
|
151
|
-
.min(1, 'Pattern required')
|
|
152
|
-
.max(1000, 'Max 1000 chars')
|
|
153
|
-
.refine((val) => isSafeGlobPattern(val), {
|
|
154
|
-
error: 'Invalid glob or unsafe path (absolute/.. forbidden)',
|
|
155
|
-
})
|
|
156
|
-
.describe('Glob pattern (e.g. "**/*.ts", "src/*.js")'),
|
|
148
|
+
pattern: SafeGlobPatternSchema.describe('Glob pattern (e.g. "**/*.ts", "src/*.js")'),
|
|
157
149
|
maxResults: z
|
|
158
150
|
.int({ error: 'Must be integer' })
|
|
159
151
|
.min(1, 'Min: 1')
|
|
@@ -221,11 +213,7 @@ export const SearchContentInputSchema = z.strictObject({
|
|
|
221
213
|
.optional()
|
|
222
214
|
.default(DEFAULT_SEARCH_CONTENT_RESULTS)
|
|
223
215
|
.describe(`Maximum match rows to return. Default: ${DEFAULT_SEARCH_CONTENT_RESULTS}`),
|
|
224
|
-
filePattern:
|
|
225
|
-
.string()
|
|
226
|
-
.min(1, 'Pattern required')
|
|
227
|
-
.max(1000, 'Max 1000 chars')
|
|
228
|
-
.optional()
|
|
216
|
+
filePattern: SafeGlobPatternSchema.optional()
|
|
229
217
|
.default('**/*')
|
|
230
218
|
.describe('Glob for candidate files (e.g. "**/*.ts")'),
|
|
231
219
|
includeHidden: defaultFalseBoolean('Include hidden items (starting with .)'),
|
|
@@ -449,6 +437,8 @@ export const EditFileInputSchema = z.strictObject({
|
|
|
449
437
|
.array(z.strictObject({
|
|
450
438
|
oldText: z
|
|
451
439
|
.string()
|
|
440
|
+
.min(1, 'oldText required')
|
|
441
|
+
.max(102400, 'Max 100KB')
|
|
452
442
|
.describe('Exact literal string to replace (character-for-character). Include 3–5 lines of context for unique targeting.'),
|
|
453
443
|
newText: z
|
|
454
444
|
.string()
|
|
@@ -621,15 +611,8 @@ export const ApplyPatchOutputSchema = z.strictObject({
|
|
|
621
611
|
});
|
|
622
612
|
export const SearchAndReplaceInputSchema = z.strictObject({
|
|
623
613
|
path: OptionalPathSchema.describe(DESC_PATH_ROOT),
|
|
624
|
-
filePattern:
|
|
625
|
-
.string()
|
|
626
|
-
.min(1, 'Pattern required')
|
|
627
|
-
.max(1000, 'Max 1000 chars')
|
|
628
|
-
.optional()
|
|
614
|
+
filePattern: SafeGlobPatternSchema.optional()
|
|
629
615
|
.default('**/*')
|
|
630
|
-
.refine((val) => isSafeGlobPattern(val), {
|
|
631
|
-
error: 'Invalid glob or unsafe path (absolute/.. forbidden)',
|
|
632
|
-
})
|
|
633
616
|
.describe('Glob to filter files. Default: **/*'),
|
|
634
617
|
searchPattern: z
|
|
635
618
|
.string()
|
|
@@ -644,18 +627,9 @@ export const SearchAndReplaceInputSchema = z.strictObject({
|
|
|
644
627
|
.default(true)
|
|
645
628
|
.describe('Case-sensitive matching. Default: true.'),
|
|
646
629
|
dryRun: defaultFalseBoolean('Preview matches without writing. Check changedFiles and matches in the response before committing.'),
|
|
647
|
-
includeHidden:
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
.describe('Include hidden files/directories (starting with .). Default: false.'),
|
|
651
|
-
includeIgnored: z
|
|
652
|
-
.boolean()
|
|
653
|
-
.optional()
|
|
654
|
-
.describe('Include .gitignore-ignored files (node_modules, dist). Default: false.'),
|
|
655
|
-
returnDiff: z
|
|
656
|
-
.boolean()
|
|
657
|
-
.optional()
|
|
658
|
-
.describe('Return unified diff of changes even if dryRun is false. Default: false.'),
|
|
630
|
+
includeHidden: defaultFalseBoolean('Include hidden files/directories (starting with .). Default: false.'),
|
|
631
|
+
includeIgnored: defaultFalseBoolean('Include .gitignore-ignored files (node_modules, dist). Default: false.'),
|
|
632
|
+
returnDiff: defaultFalseBoolean('Return unified diff of changes even if dryRun is false. Default: false.'),
|
|
659
633
|
maxFiles: z
|
|
660
634
|
.int({ error: 'Must be integer' })
|
|
661
635
|
.min(1, 'Min: 1')
|
|
@@ -687,7 +661,10 @@ export const SearchAndReplaceOutputSchema = z.strictObject({
|
|
|
687
661
|
.boolean()
|
|
688
662
|
.optional()
|
|
689
663
|
.describe('Changed file list truncated'),
|
|
690
|
-
diff: z
|
|
664
|
+
diff: z
|
|
665
|
+
.string()
|
|
666
|
+
.optional()
|
|
667
|
+
.describe('Unified diff of changes when `dryRun` or `returnDiff` is enabled'),
|
|
691
668
|
diffTruncated: z
|
|
692
669
|
.boolean()
|
|
693
670
|
.optional()
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import * as http from 'node:http';
|
|
2
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
-
import type
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
import { type Server } from 'node:http';
|
|
3
|
+
import { type LoggingState } from '../lib/logger.js';
|
|
4
|
+
import { type ServerOptions } from './roots-manager.js';
|
|
5
|
+
export declare const activeServers: Map<string, {
|
|
6
|
+
server: McpServer;
|
|
7
|
+
loggingState: LoggingState;
|
|
8
|
+
}>;
|
|
9
|
+
export declare let stdioServer: {
|
|
10
|
+
server: McpServer;
|
|
11
|
+
loggingState: LoggingState;
|
|
12
|
+
} | undefined;
|
|
12
13
|
export declare function createServer(options?: ServerOptions): Promise<McpServer>;
|
|
13
14
|
export declare function startServer(server: McpServer): Promise<void>;
|
|
14
|
-
export declare function startHttpServer(port: number, options: ServerOptions): Promise<
|
|
15
|
+
export declare function startHttpServer(port: number, options: ServerOptions): Promise<Server>;
|