@j0hanz/fs-context-mcp 2.7.2 → 2.7.4

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.
@@ -56,7 +56,7 @@ export function registerApplyPatchTool(server, options = {}) {
56
56
  guard: options.isInitialized,
57
57
  progressMessage: (args) => {
58
58
  const name = path.basename(args.path);
59
- return `▣ apply_patch: ${name}`;
59
+ return `🛠 apply_patch: ${name}`;
60
60
  },
61
61
  }));
62
62
  }
@@ -105,7 +105,7 @@ export function registerCalculateHashTool(server, options = {}) {
105
105
  guard: options.isInitialized,
106
106
  progressMessage: (args) => {
107
107
  const name = path.basename(args.path);
108
- return `⩩ calculate_hash: ${name}`;
108
+ return `⌗ calculate_hash: ${name}`;
109
109
  },
110
110
  }));
111
111
  }
@@ -37,6 +37,6 @@ export function registerCreateDirectoryTool(server, options = {}) {
37
37
  }, (error) => buildToolErrorResponse(error, ErrorCode.E_UNKNOWN, args.path)), { path: args.path });
38
38
  server.registerTool('mkdir', withDefaultIcons({ ...CREATE_DIRECTORY_TOOL }, options.iconInfo), wrapToolHandler(handler, {
39
39
  guard: options.isInitialized,
40
- progressMessage: (args) => `✚ mkdir: ${path.basename(args.path)}`,
40
+ progressMessage: (args) => `🛠 mkdir: ${path.basename(args.path)}`,
41
41
  }));
42
42
  }
@@ -53,6 +53,6 @@ export function registerDeleteFileTool(server, options = {}) {
53
53
  }), { path: args.path });
54
54
  server.registerTool('rm', withDefaultIcons({ ...DELETE_FILE_TOOL }, options.iconInfo), wrapToolHandler(handler, {
55
55
  guard: options.isInitialized,
56
- progressMessage: (args) => `✘ rm: ${path.basename(args.path)}`,
56
+ progressMessage: (args) => `✖ rm: ${path.basename(args.path)}`,
57
57
  }));
58
58
  }
@@ -72,7 +72,7 @@ export function registerDiffFilesTool(server, options = {}) {
72
72
  progressMessage: (args) => {
73
73
  const name1 = path.basename(args.original);
74
74
  const name2 = path.basename(args.modified);
75
- return `⟺ diff_files: ${name1} ↔ ${name2}`;
75
+ return `⇄ diff_files: ${name1} ↔ ${name2}`;
76
76
  },
77
77
  }));
78
78
  }
@@ -62,7 +62,7 @@ export function registerEditFileTool(server, options = {}) {
62
62
  guard: options.isInitialized,
63
63
  progressMessage: (args) => {
64
64
  const name = path.basename(args.path);
65
- return `✎ edit: ${name} ${args.edits.length} edits`;
65
+ return `🛠 edit: ${name} (${args.edits.length} edits)`;
66
66
  },
67
67
  }));
68
68
  }
@@ -99,9 +99,9 @@ export function registerListDirectoryTool(server, options = {}) {
99
99
  guard: options.isInitialized,
100
100
  progressMessage: (args) => {
101
101
  if (args.path) {
102
- return `≣ ls: ${path.basename(args.path)}`;
102
+ return `☰ ls: ${path.basename(args.path)}`;
103
103
  }
104
- return ' ls';
104
+ return ' ls';
105
105
  },
106
106
  }));
107
107
  }
@@ -53,6 +53,6 @@ export function registerMoveFileTool(server, options = {}) {
53
53
  }, (error) => buildToolErrorResponse(error, ErrorCode.E_UNKNOWN, args.source)), { path: args.source });
54
54
  server.registerTool('mv', withDefaultIcons({ ...MOVE_FILE_TOOL }, options.iconInfo), wrapToolHandler(handler, {
55
55
  guard: options.isInitialized,
56
- progressMessage: (args) => `➔ mv: ${path.basename(args.source)} -> ${path.basename(args.destination)}`,
56
+ progressMessage: (args) => `🛠 mv: ${path.basename(args.source)} ${path.basename(args.destination)}`,
57
57
  }));
58
58
  }
@@ -90,7 +90,7 @@ async function handleReadMultipleFiles(args, signal, resourceStore) {
90
90
  return result.path;
91
91
  })
92
92
  .join('\n');
93
- return buildToolResponse(text, structured, resourceLinks);
93
+ return buildToolResponse(text, structured, resourceLinks, resourceStore);
94
94
  }
95
95
  export function registerReadMultipleFilesTool(server, options = {}) {
96
96
  const handler = (args, extra) => {
@@ -107,7 +107,7 @@ export function registerReadMultipleFilesTool(server, options = {}) {
107
107
  };
108
108
  const wrappedHandler = wrapToolHandler(handler, {
109
109
  guard: options.isInitialized,
110
- progressMessage: (args) => `🗐 read_many: ${args.paths.length} files`,
110
+ progressMessage: (args) => `🕮 read_many: ${args.paths.length} files`,
111
111
  });
112
112
  const taskOptions = options.isInitialized
113
113
  ? { guard: options.isInitialized }
@@ -54,7 +54,7 @@ async function handleReadFile(args, signal, resourceStore) {
54
54
  };
55
55
  const externalized = maybeExternalizeTextContent(resourceStore, result.content, { name: `read:${path.basename(args.path)}`, mimeType: 'text/plain' });
56
56
  if (!externalized) {
57
- return buildToolResponse(result.content, structured);
57
+ return buildToolResponse(result.content, structured, [], resourceStore);
58
58
  }
59
59
  const { entry, preview } = externalized;
60
60
  const structuredWithResource = {
@@ -75,7 +75,7 @@ async function handleReadFile(args, signal, resourceStore) {
75
75
  mimeType: entry.mimeType,
76
76
  description: 'Full file contents',
77
77
  }),
78
- ]);
78
+ ], resourceStore);
79
79
  }
80
80
  export function registerReadFileTool(server, options = {}) {
81
81
  const handler = (args, extra) => withToolDiagnostics('read', () => withToolErrorHandling(async () => {
@@ -93,7 +93,7 @@ export function registerReadFileTool(server, options = {}) {
93
93
  const name = path.basename(args.path);
94
94
  if (args.startLine !== undefined) {
95
95
  const end = args.endLine ?? '…';
96
- return `🕮 read: ${name} ${args.startLine}-${end}`;
96
+ return `🕮 read: ${name} [${args.startLine}-${end}]`;
97
97
  }
98
98
  return `🕮 read: ${name}`;
99
99
  },
@@ -176,7 +176,7 @@ export function registerSearchAndReplaceTool(server, options = {}) {
176
176
  const handler = (args, extra) => withToolDiagnostics('search_and_replace', () => withToolErrorHandling(async () => {
177
177
  notifyProgress(extra, {
178
178
  current: 0,
179
- message: `⟳ search_and_replace: ${args.filePattern}`,
179
+ message: `🛠 search_and_replace: ${args.filePattern}`,
180
180
  });
181
181
  const { signal, cleanup } = createTimedAbortSignal(extra.signal);
182
182
  try {
@@ -185,7 +185,7 @@ export function registerSearchAndReplaceTool(server, options = {}) {
185
185
  const finalCurrent = (sc.processedFiles ?? 0) + 1;
186
186
  notifyProgress(extra, {
187
187
  current: finalCurrent,
188
- message: `⟳ search_and_replace: ${args.filePattern} → ${String(sc.filesChanged ?? 0)} files`,
188
+ message: `🛠 search_and_replace: ${args.filePattern} → ${String(sc.filesChanged ?? 0)} files`,
189
189
  });
190
190
  return result;
191
191
  }
@@ -38,6 +38,6 @@ export function registerListAllowedDirectoriesTool(server, options = {}) {
38
38
  const handler = () => withToolErrorHandling(() => withToolDiagnostics('roots', () => Promise.resolve(handleListAllowedDirectories())), (error) => buildToolErrorResponse(error, ErrorCode.E_UNKNOWN));
39
39
  server.registerTool('roots', withDefaultIcons({ ...LIST_ALLOWED_DIRECTORIES_TOOL }, options.iconInfo), wrapToolHandler(handler, {
40
40
  guard: options.isInitialized,
41
- progressMessage: () => ' roots',
41
+ progressMessage: () => ' roots',
42
42
  }));
43
43
  }
@@ -169,7 +169,7 @@ export function registerSearchContentTool(server, options = {}) {
169
169
  const normalizedArgs = SearchContentInputSchema.parse(args);
170
170
  notifyProgress(extra, {
171
171
  current: 0,
172
- message: `⌕ grep: ${normalizedArgs.pattern}`,
172
+ message: `🔎︎ grep: ${normalizedArgs.pattern}`,
173
173
  });
174
174
  const result = await handleSearchContent(normalizedArgs, extra.signal, options.resourceStore, createProgressReporter(extra));
175
175
  const sc = result.structuredContent;
@@ -177,7 +177,7 @@ export function registerSearchContentTool(server, options = {}) {
177
177
  const finalCurrent = (sc.filesScanned ?? 0) + 1;
178
178
  notifyProgress(extra, {
179
179
  current: finalCurrent,
180
- message: `⌕ grep: ${normalizedArgs.pattern} → ${suffix}`,
180
+ message: `🔎︎ grep: ${normalizedArgs.pattern} → ${suffix}`,
181
181
  });
182
182
  return result;
183
183
  }, (error) => buildToolErrorResponse(error, ErrorCode.E_UNKNOWN, args.path ?? '.')), { path: args.path ?? '.' });
@@ -82,7 +82,7 @@ export function registerSearchFilesTool(server, options = {}) {
82
82
  const handler = (args, extra) => withToolDiagnostics('find', () => withToolErrorHandling(async () => {
83
83
  notifyProgress(extra, {
84
84
  current: 0,
85
- message: `⌕ find: ${args.pattern}`,
85
+ message: `🔎︎ find: ${args.pattern}`,
86
86
  });
87
87
  const { signal, cleanup } = createTimedAbortSignal(extra.signal, DEFAULT_SEARCH_TIMEOUT_MS);
88
88
  try {
@@ -94,7 +94,7 @@ export function registerSearchFilesTool(server, options = {}) {
94
94
  const finalCurrent = (sc.filesScanned ?? 0) + 1;
95
95
  notifyProgress(extra, {
96
96
  current: finalCurrent,
97
- message: `⌕ find: ${args.pattern} → ${suffix}`,
97
+ message: `🔎︎ find: ${args.pattern} → ${suffix}`,
98
98
  });
99
99
  return result;
100
100
  }
@@ -17,7 +17,7 @@ export declare function buildResourceLink(params: {
17
17
  mimeType?: string;
18
18
  description?: string;
19
19
  }): ContentBlock;
20
- export declare function buildToolResponse<T>(text: string, structuredContent: T, extraContent?: ContentBlock[]): {
20
+ export declare function buildToolResponse<T>(text: string, structuredContent: T, extraContent?: ContentBlock[], resourceStore?: ResourceStore): {
21
21
  content: ContentBlock[];
22
22
  structuredContent: T;
23
23
  };
@@ -32,7 +32,7 @@ export function buildResourceLink(params) {
32
32
  ...(params.mimeType ? { mimeType: params.mimeType } : {}),
33
33
  };
34
34
  }
35
- function buildContentBlock(text, structuredContent, extraContent = []) {
35
+ function buildContentBlock(text, structuredContent, extraContent = [], resourceStore) {
36
36
  let json;
37
37
  try {
38
38
  json = JSON.stringify(structuredContent);
@@ -51,12 +51,23 @@ function buildContentBlock(text, structuredContent, extraContent = []) {
51
51
  preview,
52
52
  });
53
53
  }
54
+ const externalized = maybeExternalizeTextContent(resourceStore, json, {
55
+ name: 'tool:structuredContent',
56
+ mimeType: 'application/json',
57
+ });
58
+ const jsonContent = externalized
59
+ ? [
60
+ { type: 'text', text: externalized.preview },
61
+ buildResourceLink({
62
+ uri: externalized.entry.uri,
63
+ name: externalized.entry.name,
64
+ mimeType: externalized.entry.mimeType,
65
+ description: 'Full structuredContent JSON',
66
+ }),
67
+ ]
68
+ : [{ type: 'text', text: json }];
54
69
  return {
55
- content: [
56
- { type: 'text', text },
57
- ...extraContent,
58
- { type: 'text', text: json },
59
- ],
70
+ content: [{ type: 'text', text }, ...extraContent, ...jsonContent],
60
71
  structuredContent,
61
72
  };
62
73
  }
@@ -68,8 +79,8 @@ function resolveDetailedError(error, defaultCode, path) {
68
79
  }
69
80
  return detailed;
70
81
  }
71
- export function buildToolResponse(text, structuredContent, extraContent = []) {
72
- return buildContentBlock(text, structuredContent, extraContent);
82
+ export function buildToolResponse(text, structuredContent, extraContent = [], resourceStore) {
83
+ return buildContentBlock(text, structuredContent, extraContent, resourceStore);
73
84
  }
74
85
  function canSendProgress(extra) {
75
86
  return (extra._meta?.progressToken !== undefined &&
@@ -87,7 +87,7 @@ export function registerGetMultipleFileInfoTool(server, options = {}) {
87
87
  };
88
88
  const wrappedHandler = wrapToolHandler(handler, {
89
89
  guard: options.isInitialized,
90
- progressMessage: (args) => `ⓘ+ stat_many: ${args.paths.length} paths`,
90
+ progressMessage: (args) => `🛈 stat_many: ${args.paths.length} paths`,
91
91
  });
92
92
  const taskOptions = options.isInitialized
93
93
  ? { guard: options.isInitialized }
@@ -74,6 +74,6 @@ export function registerGetFileInfoTool(server, options = {}) {
74
74
  }, (error) => buildToolErrorResponse(error, ErrorCode.E_NOT_FOUND, args.path)), { path: args.path });
75
75
  server.registerTool('stat', withDefaultIcons({ ...GET_FILE_INFO_TOOL }, options.iconInfo), wrapToolHandler(handler, {
76
76
  guard: options.isInitialized,
77
- progressMessage: (args) => `ⓘ stat: ${path.basename(args.path)}`,
77
+ progressMessage: (args) => `🛈 stat: ${path.basename(args.path)}`,
78
78
  }));
79
79
  }
@@ -58,9 +58,9 @@ export function registerTreeTool(server, options = {}) {
58
58
  guard: options.isInitialized,
59
59
  progressMessage: (args) => {
60
60
  if (args.path) {
61
- return `⊨ tree: ${path.basename(args.path)}`;
61
+ return `⎇ tree: ${path.basename(args.path)}`;
62
62
  }
63
- return ' tree';
63
+ return ' tree';
64
64
  },
65
65
  });
66
66
  const taskOptions = options.isInitialized
@@ -41,6 +41,6 @@ export function registerWriteFileTool(server, options = {}) {
41
41
  }, (error) => buildToolErrorResponse(error, ErrorCode.E_UNKNOWN, args.path)), { path: args.path });
42
42
  server.registerTool('write', withDefaultIcons({ ...WRITE_FILE_TOOL }, options.iconInfo), wrapToolHandler(handler, {
43
43
  guard: options.isInitialized,
44
- progressMessage: (args) => `✎ write: ${path.basename(args.path)}`,
44
+ progressMessage: (args) => `🛠 write: ${path.basename(args.path)}`,
45
45
  }));
46
46
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@j0hanz/fs-context-mcp",
3
- "version": "2.7.2",
3
+ "version": "2.7.4",
4
4
  "mcpName": "io.github.j0hanz/fs-context",
5
5
  "description": "MCP Server that enables LLMs to interact with the local filesystem.",
6
6
  "type": "module",