@j0hanz/filesystem-mcp 1.2.0 → 1.2.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.
package/dist/config.d.ts CHANGED
@@ -102,6 +102,7 @@ export declare const ErrorCode: {
102
102
  readonly E_NOT_DIRECTORY: "E_NOT_DIRECTORY";
103
103
  readonly E_TOO_LARGE: "E_TOO_LARGE";
104
104
  readonly E_TIMEOUT: "E_TIMEOUT";
105
+ readonly E_CANCELLED: "E_CANCELLED";
105
106
  readonly E_INVALID_PATTERN: "E_INVALID_PATTERN";
106
107
  readonly E_INVALID_INPUT: "E_INVALID_INPUT";
107
108
  readonly E_PERMISSION_DENIED: "E_PERMISSION_DENIED";
package/dist/config.js CHANGED
@@ -5,6 +5,7 @@ export const ErrorCode = {
5
5
  E_NOT_DIRECTORY: 'E_NOT_DIRECTORY',
6
6
  E_TOO_LARGE: 'E_TOO_LARGE',
7
7
  E_TIMEOUT: 'E_TIMEOUT',
8
+ E_CANCELLED: 'E_CANCELLED',
8
9
  E_INVALID_PATTERN: 'E_INVALID_PATTERN',
9
10
  E_INVALID_INPUT: 'E_INVALID_INPUT',
10
11
  E_PERMISSION_DENIED: 'E_PERMISSION_DENIED',
@@ -146,8 +146,6 @@ function isTimeoutErrorSingle(error) {
146
146
  return false;
147
147
  if (error.name === 'TimeoutError')
148
148
  return true;
149
- if (isAbortErrorSingle(error))
150
- return true;
151
149
  const code = getNodeErrorCodeLabel(error);
152
150
  if (code === 'ETIMEDOUT')
153
151
  return true;
@@ -184,6 +182,7 @@ const ERROR_SUGGESTIONS = {
184
182
  [ErrorCode.E_NOT_DIRECTORY]: 'The path points to a file, not a directory. Use read to read file contents.',
185
183
  [ErrorCode.E_TOO_LARGE]: 'The file exceeds the size limit. Use head to read a partial preview, or narrow the scope of what you read.',
186
184
  [ErrorCode.E_TIMEOUT]: 'The operation timed out. Try a smaller scope (narrower path), fewer results (maxResults), or search fewer files.',
185
+ [ErrorCode.E_CANCELLED]: 'The operation was cancelled. This is not an error — no retry is needed unless you want to re-run the operation.',
187
186
  [ErrorCode.E_INVALID_PATTERN]: 'The glob or regex pattern is invalid. Check syntax and escape special characters.',
188
187
  [ErrorCode.E_INVALID_INPUT]: 'One or more input parameters are invalid. Check the tool documentation for correct usage.',
189
188
  [ErrorCode.E_PERMISSION_DENIED]: 'Permission denied by the operating system. Check file permissions.',
@@ -220,6 +219,9 @@ function classifyMessageError(error) {
220
219
  return undefined;
221
220
  }
222
221
  function classifyError(error) {
222
+ if (isAbortError(error)) {
223
+ return ErrorCode.E_CANCELLED;
224
+ }
223
225
  if (isTimeoutLikeError(error)) {
224
226
  return ErrorCode.E_TIMEOUT;
225
227
  }
package/dist/schemas.d.ts CHANGED
@@ -21,6 +21,7 @@ export declare const ToolErrorResponseSchema: z.ZodObject<{
21
21
  readonly E_NOT_DIRECTORY: "E_NOT_DIRECTORY";
22
22
  readonly E_TOO_LARGE: "E_TOO_LARGE";
23
23
  readonly E_TIMEOUT: "E_TIMEOUT";
24
+ readonly E_CANCELLED: "E_CANCELLED";
24
25
  readonly E_INVALID_PATTERN: "E_INVALID_PATTERN";
25
26
  readonly E_INVALID_INPUT: "E_INVALID_INPUT";
26
27
  readonly E_PERMISSION_DENIED: "E_PERMISSION_DENIED";
@@ -112,6 +113,7 @@ export declare const ListAllowedDirectoriesOutputSchema: z.ZodObject<{
112
113
  readonly E_NOT_DIRECTORY: "E_NOT_DIRECTORY";
113
114
  readonly E_TOO_LARGE: "E_TOO_LARGE";
114
115
  readonly E_TIMEOUT: "E_TIMEOUT";
116
+ readonly E_CANCELLED: "E_CANCELLED";
115
117
  readonly E_INVALID_PATTERN: "E_INVALID_PATTERN";
116
118
  readonly E_INVALID_INPUT: "E_INVALID_INPUT";
117
119
  readonly E_PERMISSION_DENIED: "E_PERMISSION_DENIED";
@@ -159,6 +161,7 @@ export declare const ListDirectoryOutputSchema: z.ZodObject<{
159
161
  readonly E_NOT_DIRECTORY: "E_NOT_DIRECTORY";
160
162
  readonly E_TOO_LARGE: "E_TOO_LARGE";
161
163
  readonly E_TIMEOUT: "E_TIMEOUT";
164
+ readonly E_CANCELLED: "E_CANCELLED";
162
165
  readonly E_INVALID_PATTERN: "E_INVALID_PATTERN";
163
166
  readonly E_INVALID_INPUT: "E_INVALID_INPUT";
164
167
  readonly E_PERMISSION_DENIED: "E_PERMISSION_DENIED";
@@ -182,6 +185,7 @@ export declare const SearchFilesOutputSchema: z.ZodObject<{
182
185
  readonly E_NOT_DIRECTORY: "E_NOT_DIRECTORY";
183
186
  readonly E_TOO_LARGE: "E_TOO_LARGE";
184
187
  readonly E_TIMEOUT: "E_TIMEOUT";
188
+ readonly E_CANCELLED: "E_CANCELLED";
185
189
  readonly E_INVALID_PATTERN: "E_INVALID_PATTERN";
186
190
  readonly E_INVALID_INPUT: "E_INVALID_INPUT";
187
191
  readonly E_PERMISSION_DENIED: "E_PERMISSION_DENIED";
@@ -220,6 +224,7 @@ export declare const SearchContentOutputSchema: z.ZodObject<{
220
224
  readonly E_NOT_DIRECTORY: "E_NOT_DIRECTORY";
221
225
  readonly E_TOO_LARGE: "E_TOO_LARGE";
222
226
  readonly E_TIMEOUT: "E_TIMEOUT";
227
+ readonly E_CANCELLED: "E_CANCELLED";
223
228
  readonly E_INVALID_PATTERN: "E_INVALID_PATTERN";
224
229
  readonly E_INVALID_INPUT: "E_INVALID_INPUT";
225
230
  readonly E_PERMISSION_DENIED: "E_PERMISSION_DENIED";
@@ -271,6 +276,7 @@ export declare const TreeOutputSchema: z.ZodObject<{
271
276
  readonly E_NOT_DIRECTORY: "E_NOT_DIRECTORY";
272
277
  readonly E_TOO_LARGE: "E_TOO_LARGE";
273
278
  readonly E_TIMEOUT: "E_TIMEOUT";
279
+ readonly E_CANCELLED: "E_CANCELLED";
274
280
  readonly E_INVALID_PATTERN: "E_INVALID_PATTERN";
275
281
  readonly E_INVALID_INPUT: "E_INVALID_INPUT";
276
282
  readonly E_PERMISSION_DENIED: "E_PERMISSION_DENIED";
@@ -307,6 +313,7 @@ export declare const ReadFileOutputSchema: z.ZodObject<{
307
313
  readonly E_NOT_DIRECTORY: "E_NOT_DIRECTORY";
308
314
  readonly E_TOO_LARGE: "E_TOO_LARGE";
309
315
  readonly E_TIMEOUT: "E_TIMEOUT";
316
+ readonly E_CANCELLED: "E_CANCELLED";
310
317
  readonly E_INVALID_PATTERN: "E_INVALID_PATTERN";
311
318
  readonly E_INVALID_INPUT: "E_INVALID_INPUT";
312
319
  readonly E_PERMISSION_DENIED: "E_PERMISSION_DENIED";
@@ -357,6 +364,7 @@ export declare const ReadMultipleFilesOutputSchema: z.ZodObject<{
357
364
  readonly E_NOT_DIRECTORY: "E_NOT_DIRECTORY";
358
365
  readonly E_TOO_LARGE: "E_TOO_LARGE";
359
366
  readonly E_TIMEOUT: "E_TIMEOUT";
367
+ readonly E_CANCELLED: "E_CANCELLED";
360
368
  readonly E_INVALID_PATTERN: "E_INVALID_PATTERN";
361
369
  readonly E_INVALID_INPUT: "E_INVALID_INPUT";
362
370
  readonly E_PERMISSION_DENIED: "E_PERMISSION_DENIED";
@@ -397,6 +405,7 @@ export declare const GetFileInfoOutputSchema: z.ZodObject<{
397
405
  readonly E_NOT_DIRECTORY: "E_NOT_DIRECTORY";
398
406
  readonly E_TOO_LARGE: "E_TOO_LARGE";
399
407
  readonly E_TIMEOUT: "E_TIMEOUT";
408
+ readonly E_CANCELLED: "E_CANCELLED";
400
409
  readonly E_INVALID_PATTERN: "E_INVALID_PATTERN";
401
410
  readonly E_INVALID_INPUT: "E_INVALID_INPUT";
402
411
  readonly E_PERMISSION_DENIED: "E_PERMISSION_DENIED";
@@ -446,6 +455,7 @@ export declare const GetMultipleFileInfoOutputSchema: z.ZodObject<{
446
455
  readonly E_NOT_DIRECTORY: "E_NOT_DIRECTORY";
447
456
  readonly E_TOO_LARGE: "E_TOO_LARGE";
448
457
  readonly E_TIMEOUT: "E_TIMEOUT";
458
+ readonly E_CANCELLED: "E_CANCELLED";
449
459
  readonly E_INVALID_PATTERN: "E_INVALID_PATTERN";
450
460
  readonly E_INVALID_INPUT: "E_INVALID_INPUT";
451
461
  readonly E_PERMISSION_DENIED: "E_PERMISSION_DENIED";
@@ -471,6 +481,7 @@ export declare const CreateDirectoryOutputSchema: z.ZodObject<{
471
481
  readonly E_NOT_DIRECTORY: "E_NOT_DIRECTORY";
472
482
  readonly E_TOO_LARGE: "E_TOO_LARGE";
473
483
  readonly E_TIMEOUT: "E_TIMEOUT";
484
+ readonly E_CANCELLED: "E_CANCELLED";
474
485
  readonly E_INVALID_PATTERN: "E_INVALID_PATTERN";
475
486
  readonly E_INVALID_INPUT: "E_INVALID_INPUT";
476
487
  readonly E_PERMISSION_DENIED: "E_PERMISSION_DENIED";
@@ -498,6 +509,7 @@ export declare const WriteFileOutputSchema: z.ZodObject<{
498
509
  readonly E_NOT_DIRECTORY: "E_NOT_DIRECTORY";
499
510
  readonly E_TOO_LARGE: "E_TOO_LARGE";
500
511
  readonly E_TIMEOUT: "E_TIMEOUT";
512
+ readonly E_CANCELLED: "E_CANCELLED";
501
513
  readonly E_INVALID_PATTERN: "E_INVALID_PATTERN";
502
514
  readonly E_INVALID_INPUT: "E_INVALID_INPUT";
503
515
  readonly E_PERMISSION_DENIED: "E_PERMISSION_DENIED";
@@ -531,6 +543,7 @@ export declare const EditFileOutputSchema: z.ZodObject<{
531
543
  readonly E_NOT_DIRECTORY: "E_NOT_DIRECTORY";
532
544
  readonly E_TOO_LARGE: "E_TOO_LARGE";
533
545
  readonly E_TIMEOUT: "E_TIMEOUT";
546
+ readonly E_CANCELLED: "E_CANCELLED";
534
547
  readonly E_INVALID_PATTERN: "E_INVALID_PATTERN";
535
548
  readonly E_INVALID_INPUT: "E_INVALID_INPUT";
536
549
  readonly E_PERMISSION_DENIED: "E_PERMISSION_DENIED";
@@ -558,6 +571,7 @@ export declare const MoveFileOutputSchema: z.ZodObject<{
558
571
  readonly E_NOT_DIRECTORY: "E_NOT_DIRECTORY";
559
572
  readonly E_TOO_LARGE: "E_TOO_LARGE";
560
573
  readonly E_TIMEOUT: "E_TIMEOUT";
574
+ readonly E_CANCELLED: "E_CANCELLED";
561
575
  readonly E_INVALID_PATTERN: "E_INVALID_PATTERN";
562
576
  readonly E_INVALID_INPUT: "E_INVALID_INPUT";
563
577
  readonly E_PERMISSION_DENIED: "E_PERMISSION_DENIED";
@@ -585,6 +599,7 @@ export declare const DeleteFileOutputSchema: z.ZodObject<{
585
599
  readonly E_NOT_DIRECTORY: "E_NOT_DIRECTORY";
586
600
  readonly E_TOO_LARGE: "E_TOO_LARGE";
587
601
  readonly E_TIMEOUT: "E_TIMEOUT";
602
+ readonly E_CANCELLED: "E_CANCELLED";
588
603
  readonly E_INVALID_PATTERN: "E_INVALID_PATTERN";
589
604
  readonly E_INVALID_INPUT: "E_INVALID_INPUT";
590
605
  readonly E_PERMISSION_DENIED: "E_PERMISSION_DENIED";
@@ -613,6 +628,7 @@ export declare const CalculateHashOutputSchema: z.ZodObject<{
613
628
  readonly E_NOT_DIRECTORY: "E_NOT_DIRECTORY";
614
629
  readonly E_TOO_LARGE: "E_TOO_LARGE";
615
630
  readonly E_TIMEOUT: "E_TIMEOUT";
631
+ readonly E_CANCELLED: "E_CANCELLED";
616
632
  readonly E_INVALID_PATTERN: "E_INVALID_PATTERN";
617
633
  readonly E_INVALID_INPUT: "E_INVALID_INPUT";
618
634
  readonly E_PERMISSION_DENIED: "E_PERMISSION_DENIED";
@@ -645,6 +661,7 @@ export declare const DiffFilesOutputSchema: z.ZodObject<{
645
661
  readonly E_NOT_DIRECTORY: "E_NOT_DIRECTORY";
646
662
  readonly E_TOO_LARGE: "E_TOO_LARGE";
647
663
  readonly E_TIMEOUT: "E_TIMEOUT";
664
+ readonly E_CANCELLED: "E_CANCELLED";
648
665
  readonly E_INVALID_PATTERN: "E_INVALID_PATTERN";
649
666
  readonly E_INVALID_INPUT: "E_INVALID_INPUT";
650
667
  readonly E_PERMISSION_DENIED: "E_PERMISSION_DENIED";
@@ -675,6 +692,7 @@ export declare const ApplyPatchOutputSchema: z.ZodObject<{
675
692
  readonly E_NOT_DIRECTORY: "E_NOT_DIRECTORY";
676
693
  readonly E_TOO_LARGE: "E_TOO_LARGE";
677
694
  readonly E_TIMEOUT: "E_TIMEOUT";
695
+ readonly E_CANCELLED: "E_CANCELLED";
678
696
  readonly E_INVALID_PATTERN: "E_INVALID_PATTERN";
679
697
  readonly E_INVALID_INPUT: "E_INVALID_INPUT";
680
698
  readonly E_PERMISSION_DENIED: "E_PERMISSION_DENIED";
@@ -718,6 +736,7 @@ export declare const SearchAndReplaceOutputSchema: z.ZodObject<{
718
736
  readonly E_NOT_DIRECTORY: "E_NOT_DIRECTORY";
719
737
  readonly E_TOO_LARGE: "E_TOO_LARGE";
720
738
  readonly E_TIMEOUT: "E_TIMEOUT";
739
+ readonly E_CANCELLED: "E_CANCELLED";
721
740
  readonly E_INVALID_PATTERN: "E_INVALID_PATTERN";
722
741
  readonly E_INVALID_INPUT: "E_INVALID_INPUT";
723
742
  readonly E_PERMISSION_DENIED: "E_PERMISSION_DENIED";
package/dist/server.js CHANGED
@@ -301,22 +301,33 @@ export async function createServer(options = {}) {
301
301
  registerResultResources(server, resourceStore, localIcon);
302
302
  registerCompletions(server);
303
303
  {
304
- const typedServer = server;
305
- const origReg = typedServer.registerTool.bind(server);
306
- typedServer.registerTool = (...regArgs) => {
307
- const handlerIdx = regArgs.length - 1;
308
- const origHandler = regArgs[handlerIdx];
309
- if (typeof origHandler !== 'function')
304
+ const stripStructured = process.env['FS_CONTEXT_STRIP_STRUCTURED'] !== '0';
305
+ if (stripStructured) {
306
+ const typedServer = server;
307
+ const origReg = typedServer.registerTool.bind(server);
308
+ typedServer.registerTool = (...regArgs) => {
309
+ // Strip outputSchema so SDK won't require structuredContent
310
+ if (regArgs.length >= 2 &&
311
+ regArgs[1] &&
312
+ typeof regArgs[1] === 'object') {
313
+ const config = { ...regArgs[1] };
314
+ delete config['outputSchema'];
315
+ regArgs[1] = config;
316
+ }
317
+ const handlerIdx = regArgs.length - 1;
318
+ const origHandler = regArgs[handlerIdx];
319
+ if (typeof origHandler !== 'function')
320
+ return origReg(...regArgs);
321
+ regArgs[handlerIdx] = async (...hArgs) => {
322
+ const r = await origHandler(...hArgs);
323
+ if (!r || typeof r !== 'object')
324
+ return r;
325
+ const record = r;
326
+ return Object.fromEntries(Object.entries(record).filter(([key]) => key !== 'structuredContent'));
327
+ };
310
328
  return origReg(...regArgs);
311
- regArgs[handlerIdx] = async (...hArgs) => {
312
- const r = await origHandler(...hArgs);
313
- if (!r || typeof r !== 'object')
314
- return r;
315
- const record = r;
316
- return Object.fromEntries(Object.entries(record).filter(([key]) => key !== 'structuredContent'));
317
329
  };
318
- return origReg(...regArgs);
319
- };
330
+ }
320
331
  }
321
332
  registerAllTools(server, {
322
333
  resourceStore,
@@ -5,7 +5,7 @@ import { MAX_TEXT_FILE_SIZE } from '../lib/constants.js';
5
5
  import { ErrorCode, McpError } from '../lib/errors.js';
6
6
  import { atomicWriteFile, withAbort } from '../lib/fs-helpers.js';
7
7
  import { validateExistingPath } from '../lib/path-validation.js';
8
- import { ApplyPatchInputSchema, } from '../schemas.js';
8
+ import { ApplyPatchInputSchema, ApplyPatchOutputSchema } from '../schemas.js';
9
9
  import { buildToolErrorResponse, buildToolResponse, DESTRUCTIVE_WRITE_TOOL_ANNOTATIONS, executeToolWithDiagnostics, withDefaultIcons, wrapToolHandler, } from './shared.js';
10
10
  import { registerToolTaskIfAvailable } from './task-support.js';
11
11
  const APPLY_PATCH_TOOL = {
@@ -14,6 +14,7 @@ const APPLY_PATCH_TOOL = {
14
14
  'Generate the patch with `diff_files`, then validate with `dryRun: true` before writing. ' +
15
15
  'On failure, regenerate a fresh patch via `diff_files` against the current file content and retry.',
16
16
  inputSchema: ApplyPatchInputSchema,
17
+ outputSchema: ApplyPatchOutputSchema,
17
18
  annotations: DESTRUCTIVE_WRITE_TOOL_ANNOTATIONS,
18
19
  };
19
20
  function assertPatchTargetSizeWithinLimit(filePath, size, maxFileSize) {
@@ -8,7 +8,7 @@ import { isIgnoredByGitignore, loadRootGitignore, } from '../lib/file-operations
8
8
  import { globEntries } from '../lib/file-operations/glob-engine.js';
9
9
  import { assertNotAborted, withAbort } from '../lib/fs-helpers.js';
10
10
  import { validateExistingPath } from '../lib/path-validation.js';
11
- import { CalculateHashInputSchema, } from '../schemas.js';
11
+ import { CalculateHashInputSchema, CalculateHashOutputSchema, } from '../schemas.js';
12
12
  import { buildToolErrorResponse, buildToolResponse, createProgressReporter, executeToolWithDiagnostics, notifyProgress, READ_ONLY_TOOL_ANNOTATIONS, withDefaultIcons, wrapToolHandler, } from './shared.js';
13
13
  import { registerToolTaskIfAvailable } from './task-support.js';
14
14
  const WINDOWS_PATH_SEPARATOR = /\\/gu;
@@ -16,6 +16,7 @@ const CALCULATE_HASH_TOOL = {
16
16
  title: 'Calculate Hash',
17
17
  description: 'Calculate SHA-256 hash of a file or directory.',
18
18
  inputSchema: CalculateHashInputSchema,
19
+ outputSchema: CalculateHashOutputSchema,
19
20
  annotations: READ_ONLY_TOOL_ANNOTATIONS,
20
21
  };
21
22
  async function hashFile(filePath, encoding, signal) {
@@ -3,13 +3,14 @@ import * as path from 'node:path';
3
3
  import { ErrorCode } from '../lib/errors.js';
4
4
  import { withAbort } from '../lib/fs-helpers.js';
5
5
  import { validatePathForWrite } from '../lib/path-validation.js';
6
- import { CreateDirectoryInputSchema, } from '../schemas.js';
6
+ import { CreateDirectoryInputSchema, CreateDirectoryOutputSchema, } from '../schemas.js';
7
7
  import { buildToolErrorResponse, buildToolResponse, executeToolWithDiagnostics, IDEMPOTENT_WRITE_TOOL_ANNOTATIONS, withDefaultIcons, wrapToolHandler, } from './shared.js';
8
8
  import { registerToolTaskIfAvailable } from './task-support.js';
9
9
  const CREATE_DIRECTORY_TOOL = {
10
10
  title: 'Create Directory',
11
11
  description: 'Create a new directory at the specified path (recursive)',
12
12
  inputSchema: CreateDirectoryInputSchema,
13
+ outputSchema: CreateDirectoryOutputSchema,
13
14
  annotations: IDEMPOTENT_WRITE_TOOL_ANNOTATIONS,
14
15
  };
15
16
  async function handleCreateDirectory(args, signal) {
@@ -3,13 +3,14 @@ import * as path from 'node:path';
3
3
  import { ErrorCode, isNodeError } from '../lib/errors.js';
4
4
  import { withAbort } from '../lib/fs-helpers.js';
5
5
  import { validatePathForWrite } from '../lib/path-validation.js';
6
- import { DeleteFileInputSchema, } from '../schemas.js';
6
+ import { DeleteFileInputSchema, DeleteFileOutputSchema } from '../schemas.js';
7
7
  import { buildToolErrorResponse, buildToolResponse, DESTRUCTIVE_WRITE_TOOL_ANNOTATIONS, executeToolWithDiagnostics, withDefaultIcons, wrapToolHandler, } from './shared.js';
8
8
  import { registerToolTaskIfAvailable } from './task-support.js';
9
9
  const DELETE_FILE_TOOL = {
10
10
  title: 'Delete File',
11
11
  description: 'Delete a file or directory.',
12
12
  inputSchema: DeleteFileInputSchema,
13
+ outputSchema: DeleteFileOutputSchema,
13
14
  annotations: DESTRUCTIVE_WRITE_TOOL_ANNOTATIONS,
14
15
  };
15
16
  async function handleDeleteFile(args, signal) {
@@ -5,7 +5,7 @@ import { MAX_TEXT_FILE_SIZE } from '../lib/constants.js';
5
5
  import { ErrorCode, McpError } from '../lib/errors.js';
6
6
  import { withAbort } from '../lib/fs-helpers.js';
7
7
  import { validateExistingPath } from '../lib/path-validation.js';
8
- import { DiffFilesInputSchema, } from '../schemas.js';
8
+ import { DiffFilesInputSchema, DiffFilesOutputSchema } from '../schemas.js';
9
9
  import { buildResourceLink, buildToolErrorResponse, buildToolResponse, executeToolWithDiagnostics, maybeExternalizeTextContent, READ_ONLY_TOOL_ANNOTATIONS, withDefaultIcons, wrapToolHandler, } from './shared.js';
10
10
  const DIFF_FILES_TOOL = {
11
11
  title: 'Diff Files',
@@ -13,6 +13,7 @@ const DIFF_FILES_TOOL = {
13
13
  'Output feeds directly into `apply_patch`. ' +
14
14
  'Check `isIdentical` in the response — if true, the files are already in sync and no patch is needed.',
15
15
  inputSchema: DiffFilesInputSchema,
16
+ outputSchema: DiffFilesOutputSchema,
16
17
  annotations: READ_ONLY_TOOL_ANNOTATIONS,
17
18
  };
18
19
  function assertDiffFileSizeWithinLimit(filePath, size, maxFileSize) {
@@ -3,7 +3,7 @@ import * as path from 'node:path';
3
3
  import { ErrorCode } from '../lib/errors.js';
4
4
  import { atomicWriteFile } from '../lib/fs-helpers.js';
5
5
  import { validateExistingPath } from '../lib/path-validation.js';
6
- import { EditFileInputSchema } from '../schemas.js';
6
+ import { EditFileInputSchema, EditFileOutputSchema } from '../schemas.js';
7
7
  import { buildToolErrorResponse, buildToolResponse, DESTRUCTIVE_WRITE_TOOL_ANNOTATIONS, executeToolWithDiagnostics, withDefaultIcons, wrapToolHandler, } from './shared.js';
8
8
  const EDIT_FILE_TOOL = {
9
9
  title: 'Edit File',
@@ -12,6 +12,7 @@ const EDIT_FILE_TOOL = {
12
12
  '`oldText` must match exactly — include 3–5 lines of surrounding context to uniquely target the location. ' +
13
13
  'Use `dryRun: true` to validate edits before writing.',
14
14
  inputSchema: EditFileInputSchema,
15
+ outputSchema: EditFileOutputSchema,
15
16
  annotations: DESTRUCTIVE_WRITE_TOOL_ANNOTATIONS,
16
17
  };
17
18
  function applyEdits(content, edits) {
@@ -3,7 +3,7 @@ import { formatOperationSummary, joinLines } from '../config.js';
3
3
  import { DEFAULT_EXCLUDE_PATTERNS } from '../lib/constants.js';
4
4
  import { ErrorCode } from '../lib/errors.js';
5
5
  import { listDirectory } from '../lib/file-operations/list-directory.js';
6
- import { ListDirectoryInputSchema, } from '../schemas.js';
6
+ import { ListDirectoryInputSchema, ListDirectoryOutputSchema, } from '../schemas.js';
7
7
  import { buildToolErrorResponse, buildToolResponse, executeToolWithDiagnostics, READ_ONLY_TOOL_ANNOTATIONS, resolvePathOrRoot, withDefaultIcons, wrapToolHandler, } from './shared.js';
8
8
  const LIST_DIRECTORY_TOOL = {
9
9
  title: 'List Directory',
@@ -13,6 +13,7 @@ const LIST_DIRECTORY_TOOL = {
13
13
  'Use includeIgnored=true to include ignored directories like node_modules. ' +
14
14
  'For recursive searches, use find instead.',
15
15
  inputSchema: ListDirectoryInputSchema,
16
+ outputSchema: ListDirectoryOutputSchema,
16
17
  annotations: READ_ONLY_TOOL_ANNOTATIONS,
17
18
  };
18
19
  function buildListTextResult(result) {
@@ -3,13 +3,14 @@ import * as path from 'node:path';
3
3
  import { ErrorCode, isNodeError } from '../lib/errors.js';
4
4
  import { withAbort } from '../lib/fs-helpers.js';
5
5
  import { validateExistingPath, validatePathForWrite, } from '../lib/path-validation.js';
6
- import { MoveFileInputSchema } from '../schemas.js';
6
+ import { MoveFileInputSchema, MoveFileOutputSchema } from '../schemas.js';
7
7
  import { buildToolErrorResponse, buildToolResponse, DESTRUCTIVE_WRITE_TOOL_ANNOTATIONS, executeToolWithDiagnostics, withDefaultIcons, wrapToolHandler, } from './shared.js';
8
8
  import { registerToolTaskIfAvailable } from './task-support.js';
9
9
  const MOVE_FILE_TOOL = {
10
10
  title: 'Move File',
11
11
  description: 'Move or rename a file or directory.',
12
12
  inputSchema: MoveFileInputSchema,
13
+ outputSchema: MoveFileOutputSchema,
13
14
  annotations: DESTRUCTIVE_WRITE_TOOL_ANNOTATIONS,
14
15
  };
15
16
  async function handleMoveFile(args, signal) {
@@ -2,7 +2,7 @@ import * as path from 'node:path';
2
2
  import { DEFAULT_READ_MANY_MAX_TOTAL_SIZE, DEFAULT_SEARCH_TIMEOUT_MS, } from '../lib/constants.js';
3
3
  import { ErrorCode } from '../lib/errors.js';
4
4
  import { readMultipleFiles } from '../lib/file-operations/read-multiple-files.js';
5
- import { ReadMultipleFilesInputSchema, } from '../schemas.js';
5
+ import { ReadMultipleFilesInputSchema, ReadMultipleFilesOutputSchema, } from '../schemas.js';
6
6
  import { buildResourceLink, buildToolErrorResponse, buildToolResponse, executeToolWithDiagnostics, maybeExternalizeTextContent, READ_ONLY_TOOL_ANNOTATIONS, withDefaultIcons, wrapToolHandler, } from './shared.js';
7
7
  import { registerToolTaskIfAvailable } from './task-support.js';
8
8
  const READ_MULTIPLE_FILES_TOOL = {
@@ -11,6 +11,7 @@ const READ_MULTIPLE_FILES_TOOL = {
11
11
  'Returns contents and metadata for each file. ' +
12
12
  'For single file, use read for simpler output.',
13
13
  inputSchema: ReadMultipleFilesInputSchema,
14
+ outputSchema: ReadMultipleFilesOutputSchema,
14
15
  annotations: READ_ONLY_TOOL_ANNOTATIONS,
15
16
  };
16
17
  async function handleReadMultipleFiles(args, signal, resourceStore) {
@@ -2,7 +2,7 @@ import * as path from 'node:path';
2
2
  import { DEFAULT_SEARCH_TIMEOUT_MS, MAX_TEXT_FILE_SIZE, } from '../lib/constants.js';
3
3
  import { ErrorCode } from '../lib/errors.js';
4
4
  import { readFile } from '../lib/fs-helpers.js';
5
- import { ReadFileInputSchema } from '../schemas.js';
5
+ import { ReadFileInputSchema, ReadFileOutputSchema } from '../schemas.js';
6
6
  import { buildResourceLink, buildToolErrorResponse, buildToolResponse, executeToolWithDiagnostics, maybeExternalizeTextContent, READ_ONLY_TOOL_ANNOTATIONS, withDefaultIcons, wrapToolHandler, } from './shared.js';
7
7
  import { registerToolTaskIfAvailable } from './task-support.js';
8
8
  const READ_FILE_TOOL = {
@@ -11,6 +11,7 @@ const READ_FILE_TOOL = {
11
11
  'Use head parameter to preview the first N lines of large files. ' +
12
12
  'For multiple files, use read_many for efficiency.',
13
13
  inputSchema: ReadFileInputSchema,
14
+ outputSchema: ReadFileOutputSchema,
14
15
  annotations: READ_ONLY_TOOL_ANNOTATIONS,
15
16
  };
16
17
  async function handleReadFile(args, signal, resourceStore) {
@@ -7,7 +7,7 @@ import { ErrorCode, formatUnknownErrorMessage, McpError, } from '../lib/errors.j
7
7
  import { globEntries } from '../lib/file-operations/glob-engine.js';
8
8
  import { atomicWriteFile, withAbort } from '../lib/fs-helpers.js';
9
9
  import { validateExistingPath, validatePathForWrite, } from '../lib/path-validation.js';
10
- import { SearchAndReplaceInputSchema, } from '../schemas.js';
10
+ import { SearchAndReplaceInputSchema, SearchAndReplaceOutputSchema, } from '../schemas.js';
11
11
  import { buildToolErrorResponse, buildToolResponse, createProgressReporter, DESTRUCTIVE_WRITE_TOOL_ANNOTATIONS, executeToolWithDiagnostics, notifyProgress, resolvePathOrRoot, withDefaultIcons, wrapToolHandler, } from './shared.js';
12
12
  import { registerToolTaskIfAvailable } from './task-support.js';
13
13
  const SEARCH_AND_REPLACE_TOOL = {
@@ -18,6 +18,7 @@ const SEARCH_AND_REPLACE_TOOL = {
18
18
  'Always run with `dryRun: true` first to verify matches before writing. ' +
19
19
  'Literal mode (default) matches exact text; `isRegex: true` enables RE2 regex with capture groups ($1, $2).',
20
20
  inputSchema: SearchAndReplaceInputSchema,
21
+ outputSchema: SearchAndReplaceOutputSchema,
21
22
  annotations: DESTRUCTIVE_WRITE_TOOL_ANNOTATIONS,
22
23
  };
23
24
  const MAX_FAILURES = 20;
@@ -1,7 +1,7 @@
1
1
  import { joinLines } from '../config.js';
2
2
  import { ErrorCode } from '../lib/errors.js';
3
3
  import { getAllowedDirectories } from '../lib/path-validation.js';
4
- import { ListAllowedDirectoriesInputSchema, } from '../schemas.js';
4
+ import { ListAllowedDirectoriesInputSchema, ListAllowedDirectoriesOutputSchema, } from '../schemas.js';
5
5
  import { buildToolErrorResponse, buildToolResponse, executeToolWithDiagnostics, READ_ONLY_TOOL_ANNOTATIONS, withDefaultIcons, wrapToolHandler, } from './shared.js';
6
6
  const LIST_ALLOWED_DIRECTORIES_TOOL = {
7
7
  title: 'Workspace Roots',
@@ -9,6 +9,7 @@ const LIST_ALLOWED_DIRECTORIES_TOOL = {
9
9
  'Call this first to see available directories. ' +
10
10
  'All other tools only work within these directories.',
11
11
  inputSchema: ListAllowedDirectoriesInputSchema,
12
+ outputSchema: ListAllowedDirectoriesOutputSchema,
12
13
  annotations: READ_ONLY_TOOL_ANNOTATIONS,
13
14
  };
14
15
  function buildTextRoots(dirs) {
@@ -4,7 +4,7 @@ import { formatOperationSummary, joinLines } from '../config.js';
4
4
  import { DEFAULT_EXCLUDE_PATTERNS } from '../lib/constants.js';
5
5
  import { ErrorCode, formatUnknownErrorMessage, McpError, } from '../lib/errors.js';
6
6
  import { searchContent } from '../lib/file-operations/search-content.js';
7
- import { SearchContentInputSchema, } from '../schemas.js';
7
+ import { SearchContentInputSchema, SearchContentOutputSchema, } from '../schemas.js';
8
8
  import { buildResourceLink, buildToolErrorResponse, buildToolResponse, createProgressReporter, executeToolWithDiagnostics, notifyProgress, READ_ONLY_TOOL_ANNOTATIONS, resolvePathOrRoot, withDefaultIcons, wrapToolHandler, } from './shared.js';
9
9
  import { registerToolTaskIfAvailable } from './task-support.js';
10
10
  const MAX_INLINE_MATCHES = 50;
@@ -16,6 +16,7 @@ const SEARCH_CONTENT_TOOL = {
16
16
  'Use `filePattern` to scope by file type (e.g. `**/*.ts`) and avoid noisy results. ' +
17
17
  'Use includeHidden=true to include hidden files and directories.',
18
18
  inputSchema: SearchContentInputSchema,
19
+ outputSchema: SearchContentOutputSchema,
19
20
  annotations: READ_ONLY_TOOL_ANNOTATIONS,
20
21
  };
21
22
  function assertValidRegexPattern(pattern) {
@@ -3,7 +3,7 @@ import { formatOperationSummary, joinLines } from '../config.js';
3
3
  import { DEFAULT_EXCLUDE_PATTERNS, DEFAULT_SEARCH_TIMEOUT_MS, } from '../lib/constants.js';
4
4
  import { ErrorCode } from '../lib/errors.js';
5
5
  import { searchFiles } from '../lib/file-operations/search-files.js';
6
- import { SearchFilesInputSchema, } from '../schemas.js';
6
+ import { SearchFilesInputSchema, SearchFilesOutputSchema } from '../schemas.js';
7
7
  import { buildToolErrorResponse, buildToolResponse, createProgressReporter, executeToolWithDiagnostics, notifyProgress, READ_ONLY_TOOL_ANNOTATIONS, resolvePathOrRoot, withDefaultIcons, wrapToolHandler, } from './shared.js';
8
8
  import { registerToolTaskIfAvailable } from './task-support.js';
9
9
  const SEARCH_FILES_TOOL = {
@@ -13,6 +13,7 @@ const SEARCH_FILES_TOOL = {
13
13
  'For text search inside files, use grep. ' +
14
14
  'To bulk-edit the matched files, pass the same glob pattern to search_and_replace.',
15
15
  inputSchema: SearchFilesInputSchema,
16
+ outputSchema: SearchFilesOutputSchema,
16
17
  annotations: READ_ONLY_TOOL_ANNOTATIONS,
17
18
  };
18
19
  async function handleSearchFiles(args, signal, onProgress) {
@@ -2,13 +2,14 @@ import { formatBytes, joinLines } from '../config.js';
2
2
  import { DEFAULT_SEARCH_TIMEOUT_MS } from '../lib/constants.js';
3
3
  import { ErrorCode } from '../lib/errors.js';
4
4
  import { getMultipleFileInfo } from '../lib/file-operations/file-info.js';
5
- import { GetMultipleFileInfoInputSchema, } from '../schemas.js';
5
+ import { GetMultipleFileInfoInputSchema, GetMultipleFileInfoOutputSchema, } from '../schemas.js';
6
6
  import { buildFileInfoPayload, buildToolErrorResponse, buildToolResponse, executeToolWithDiagnostics, READ_ONLY_TOOL_ANNOTATIONS, withDefaultIcons, wrapToolHandler, } from './shared.js';
7
7
  import { registerToolTaskIfAvailable } from './task-support.js';
8
8
  const GET_MULTIPLE_FILE_INFO_TOOL = {
9
9
  title: 'Get Multiple File Info',
10
10
  description: 'Get metadata for multiple files or directories in one request.',
11
11
  inputSchema: GetMultipleFileInfoInputSchema,
12
+ outputSchema: GetMultipleFileInfoOutputSchema,
12
13
  annotations: READ_ONLY_TOOL_ANNOTATIONS,
13
14
  };
14
15
  function formatFileInfoDetail(info) {
@@ -3,12 +3,13 @@ import { formatBytes, joinLines } from '../config.js';
3
3
  import { DEFAULT_SEARCH_TIMEOUT_MS } from '../lib/constants.js';
4
4
  import { ErrorCode } from '../lib/errors.js';
5
5
  import { getFileInfo } from '../lib/file-operations/file-info.js';
6
- import { GetFileInfoInputSchema, } from '../schemas.js';
6
+ import { GetFileInfoInputSchema, GetFileInfoOutputSchema } from '../schemas.js';
7
7
  import { buildFileInfoPayload, buildToolErrorResponse, buildToolResponse, executeToolWithDiagnostics, READ_ONLY_TOOL_ANNOTATIONS, withDefaultIcons, wrapToolHandler, } from './shared.js';
8
8
  const GET_FILE_INFO_TOOL = {
9
9
  title: 'Get File Info',
10
10
  description: 'Get metadata (size, modified time, permissions, mime type) for a file or directory.',
11
11
  inputSchema: GetFileInfoInputSchema,
12
+ outputSchema: GetFileInfoOutputSchema,
12
13
  annotations: READ_ONLY_TOOL_ANNOTATIONS,
13
14
  };
14
15
  function formatFileInfoDetails(info) {
@@ -2,7 +2,7 @@ import * as path from 'node:path';
2
2
  import { DEFAULT_SEARCH_TIMEOUT_MS } from '../lib/constants.js';
3
3
  import { ErrorCode } from '../lib/errors.js';
4
4
  import { formatTreeAscii, treeDirectory } from '../lib/file-operations/tree.js';
5
- import { TreeInputSchema } from '../schemas.js';
5
+ import { TreeInputSchema, TreeOutputSchema } from '../schemas.js';
6
6
  import { buildToolErrorResponse, buildToolResponse, executeToolWithDiagnostics, READ_ONLY_TOOL_ANNOTATIONS, resolvePathOrRoot, withDefaultIcons, wrapToolHandler, } from './shared.js';
7
7
  import { registerToolTaskIfAvailable } from './task-support.js';
8
8
  const TREE_TOOL = {
@@ -11,6 +11,7 @@ const TREE_TOOL = {
11
11
  'Returns an ASCII tree for quick scanning and a structured JSON tree for programmatic use. ' +
12
12
  'Note: maxDepth=0 returns only the root node with empty children array.',
13
13
  inputSchema: TreeInputSchema,
14
+ outputSchema: TreeOutputSchema,
14
15
  annotations: READ_ONLY_TOOL_ANNOTATIONS,
15
16
  };
16
17
  async function handleTree(args, signal) {
@@ -3,13 +3,14 @@ import * as path from 'node:path';
3
3
  import { ErrorCode } from '../lib/errors.js';
4
4
  import { atomicWriteFile, withAbort } from '../lib/fs-helpers.js';
5
5
  import { validatePathForWrite } from '../lib/path-validation.js';
6
- import { WriteFileInputSchema, } from '../schemas.js';
6
+ import { WriteFileInputSchema, WriteFileOutputSchema } from '../schemas.js';
7
7
  import { buildToolErrorResponse, buildToolResponse, DESTRUCTIVE_WRITE_TOOL_ANNOTATIONS, executeToolWithDiagnostics, withDefaultIcons, wrapToolHandler, } from './shared.js';
8
8
  import { registerToolTaskIfAvailable } from './task-support.js';
9
9
  const WRITE_FILE_TOOL = {
10
10
  title: 'Write File',
11
11
  description: 'Write content to a file. Creates the file if it does not exist.',
12
12
  inputSchema: WriteFileInputSchema,
13
+ outputSchema: WriteFileOutputSchema,
13
14
  annotations: DESTRUCTIVE_WRITE_TOOL_ANNOTATIONS,
14
15
  };
15
16
  async function handleWriteFile(args, signal) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@j0hanz/filesystem-mcp",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "mcpName": "io.github.j0hanz/filesystem-mcp",
5
5
  "description": "MCP Server that enables LLMs to interact with the local filesystem.",
6
6
  "type": "module",