@j0hanz/filesystem-mcp 1.13.2 → 1.14.1

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 (74) hide show
  1. package/README.md +162 -145
  2. package/dist/cli.js +2 -2
  3. package/dist/completions.js +54 -51
  4. package/dist/config.d.ts +13 -14
  5. package/dist/config.js +12 -12
  6. package/dist/index.js +1 -1
  7. package/dist/lib/abort.d.ts +7 -0
  8. package/dist/lib/abort.js +81 -0
  9. package/dist/lib/constants.d.ts +3 -1
  10. package/dist/lib/constants.js +8 -2
  11. package/dist/lib/errors.d.ts +7 -3
  12. package/dist/lib/errors.js +64 -41
  13. package/dist/lib/file-operations/core.d.ts +3 -3
  14. package/dist/lib/file-operations/core.js +23 -20
  15. package/dist/lib/file-operations/metadata.d.ts +2 -2
  16. package/dist/lib/file-operations/metadata.js +69 -22
  17. package/dist/lib/file-operations/search.d.ts +0 -1
  18. package/dist/lib/file-operations/search.js +87 -95
  19. package/dist/lib/file-operations/traversal.js +13 -15
  20. package/dist/lib/fs-helpers.d.ts +3 -10
  21. package/dist/lib/fs-helpers.js +29 -108
  22. package/dist/lib/globs.d.ts +2 -0
  23. package/dist/lib/globs.js +19 -0
  24. package/dist/lib/logger.d.ts +28 -0
  25. package/dist/lib/logger.js +91 -0
  26. package/dist/lib/observability.d.ts +7 -0
  27. package/dist/lib/observability.js +19 -9
  28. package/dist/lib/paths.js +55 -55
  29. package/dist/lib/resource-store.js +4 -4
  30. package/dist/lib/utils.d.ts +0 -12
  31. package/dist/lib/utils.js +0 -13
  32. package/dist/lib/zod-codecs.d.ts +2 -0
  33. package/dist/lib/zod-codecs.js +18 -0
  34. package/dist/pkg-info.d.ts +1 -0
  35. package/dist/pkg-info.js +2 -2
  36. package/dist/prompts.js +3 -3
  37. package/dist/resources/generated-instructions.js +41 -41
  38. package/dist/resources/tool-catalog.js +33 -58
  39. package/dist/resources/tool-info.d.ts +0 -1
  40. package/dist/resources/tool-info.js +44 -67
  41. package/dist/resources/workflows.js +47 -19
  42. package/dist/resources.d.ts +1 -1
  43. package/dist/resources.js +4 -4
  44. package/dist/schemas.d.ts +185 -465
  45. package/dist/schemas.js +174 -206
  46. package/dist/server/bootstrap.d.ts +12 -11
  47. package/dist/server/bootstrap.js +95 -86
  48. package/dist/server/roots-manager.d.ts +5 -2
  49. package/dist/server/roots-manager.js +9 -7
  50. package/dist/server/task-store.d.ts +10 -0
  51. package/dist/server/task-store.js +73 -0
  52. package/dist/tools/apply-patch.js +39 -20
  53. package/dist/tools/calculate-hash.js +14 -27
  54. package/dist/tools/create-directory.js +11 -9
  55. package/dist/tools/delete-file.js +19 -19
  56. package/dist/tools/diff-files.js +16 -18
  57. package/dist/tools/edit-file.js +11 -5
  58. package/dist/tools/list-directory.js +16 -21
  59. package/dist/tools/move-file.js +105 -100
  60. package/dist/tools/read-multiple.js +15 -10
  61. package/dist/tools/read.js +6 -7
  62. package/dist/tools/replace-in-files.js +76 -115
  63. package/dist/tools/roots.js +3 -7
  64. package/dist/tools/search-content.js +158 -203
  65. package/dist/tools/search-files.js +59 -50
  66. package/dist/tools/shared.d.ts +10 -0
  67. package/dist/tools/shared.js +105 -36
  68. package/dist/tools/stat-many.js +15 -9
  69. package/dist/tools/stat.js +6 -6
  70. package/dist/tools/task-support.d.ts +10 -9
  71. package/dist/tools/task-support.js +94 -23
  72. package/dist/tools/tree.js +4 -4
  73. package/dist/tools/write-file.js +11 -12
  74. package/package.json +10 -9
@@ -15,27 +15,16 @@ function buildCrossToolDataFlow() {
15
15
  }
16
16
  function buildCatalogGuide() {
17
17
  const taskCapable = getTaskCapableToolNames();
18
- return (`<tool_selection_guide>
18
+ return `# Tool Selection Guide
19
+
19
20
  ## Primitive Routing
20
21
 
21
- - ` +
22
- '`tools`' +
23
- `: model-controlled operations that inspect or mutate the allowed filesystem.
24
- - ` +
25
- '`resources`' +
26
- `: application-driven context such as ` +
27
- '`internal://instructions`' +
28
- `, ` +
29
- '`internal://tool-info/{name}`' +
30
- `, and cached ` +
31
- '`filesystem-mcp://result/{id}`' +
32
- ` output.
33
- - ` +
34
- '`prompts`' +
35
- `: user-controlled workflow templates for help, comparison, and guided inspection.
36
- - ` +
37
- '`completion`' +
38
- `: argument suggestions for prompts and resource templates; not a discovery mechanism.
22
+ | Primitive | Purpose |
23
+ | -------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
24
+ | \`tools\` | Model-controlled operations that inspect or mutate the filesystem within allowed roots. |
25
+ | \`resources\` | Application-driven context: \`internal://instructions\`, \`internal://tool-info/{name}\`, cached \`filesystem-mcp://result/{id}\`. |
26
+ | \`prompts\` | User-controlled workflow templates for help, comparison, and guided inspection. |
27
+ | \`completion\` | Argument suggestions for prompts and resource templates (not a discovery mechanism). |
39
28
 
40
29
  ## Cross-Tool Data Flow
41
30
 
@@ -45,55 +34,41 @@ ${buildCrossToolDataFlow()}
45
34
 
46
35
  ## Result Contract
47
36
 
48
- - Successful tools return ` +
49
- '`content`' +
50
- ` and usually ` +
51
- '`structuredContent`' +
52
- `.
53
- - Tool/business failures return ` +
54
- '`isError: true`' +
55
- ` inside the tool result, not a JSON-RPC protocol error.
56
- - When a tool returns ` +
57
- '`resourceUri`' +
58
- ` or a ` +
59
- '`resource_link`' +
60
- `, follow it with ` +
61
- '`resources/read`' +
62
- ` immediately.
37
+ - Success: returns both \`content\` (JSON text) and \`structuredContent\` (when \`outputSchema\` is declared).
38
+ - Error: \`isError: true\` in tool result, \`structuredContent\` omitted. Parse \`content\` text for error details.
39
+ - Tool/business failures use \`isError: true\` inside the tool result, not JSON-RPC protocol errors.
40
+ - When a response includes \`resourceUri\` or \`resource_link\`, follow up with \`resources/read\` immediately.
41
+
42
+ ## Task Mode
63
43
 
64
- ## Task Mode Routing
44
+ Use inline execution by default. Add task mode only when the caller needs durable polling, deferred retrieval, or cancellation.
65
45
 
66
- - Inline first for fast operations.
67
- - Add task mode only when the caller needs durable polling, deferred retrieval, or cancellation after the initial response.
68
- - Task-capable tools: ${taskCapable.length > 0 ? taskCapable.map((name) => `\`${name}\``).join(', ') : 'none'}.
46
+ Task-capable tools: ${taskCapable.length > 0 ? taskCapable.map((name) => `\`${name}\``).join(', ') : 'none'}.
69
47
 
70
48
  ## Search Strategy
71
49
 
72
- - \`find\`: glob file discovery.
73
- - \`grep\`: text content search.
74
- - \`search_and_replace\`: replacement only, not discovery.
50
+ | Goal | Tool |
51
+ | ----------------------- | ------------------------------------------ |
52
+ | Find files by name/glob | \`find\` |
53
+ | Search file contents | \`grep\` |
54
+ | Replace across files | \`search_and_replace\` (not for discovery) |
75
55
 
76
56
  ## Write Strategy
77
57
 
78
- - \`edit\`: precise first-occurrence replacements.
79
- - \`write\`: create files or overwrite full contents.
80
- - \`search_and_replace\`: bulk multi-file replacements.
81
-
82
- ### edit vs write vs search_and_replace Decision
83
-
84
- 1. **Single file, targeted change?** -> \`edit\` (match exact text, replace first occurrence)
85
- 2. **Single file, full rewrite?** -> \`write\` (overwrite entire content)
86
- 3. **Multiple files, same change?** -> \`search_and_replace\` (glob + pattern across files)
87
- 4. **Not sure what to change?** -> \`grep\` first, then decide
58
+ | Scenario | Tool |
59
+ | --------------------------- | ----------------------------------------------------- |
60
+ | Single file, targeted edit | \`edit\` match exact text, replace first occurrence |
61
+ | Single file, full rewrite | \`write\` — overwrite entire content |
62
+ | Multiple files, same change | \`search_and_replace\` — glob + pattern across files |
63
+ | Unsure what to change | \`grep\` first, then decide |
88
64
 
89
- ## Patch Management
65
+ ## Patch Strategy
90
66
 
91
- - Generate patches with \`diff_files\` first.
92
- - Validate with \`apply_patch(dryRun:true)\` before writing.
93
- - \`apply_patch\` accepts unified diffs - single-file or multi-file.
94
- - Multi-file: \`path\` is base directory; each file is best-effort with per-file \`results[]\`.
95
- </tool_selection_guide>
96
- `);
67
+ 1. Generate with \`diff_files\`.
68
+ 2. Validate with \`apply_patch(dryRun: true)\` before writing.
69
+ 3. Apply with \`apply_patch\`.
70
+ 4. Multi-file patches: set \`path\` to the base directory; results are per-file.
71
+ `;
97
72
  }
98
73
  export function buildToolCatalog() {
99
74
  return `${buildCoreContextPack()}\n\n${buildCatalogGuide()}`;
@@ -4,7 +4,6 @@ export declare function getSortedToolContracts(): ToolContract[];
4
4
  export declare function pickAvailableToolNames(names: readonly string[]): string[];
5
5
  export declare function formatToolNameList(names: readonly string[]): string;
6
6
  export declare function getTaskCapableToolNames(): string[];
7
- export declare function getTaskToolNamesBySupport(taskSupport: Extract<ToolContract['taskSupport'], 'optional' | 'required'>): string[];
8
7
  export declare function buildCoreContextPack(): string;
9
8
  export declare function getSharedConstraints(): string[];
10
9
  export declare function buildToolInfo(name: string): string | undefined;
@@ -55,11 +55,6 @@ export function getTaskCapableToolNames() {
55
55
  contract.taskSupport === 'required')
56
56
  .map((contract) => contract.name);
57
57
  }
58
- export function getTaskToolNamesBySupport(taskSupport) {
59
- return getSortedToolContracts()
60
- .filter((contract) => contract.taskSupport === taskSupport)
61
- .map((contract) => contract.name);
62
- }
63
58
  export function buildCoreContextPack() {
64
59
  const rows = getSortedToolContracts().map((contract) => {
65
60
  const e = ENTRIES[contract.name];
@@ -68,14 +63,14 @@ export function buildCoreContextPack() {
68
63
  const annotations = e.annotations ? ` ${e.annotations.join(' ')}` : '';
69
64
  return `| \`${e.name}\` | ${e.description}${annotations} |`;
70
65
  });
71
- return `<core_context>\n| Tool | Purpose |\n|------|---------|\n${rows.join('\n')}\n</core_context>`;
66
+ return `## Tool Summary\n\n| Tool | Purpose |\n|------|---------|\n${rows.join('\n')}`;
72
67
  }
73
68
  export function getSharedConstraints() {
74
69
  return [
75
- 'Use allowed roots only (from CLI negotiation).',
76
- 'Sensitive paths are denylisted by default.',
77
- `Limits enforced: max file size ${Math.floor(MAX_TEXT_FILE_SIZE / 1024 / 1024)}MB; search caps ${MAX_SEARCH_RESULTS} files, ${DEFAULT_SEARCH_CONTENT_RESULTS} content matches.`,
78
- 'If response includes `resourceUri`, call `resources/read` immediately — cached results expire on restart.',
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.',
79
74
  ];
80
75
  }
81
76
  function formatTaskSupportLabel(taskSupport) {
@@ -88,12 +83,17 @@ function formatTaskSupportLabel(taskSupport) {
88
83
  return 'forbidden';
89
84
  }
90
85
  }
91
- function formatAnnotationValue(value) {
92
- return value ? 'true' : 'false';
93
- }
94
86
  function toJsonSchemaObject(schema, io = 'output') {
95
87
  return z.toJSONSchema(schema, { io });
96
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
+ }
97
97
  function summarizeSchemaType(schema) {
98
98
  if (Array.isArray(schema.enum) && schema.enum.length > 0) {
99
99
  return `enum(${schema.enum.map((value) => JSON.stringify(value)).join(', ')})`;
@@ -108,14 +108,7 @@ function summarizeSchemaType(schema) {
108
108
  return schema.oneOf.map(summarizeSchemaType).join(' | ');
109
109
  }
110
110
  if (schema.type === 'array') {
111
- if (Array.isArray(schema.prefixItems) && schema.prefixItems.length > 0) {
112
- const itemTypes = schema.prefixItems.map(summarizeSchemaType).join(', ');
113
- return `tuple<${itemTypes}>`;
114
- }
115
- const itemType = schema.items
116
- ? summarizeSchemaType(schema.items)
117
- : 'unknown';
118
- return `array<${itemType}>`;
111
+ return summarizeArrayType(schema);
119
112
  }
120
113
  if (schema.type === 'object' && schema.additionalProperties === false) {
121
114
  return 'object (strict)';
@@ -125,16 +118,23 @@ function summarizeSchemaType(schema) {
125
118
  }
126
119
  return 'unknown';
127
120
  }
121
+ function formatFieldLabel(label) {
122
+ return label
123
+ .split('_')
124
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
125
+ .join(' ');
126
+ }
128
127
  function buildSchemaFieldLines(label, schema) {
128
+ const heading = `**${formatFieldLabel(label)}:**`;
129
129
  if (!schema) {
130
- return [`<${label}>`, '- none', `</${label}>`];
130
+ return [heading, '- none'];
131
131
  }
132
132
  const io = label === 'input_fields' ? 'input' : 'output';
133
133
  const jsonSchema = toJsonSchemaObject(schema, io);
134
134
  const properties = jsonSchema.properties ?? {};
135
135
  const required = new Set(jsonSchema.required ?? []);
136
136
  const fieldNames = Object.keys(properties);
137
- const lines = [`<${label}>`];
137
+ const lines = [heading];
138
138
  if (typeof jsonSchema.description === 'string' &&
139
139
  jsonSchema.description.length > 0) {
140
140
  lines.push(`- Schema constraints: ${jsonSchema.description}`);
@@ -143,7 +143,7 @@ function buildSchemaFieldLines(label, schema) {
143
143
  lines.push('- Unknown fields are rejected (`additionalProperties: false`).');
144
144
  }
145
145
  if (fieldNames.length === 0) {
146
- lines.push('- object with no fields', `</${label}>`);
146
+ lines.push('- object with no fields');
147
147
  return lines;
148
148
  }
149
149
  lines.push(...fieldNames.map((fieldName) => {
@@ -155,75 +155,52 @@ function buildSchemaFieldLines(label, schema) {
155
155
  ? fieldSchema.description
156
156
  : 'No description.';
157
157
  return `- ${fieldName} (${type}, ${requiredLabel}): ${description}`;
158
- }), `</${label}>`);
158
+ }));
159
159
  return lines;
160
160
  }
161
- function buildProtocolNotes(contract) {
162
- const notes = [
163
- '- Protocol failures use JSON-RPC `error`; execution failures use tool result `isError: true`.',
164
- ];
165
- if (contract.outputSchema) {
166
- notes.push('- Successful responses include `structuredContent` that must match the declared output schema.');
167
- }
168
- if (contract.taskSupport === 'optional') {
169
- notes.push('- Supports inline execution by default and task mode when durable polling or deferred results are needed.');
170
- }
171
- if (contract.taskSupport === 'required') {
172
- notes.push('- Must run in task mode; callers should poll `tasks/get` and fetch the payload via `tasks/result`.');
173
- }
174
- if (contract.taskSupport === 'forbidden') {
175
- notes.push('- Runs inline only; task augmentation is not supported for this tool.');
176
- }
177
- return notes;
178
- }
179
161
  export function buildToolInfo(name) {
180
162
  const contract = CONTRACTS_BY_NAME.get(name);
181
163
  const entry = ENTRIES[name];
182
164
  if (!entry || !contract)
183
165
  return undefined;
166
+ const annotationLines = [];
167
+ if (contract.annotations?.readOnlyHint)
168
+ annotationLines.push('- readOnlyHint: true');
169
+ if (contract.annotations?.idempotentHint)
170
+ annotationLines.push('- idempotentHint: true');
171
+ if (contract.annotations?.destructiveHint)
172
+ annotationLines.push('- destructiveHint: true');
173
+ if (contract.annotations?.openWorldHint)
174
+ annotationLines.push('- openWorldHint: true');
184
175
  const lines = [
185
- `<tool_info name="${entry.name}">`,
186
- `## ${entry.name}`,
176
+ `---`,
177
+ `# ${entry.name}`,
187
178
  '',
188
- `Title: ${entry.title}`,
189
- `Description: ${entry.description}`,
179
+ `**Title:** ${entry.title}`,
180
+ `**Description:** ${entry.description}`,
190
181
  '',
191
- '<execution>',
182
+ '**Execution:**',
192
183
  `- taskSupport: ${formatTaskSupportLabel(contract.taskSupport)}`,
193
- '</execution>',
194
- '',
195
- '<annotations>',
196
- `- readOnlyHint: ${formatAnnotationValue(contract.annotations?.readOnlyHint)}`,
197
- `- idempotentHint: ${formatAnnotationValue(contract.annotations?.idempotentHint)}`,
198
- `- destructiveHint: ${formatAnnotationValue(contract.annotations?.destructiveHint)}`,
199
- `- openWorldHint: ${formatAnnotationValue(contract.annotations?.openWorldHint)}`,
200
- '</annotations>',
201
184
  '',
202
185
  ...buildSchemaFieldLines('input_fields', contract.inputSchema),
203
186
  '',
204
187
  ...buildSchemaFieldLines('output_fields', contract.outputSchema),
205
- '',
206
- '<protocol_notes>',
207
- ...buildProtocolNotes(contract),
208
- '</protocol_notes>',
209
188
  ];
210
- if (entry.annotations && entry.annotations.length > 0) {
211
- lines.push('', `<quick_hints>${entry.annotations.join(' ')}</quick_hints>`);
189
+ if (annotationLines.length > 0) {
190
+ lines.push('', '**Behavior:**', ...annotationLines);
212
191
  }
213
192
  if (entry.nuances && entry.nuances.length > 0) {
214
- lines.push('', '<nuances>');
193
+ lines.push('', '**Usage Notes:**');
215
194
  for (const nuance of entry.nuances) {
216
195
  lines.push(`- ${nuance}`);
217
196
  }
218
- lines.push('</nuances>');
219
197
  }
220
198
  if (entry.gotchas && entry.gotchas.length > 0) {
221
- lines.push('', '<gotchas>');
199
+ lines.push('', '**Warnings:**');
222
200
  for (const gotcha of entry.gotchas) {
223
201
  lines.push(`- ${gotcha}`);
224
202
  }
225
- lines.push('</gotchas>');
226
203
  }
227
- lines.push('</tool_info>');
204
+ lines.push('---');
228
205
  return lines.join('\n');
229
206
  }
@@ -10,23 +10,51 @@ export function buildWorkflowGuide() {
10
10
  'read_many',
11
11
  ]));
12
12
  const searchTools = formatToolNameList(pickAvailableToolNames(['find', 'grep', 'read']));
13
- const editTools = formatToolNameList(pickAvailableToolNames(['edit', 'search_and_replace', 'mv', 'rm', 'mkdir']));
14
- return `<workflows>
15
- ### A: EXPLORE — directory layout or file content
16
- 1. ${exploreTools}.
17
- > **Strict:** Resolve paths first. Never guess.
18
-
19
- ### B: SEARCH — files by pattern or content
20
- 1. ${searchTools}.
21
- > **Strict:** Content search with \`grep\`, not \`find\`.
22
-
23
- ### C: EDITmodify files or layout
24
- 1. ${editTools}.
25
- 2. Use \`edit\` for targeted changes, \`search_and_replace\` for bulk changes, and \`mv\`/\`rm\`/\`mkdir\` for layout updates.
26
- > **Strict:** Confirm destructive ops (\`write\`, \`mv\`, \`rm\`, bulk replace).
27
-
28
- ### D: PATCH apply unified diffs
29
- 1. \`diff_files\` → \`apply_patch(dryRun:true)\` → \`apply_patch\`.
30
- > **Tip:** Feed \`diff_files\` output directly. Multi-file patches: \`path\` = base dir, results per file.
31
- </workflows>`;
13
+ const editTools = formatToolNameList(pickAvailableToolNames([
14
+ 'edit',
15
+ 'write',
16
+ 'search_and_replace',
17
+ 'mv',
18
+ 'rm',
19
+ 'mkdir',
20
+ ]));
21
+ return `## Workflows
22
+
23
+ ### A: ExploreDiscover 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
+ `;
32
60
  }
@@ -1,4 +1,4 @@
1
- import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
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.E_NOT_FOUND, 'Cached result has expired — re-run the tool to regenerate.');
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.E_INVALID_INPUT, 'Tool name is required');
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.E_INVALID_INPUT, `Tool not found: ${name}`);
137
+ throw new McpError(ErrorCode.INVALID_INPUT, `Tool not found: ${name}`);
138
138
  }
139
139
  return {
140
140
  contents: [