@j0hanz/fs-context-mcp 2.0.6 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/README.md +60 -12
  2. package/dist/config.d.ts +1 -0
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js.map +1 -1
  5. package/dist/instructions.md +27 -118
  6. package/dist/lib/constants.d.ts +1 -0
  7. package/dist/lib/constants.d.ts.map +1 -1
  8. package/dist/lib/constants.js +1 -0
  9. package/dist/lib/constants.js.map +1 -1
  10. package/dist/lib/file-operations/file-info.d.ts.map +1 -1
  11. package/dist/lib/file-operations/file-info.js +2 -0
  12. package/dist/lib/file-operations/file-info.js.map +1 -1
  13. package/dist/lib/file-operations/gitignore.d.ts +6 -0
  14. package/dist/lib/file-operations/gitignore.d.ts.map +1 -0
  15. package/dist/lib/file-operations/gitignore.js +42 -0
  16. package/dist/lib/file-operations/gitignore.js.map +1 -0
  17. package/dist/lib/file-operations/read-multiple-files.d.ts +5 -1
  18. package/dist/lib/file-operations/read-multiple-files.d.ts.map +1 -1
  19. package/dist/lib/file-operations/read-multiple-files.js +48 -17
  20. package/dist/lib/file-operations/read-multiple-files.js.map +1 -1
  21. package/dist/lib/file-operations/search-content-scan.d.ts +29 -0
  22. package/dist/lib/file-operations/search-content-scan.d.ts.map +1 -0
  23. package/dist/lib/file-operations/search-content-scan.js +468 -0
  24. package/dist/lib/file-operations/search-content-scan.js.map +1 -0
  25. package/dist/lib/file-operations/search-content-worker-api.d.ts +56 -0
  26. package/dist/lib/file-operations/search-content-worker-api.d.ts.map +1 -0
  27. package/dist/lib/file-operations/search-content-worker-api.js +239 -0
  28. package/dist/lib/file-operations/search-content-worker-api.js.map +1 -0
  29. package/dist/lib/file-operations/search-content.d.ts.map +1 -1
  30. package/dist/lib/file-operations/search-content.js +59 -53
  31. package/dist/lib/file-operations/search-content.js.map +1 -1
  32. package/dist/lib/file-operations/search-files.d.ts +1 -0
  33. package/dist/lib/file-operations/search-files.d.ts.map +1 -1
  34. package/dist/lib/file-operations/search-files.js +11 -2
  35. package/dist/lib/file-operations/search-files.js.map +1 -1
  36. package/dist/lib/file-operations/tree.d.ts +25 -0
  37. package/dist/lib/file-operations/tree.d.ts.map +1 -0
  38. package/dist/lib/file-operations/tree.js +172 -0
  39. package/dist/lib/file-operations/tree.js.map +1 -0
  40. package/dist/lib/fs-helpers.d.ts +5 -1
  41. package/dist/lib/fs-helpers.d.ts.map +1 -1
  42. package/dist/lib/fs-helpers.js +131 -14
  43. package/dist/lib/fs-helpers.js.map +1 -1
  44. package/dist/lib/path-validation.d.ts.map +1 -1
  45. package/dist/lib/path-validation.js +15 -17
  46. package/dist/lib/path-validation.js.map +1 -1
  47. package/dist/lib/resource-store.d.ts +23 -0
  48. package/dist/lib/resource-store.d.ts.map +1 -0
  49. package/dist/lib/resource-store.js +75 -0
  50. package/dist/lib/resource-store.js.map +1 -0
  51. package/dist/lib/strict-stdio-transport.d.ts +31 -0
  52. package/dist/lib/strict-stdio-transport.d.ts.map +1 -0
  53. package/dist/lib/strict-stdio-transport.js +158 -0
  54. package/dist/lib/strict-stdio-transport.js.map +1 -0
  55. package/dist/resources.d.ts +5 -0
  56. package/dist/resources.d.ts.map +1 -0
  57. package/dist/resources.js +43 -0
  58. package/dist/resources.js.map +1 -0
  59. package/dist/schemas.d.ts +78 -12
  60. package/dist/schemas.d.ts.map +1 -1
  61. package/dist/schemas.js +125 -24
  62. package/dist/schemas.js.map +1 -1
  63. package/dist/server.d.ts.map +1 -1
  64. package/dist/server.js +27 -3
  65. package/dist/server.js.map +1 -1
  66. package/dist/tooling/tool-response.d.ts +32 -0
  67. package/dist/tooling/tool-response.d.ts.map +1 -0
  68. package/dist/tooling/tool-response.js +63 -0
  69. package/dist/tooling/tool-response.js.map +1 -0
  70. package/dist/tooling/tools-registry.d.ts +5 -0
  71. package/dist/tooling/tools-registry.d.ts.map +1 -0
  72. package/dist/tooling/tools-registry.js +532 -0
  73. package/dist/tooling/tools-registry.js.map +1 -0
  74. package/dist/tools.d.ts +8 -10
  75. package/dist/tools.d.ts.map +1 -1
  76. package/dist/tools.js +235 -28
  77. package/dist/tools.js.map +1 -1
  78. package/package.json +5 -3
@@ -0,0 +1,158 @@
1
+ function isObject(value) {
2
+ return typeof value === 'object' && value !== null;
3
+ }
4
+ function getMethod(value) {
5
+ if (!isObject(value))
6
+ return undefined;
7
+ const { method } = value;
8
+ return typeof method === 'string' ? method : undefined;
9
+ }
10
+ function parseId(value) {
11
+ if (!isObject(value) || !('id' in value)) {
12
+ return { value: null, isValid: false };
13
+ }
14
+ const { id } = value;
15
+ if (typeof id === 'string' || typeof id === 'number' || id === null) {
16
+ return { value: id, isValid: true };
17
+ }
18
+ return { value: null, isValid: false };
19
+ }
20
+ function isRequest(value) {
21
+ if (!isObject(value))
22
+ return false;
23
+ const { id } = value;
24
+ return typeof id === 'string' || typeof id === 'number';
25
+ }
26
+ /**
27
+ * Strict stdio transport wrapper that:
28
+ * - Rejects JSON-RPC batch payloads (arrays) with a JSON-RPC error
29
+ * - Enforces lifecycle: `initialize` must be the first request
30
+ *
31
+ * This addresses interoperability issues where some clients send malformed input
32
+ * (batches) or where SDKs do not strictly enforce initialization ordering.
33
+ */
34
+ export class StrictStdioServerTransport {
35
+ stdin;
36
+ stdout;
37
+ started = false;
38
+ buffer = '';
39
+ seenInitializeRequest = false;
40
+ onmessage;
41
+ onerror;
42
+ onclose;
43
+ constructor(stdin, stdout) {
44
+ this.stdin = stdin ?? process.stdin;
45
+ this.stdout = stdout ?? process.stdout;
46
+ }
47
+ start() {
48
+ if (this.started) {
49
+ throw new Error('StrictStdioServerTransport already started');
50
+ }
51
+ this.started = true;
52
+ this.stdin.on('data', this.onData);
53
+ this.stdin.on('error', this.onError);
54
+ return Promise.resolve();
55
+ }
56
+ close() {
57
+ this.stdin.off('data', this.onData);
58
+ this.stdin.off('error', this.onError);
59
+ this.buffer = '';
60
+ this.onclose?.();
61
+ return Promise.resolve();
62
+ }
63
+ async send(message) {
64
+ const json = `${JSON.stringify(message)}\n`;
65
+ await new Promise((resolve) => {
66
+ if (this.stdout.write(json, 'utf8')) {
67
+ resolve();
68
+ }
69
+ else {
70
+ this.stdout.once('drain', () => {
71
+ resolve();
72
+ });
73
+ }
74
+ });
75
+ }
76
+ onData = (chunk) => {
77
+ this.buffer +=
78
+ typeof chunk === 'string' ? chunk : chunk.toString('utf8');
79
+ this.processBuffer();
80
+ };
81
+ onError = (error) => {
82
+ this.onerror?.(error);
83
+ };
84
+ async sendJsonRpcError(id, code, message, extra) {
85
+ const payload = {
86
+ jsonrpc: '2.0',
87
+ id,
88
+ error: {
89
+ code,
90
+ message,
91
+ ...(extra?.data !== undefined ? { data: extra.data } : {}),
92
+ },
93
+ };
94
+ try {
95
+ await this.send(payload);
96
+ }
97
+ catch (sendError) {
98
+ this.onerror?.(sendError instanceof Error ? sendError : new Error(String(sendError)));
99
+ }
100
+ }
101
+ processBuffer() {
102
+ while (this.buffer.length > 0) {
103
+ const newlineIndex = this.buffer.indexOf('\n');
104
+ if (newlineIndex < 0)
105
+ return;
106
+ const rawLine = this.buffer.slice(0, newlineIndex);
107
+ this.buffer = this.buffer.slice(newlineIndex + 1);
108
+ const line = rawLine.endsWith('\r') ? rawLine.slice(0, -1) : rawLine;
109
+ if (line.trim().length === 0)
110
+ continue;
111
+ void this.processLine(line);
112
+ }
113
+ }
114
+ async processLine(line) {
115
+ let parsed;
116
+ try {
117
+ parsed = JSON.parse(line);
118
+ }
119
+ catch (error) {
120
+ const message = error instanceof Error ? error.message : String(error);
121
+ await this.sendJsonRpcError(null, -32700, 'Parse error', { data: message });
122
+ return;
123
+ }
124
+ await this.handleIncomingMessage(parsed);
125
+ }
126
+ async handleIncomingMessage(message) {
127
+ // JSON-RPC batching is not supported in MCP 2025-06-18+.
128
+ if (Array.isArray(message)) {
129
+ await this.sendJsonRpcError(null, -32600, 'Invalid Request');
130
+ return;
131
+ }
132
+ if (!isObject(message)) {
133
+ await this.sendJsonRpcError(null, -32600, 'Invalid Request');
134
+ return;
135
+ }
136
+ const method = getMethod(message);
137
+ if (!method) {
138
+ await this.sendJsonRpcError(parseId(message).value, -32600, 'Invalid Request');
139
+ return;
140
+ }
141
+ if (!this.seenInitializeRequest) {
142
+ if (method !== 'initialize') {
143
+ if (isRequest(message)) {
144
+ const { value: id } = parseId(message);
145
+ const responseId = typeof id === 'string' || typeof id === 'number' ? id : null;
146
+ await this.sendJsonRpcError(responseId, -32000, 'Bad Request: Server not initialized');
147
+ }
148
+ // For notifications before initialize, we cannot respond; ignore.
149
+ return;
150
+ }
151
+ // `initialize` must be first; mark after we accept it.
152
+ this.seenInitializeRequest = true;
153
+ }
154
+ // Forward valid messages to the SDK server.
155
+ this.onmessage?.(message);
156
+ }
157
+ }
158
+ //# sourceMappingURL=strict-stdio-transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strict-stdio-transport.js","sourceRoot":"","sources":["../../src/lib/strict-stdio-transport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { ResourceStore } from './lib/resource-store.js';
3
+ export declare function registerInstructionResource(server: McpServer, instructions: string): void;
4
+ export declare function registerResultResources(server: McpServer, store: ResourceStore): void;
5
+ //# sourceMappingURL=resources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAM7D,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,SAAS,EACjB,YAAY,EAAE,MAAM,GACnB,IAAI,CAmBN;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,aAAa,GACnB,IAAI,CA6BN"}
@@ -0,0 +1,43 @@
1
+ import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { ErrorCode, McpError } from './lib/errors.js';
3
+ const RESULT_TEMPLATE = new ResourceTemplate('fs-context://result/{id}', {
4
+ list: undefined,
5
+ });
6
+ export function registerInstructionResource(server, instructions) {
7
+ server.registerResource('fs-context-instructions', 'internal://instructions', {
8
+ title: 'Server Instructions',
9
+ description: 'Guidance for using the fs-context MCP tools effectively.',
10
+ mimeType: 'text/markdown',
11
+ }, (uri) => ({
12
+ contents: [
13
+ {
14
+ uri: uri.href,
15
+ mimeType: 'text/markdown',
16
+ text: instructions,
17
+ },
18
+ ],
19
+ }));
20
+ }
21
+ export function registerResultResources(server, store) {
22
+ server.registerResource('fs-context-result', RESULT_TEMPLATE, {
23
+ title: 'Cached Tool Result',
24
+ description: 'Ephemeral cached tool output exposed as an MCP resource. Not guaranteed to be listed via resources/list.',
25
+ mimeType: 'text/plain',
26
+ }, (uri, variables) => {
27
+ const { id } = variables;
28
+ if (typeof id !== 'string' || id.length === 0) {
29
+ throw new McpError(ErrorCode.E_INVALID_INPUT, 'Missing resource id');
30
+ }
31
+ const entry = store.getText(uri.toString());
32
+ return {
33
+ contents: [
34
+ {
35
+ uri: entry.uri,
36
+ mimeType: entry.mimeType,
37
+ text: entry.text,
38
+ },
39
+ ],
40
+ };
41
+ });
42
+ }
43
+ //# sourceMappingURL=resources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.js","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAG3E,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAGtD,MAAM,eAAe,GAAG,IAAI,gBAAgB,CAAC,0BAA0B,EAAE;IACvE,IAAI,EAAE,SAAS;CAChB,CAAC,CAAC;AAEH,MAAM,UAAU,2BAA2B,CACzC,MAAiB,EACjB,YAAoB;IAEpB,MAAM,CAAC,gBAAgB,CACrB,yBAAyB,EACzB,yBAAyB,EACzB;QACE,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EAAE,0DAA0D;QACvE,QAAQ,EAAE,eAAe;KAC1B,EACD,CAAC,GAAG,EAAsB,EAAE,CAAC,CAAC;QAC5B,QAAQ,EAAE;YACR;gBACE,GAAG,EAAE,GAAG,CAAC,IAAI;gBACb,QAAQ,EAAE,eAAe;gBACzB,IAAI,EAAE,YAAY;aACnB;SACF;KACF,CAAC,CACH,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,MAAiB,EACjB,KAAoB;IAEpB,MAAM,CAAC,gBAAgB,CACrB,mBAAmB,EACnB,eAAe,EACf;QACE,KAAK,EAAE,oBAAoB;QAC3B,WAAW,EACT,0GAA0G;QAC5G,QAAQ,EAAE,YAAY;KACvB,EACD,CAAC,GAAG,EAAE,SAAS,EAAsB,EAAE;QACrC,MAAM,EAAE,EAAE,EAAE,GAAG,SAAS,CAAC;QACzB,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9C,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,eAAe,EAAE,qBAAqB,CAAC,CAAC;QACvE,CAAC;QAED,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;QAE5C,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,GAAG,EAAE,KAAK,CAAC,GAAG;oBACd,QAAQ,EAAE,KAAK,CAAC,QAAQ;oBACxB,IAAI,EAAE,KAAK,CAAC,IAAI;iBACjB;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
package/dist/schemas.d.ts CHANGED
@@ -1,4 +1,16 @@
1
1
  import { z } from 'zod';
2
+ declare const TreeEntryTypeSchema: z.ZodEnum<{
3
+ file: "file";
4
+ directory: "directory";
5
+ symlink: "symlink";
6
+ other: "other";
7
+ }>;
8
+ interface TreeEntry {
9
+ name: string;
10
+ type: z.infer<typeof TreeEntryTypeSchema>;
11
+ relativePath: string;
12
+ children?: TreeEntry[] | undefined;
13
+ }
2
14
  export declare const ListDirectoryInputSchema: z.ZodObject<{
3
15
  path: z.ZodOptional<z.ZodString>;
4
16
  includeHidden: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
@@ -10,6 +22,13 @@ export declare const SearchFilesInputSchema: z.ZodObject<{
10
22
  maxResults: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
11
23
  includeIgnored: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
12
24
  }, z.core.$strict>;
25
+ export declare const TreeInputSchema: z.ZodObject<{
26
+ path: z.ZodOptional<z.ZodString>;
27
+ maxDepth: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
28
+ maxEntries: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
29
+ includeHidden: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
30
+ includeIgnored: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
31
+ }, z.core.$strict>;
13
32
  export declare const SearchContentInputSchema: z.ZodObject<{
14
33
  path: z.ZodOptional<z.ZodString>;
15
34
  pattern: z.ZodString;
@@ -18,10 +37,14 @@ export declare const SearchContentInputSchema: z.ZodObject<{
18
37
  export declare const ReadFileInputSchema: z.ZodObject<{
19
38
  path: z.ZodString;
20
39
  head: z.ZodOptional<z.ZodInt>;
40
+ startLine: z.ZodOptional<z.ZodNumber>;
41
+ endLine: z.ZodOptional<z.ZodNumber>;
21
42
  }, z.core.$strict>;
22
43
  export declare const ReadMultipleFilesInputSchema: z.ZodObject<{
23
44
  paths: z.ZodArray<z.ZodString>;
24
45
  head: z.ZodOptional<z.ZodInt>;
46
+ startLine: z.ZodOptional<z.ZodNumber>;
47
+ endLine: z.ZodOptional<z.ZodNumber>;
25
48
  }, z.core.$strict>;
26
49
  export declare const GetFileInfoInputSchema: z.ZodObject<{
27
50
  path: z.ZodString;
@@ -63,32 +86,49 @@ export declare const ListDirectoryOutputSchema: z.ZodObject<{
63
86
  }, z.core.$strip>>;
64
87
  }, z.core.$strip>;
65
88
  export declare const SearchFilesOutputSchema: z.ZodObject<{
89
+ totalMatches: z.ZodOptional<z.ZodNumber>;
90
+ truncated: z.ZodOptional<z.ZodBoolean>;
91
+ resourceUri: z.ZodOptional<z.ZodString>;
92
+ error: z.ZodOptional<z.ZodObject<{
93
+ code: z.ZodString;
94
+ message: z.ZodString;
95
+ path: z.ZodOptional<z.ZodString>;
96
+ suggestion: z.ZodOptional<z.ZodString>;
97
+ }, z.core.$strip>>;
66
98
  ok: z.ZodBoolean;
67
99
  results: z.ZodOptional<z.ZodArray<z.ZodObject<{
68
100
  path: z.ZodString;
69
101
  size: z.ZodOptional<z.ZodNumber>;
70
102
  modified: z.ZodOptional<z.ZodString>;
71
103
  }, z.core.$strip>>>;
104
+ }, z.core.$strip>;
105
+ export declare const SearchContentOutputSchema: z.ZodObject<{
72
106
  totalMatches: z.ZodOptional<z.ZodNumber>;
73
107
  truncated: z.ZodOptional<z.ZodBoolean>;
108
+ resourceUri: z.ZodOptional<z.ZodString>;
74
109
  error: z.ZodOptional<z.ZodObject<{
75
110
  code: z.ZodString;
76
111
  message: z.ZodString;
77
112
  path: z.ZodOptional<z.ZodString>;
78
113
  suggestion: z.ZodOptional<z.ZodString>;
79
114
  }, z.core.$strip>>;
80
- }, z.core.$strip>;
81
- export declare const SearchContentOutputSchema: z.ZodObject<{
82
115
  ok: z.ZodBoolean;
83
116
  matches: z.ZodOptional<z.ZodArray<z.ZodObject<{
84
117
  file: z.ZodString;
85
118
  line: z.ZodNumber;
86
119
  content: z.ZodString;
120
+ matchCount: z.ZodNumber;
87
121
  contextBefore: z.ZodOptional<z.ZodArray<z.ZodString>>;
88
122
  contextAfter: z.ZodOptional<z.ZodArray<z.ZodString>>;
89
123
  }, z.core.$strip>>>;
90
- totalMatches: z.ZodOptional<z.ZodNumber>;
124
+ }, z.core.$strip>;
125
+ export declare const TreeOutputSchema: z.ZodObject<{
126
+ ok: z.ZodBoolean;
127
+ root: z.ZodOptional<z.ZodString>;
128
+ tree: z.ZodOptional<z.ZodType<TreeEntry, unknown, z.core.$ZodTypeInternals<TreeEntry, unknown>>>;
129
+ ascii: z.ZodOptional<z.ZodString>;
91
130
  truncated: z.ZodOptional<z.ZodBoolean>;
131
+ totalEntries: z.ZodOptional<z.ZodNumber>;
92
132
  error: z.ZodOptional<z.ZodObject<{
93
133
  code: z.ZodString;
94
134
  message: z.ZodString;
@@ -97,11 +137,22 @@ export declare const SearchContentOutputSchema: z.ZodObject<{
97
137
  }, z.core.$strip>>;
98
138
  }, z.core.$strip>;
99
139
  export declare const ReadFileOutputSchema: z.ZodObject<{
100
- ok: z.ZodBoolean;
101
- path: z.ZodOptional<z.ZodString>;
102
140
  content: z.ZodOptional<z.ZodString>;
103
141
  truncated: z.ZodOptional<z.ZodBoolean>;
142
+ resourceUri: z.ZodOptional<z.ZodString>;
104
143
  totalLines: z.ZodOptional<z.ZodNumber>;
144
+ readMode: z.ZodOptional<z.ZodEnum<{
145
+ head: "head";
146
+ full: "full";
147
+ range: "range";
148
+ }>>;
149
+ head: z.ZodOptional<z.ZodNumber>;
150
+ startLine: z.ZodOptional<z.ZodNumber>;
151
+ endLine: z.ZodOptional<z.ZodNumber>;
152
+ linesRead: z.ZodOptional<z.ZodNumber>;
153
+ hasMoreLines: z.ZodOptional<z.ZodBoolean>;
154
+ ok: z.ZodBoolean;
155
+ path: z.ZodOptional<z.ZodString>;
105
156
  error: z.ZodOptional<z.ZodObject<{
106
157
  code: z.ZodString;
107
158
  message: z.ZodString;
@@ -112,9 +163,21 @@ export declare const ReadFileOutputSchema: z.ZodObject<{
112
163
  export declare const ReadMultipleFilesOutputSchema: z.ZodObject<{
113
164
  ok: z.ZodBoolean;
114
165
  results: z.ZodOptional<z.ZodArray<z.ZodObject<{
115
- path: z.ZodString;
116
166
  content: z.ZodOptional<z.ZodString>;
117
167
  truncated: z.ZodOptional<z.ZodBoolean>;
168
+ resourceUri: z.ZodOptional<z.ZodString>;
169
+ totalLines: z.ZodOptional<z.ZodNumber>;
170
+ readMode: z.ZodOptional<z.ZodEnum<{
171
+ head: "head";
172
+ full: "full";
173
+ range: "range";
174
+ }>>;
175
+ head: z.ZodOptional<z.ZodNumber>;
176
+ startLine: z.ZodOptional<z.ZodNumber>;
177
+ endLine: z.ZodOptional<z.ZodNumber>;
178
+ linesRead: z.ZodOptional<z.ZodNumber>;
179
+ hasMoreLines: z.ZodOptional<z.ZodBoolean>;
180
+ path: z.ZodString;
118
181
  error: z.ZodOptional<z.ZodString>;
119
182
  }, z.core.$strip>>>;
120
183
  summary: z.ZodOptional<z.ZodObject<{
@@ -141,11 +204,12 @@ export declare const GetFileInfoOutputSchema: z.ZodObject<{
141
204
  other: "other";
142
205
  }>;
143
206
  size: z.ZodNumber;
144
- created: z.ZodOptional<z.ZodString>;
207
+ tokenEstimate: z.ZodOptional<z.ZodNumber>;
208
+ created: z.ZodString;
145
209
  modified: z.ZodString;
146
- accessed: z.ZodOptional<z.ZodString>;
210
+ accessed: z.ZodString;
147
211
  permissions: z.ZodString;
148
- isHidden: z.ZodOptional<z.ZodBoolean>;
212
+ isHidden: z.ZodBoolean;
149
213
  mimeType: z.ZodOptional<z.ZodString>;
150
214
  symlinkTarget: z.ZodOptional<z.ZodString>;
151
215
  }, z.core.$strip>>;
@@ -170,11 +234,12 @@ export declare const GetMultipleFileInfoOutputSchema: z.ZodObject<{
170
234
  other: "other";
171
235
  }>;
172
236
  size: z.ZodNumber;
173
- created: z.ZodOptional<z.ZodString>;
237
+ tokenEstimate: z.ZodOptional<z.ZodNumber>;
238
+ created: z.ZodString;
174
239
  modified: z.ZodString;
175
- accessed: z.ZodOptional<z.ZodString>;
240
+ accessed: z.ZodString;
176
241
  permissions: z.ZodString;
177
- isHidden: z.ZodOptional<z.ZodBoolean>;
242
+ isHidden: z.ZodBoolean;
178
243
  mimeType: z.ZodOptional<z.ZodString>;
179
244
  symlinkTarget: z.ZodOptional<z.ZodString>;
180
245
  }, z.core.$strip>>;
@@ -192,4 +257,5 @@ export declare const GetMultipleFileInfoOutputSchema: z.ZodObject<{
192
257
  suggestion: z.ZodOptional<z.ZodString>;
193
258
  }, z.core.$strip>>;
194
259
  }, z.core.$strip>;
260
+ export {};
195
261
  //# sourceMappingURL=schemas.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAqDxB,eAAO,MAAM,wBAAwB;;;kBAanC,CAAC;AAEH,eAAO,MAAM,iCAAiC,iCAEX,CAAC;AAEpC,eAAO,MAAM,sBAAsB;;;;;kBA+CjC,CAAC;AAEH,eAAO,MAAM,wBAAwB;;;;kBAoBnC,CAAC;AAEH,eAAO,MAAM,mBAAmB;;;kBAW9B,CAAC;AAEH,eAAO,MAAM,4BAA4B;;;kBAUvC,CAAC;AAEH,eAAO,MAAM,sBAAsB;;kBAQjC,CAAC;AAEH,eAAO,MAAM,8BAA8B;;kBASzC,CAAC;AAEH,eAAO,MAAM,kCAAkC;;;;;;;;;iBAI7C,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;iBAgBpC,CAAC;AAEH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;iBAclC,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;iBAgBpC,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;iBAO/B,CAAC;AAEH,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;iBAcxC,CAAC;AAEH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;iBAIlC,CAAC;AAEH,eAAO,MAAM,+BAA+B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAa1C,CAAC"}
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAmBxB,QAAA,MAAM,mBAAmB;;;;;EAAoD,CAAC;AAE9E,UAAU,SAAS;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;IAC1C,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,SAAS,EAAE,GAAG,SAAS,CAAC;CACpC;AAuGD,eAAO,MAAM,wBAAwB;;;kBAanC,CAAC;AAEH,eAAO,MAAM,iCAAiC,iCAEX,CAAC;AAEpC,eAAO,MAAM,sBAAsB;;;;;kBA+CjC,CAAC;AAEH,eAAO,MAAM,eAAe;;;;;;kBAoC1B,CAAC;AAEH,eAAO,MAAM,wBAAwB;;;;kBAoBnC,CAAC;AAEH,eAAO,MAAM,mBAAmB;;;;;kBAiBC,CAAC;AAElC,eAAO,MAAM,4BAA4B;;;;;kBAgBR,CAAC;AAElC,eAAO,MAAM,sBAAsB;;kBAQjC,CAAC;AAEH,eAAO,MAAM,8BAA8B;;kBASzC,CAAC;AAEH,eAAO,MAAM,kCAAkC;;;;;;;;;iBAI7C,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;iBAgBpC,CAAC;AASH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;iBAWlC,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;iBAcpC,CAAC;AAEH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;iBAQ3B,CAAC;AAeH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;iBAI/B,CAAC;AAOH,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAKxC,CAAC;AAEH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAIlC,CAAC;AAEH,eAAO,MAAM,+BAA+B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAa1C,CAAC"}
package/dist/schemas.js CHANGED
@@ -12,6 +12,13 @@ function isSafeGlobPattern(value) {
12
12
  return true;
13
13
  }
14
14
  const FileTypeSchema = z.enum(['file', 'directory', 'symlink', 'other']);
15
+ const TreeEntryTypeSchema = z.enum(['file', 'directory', 'symlink', 'other']);
16
+ const TreeEntrySchema = z.lazy(() => z.object({
17
+ name: z.string(),
18
+ type: TreeEntryTypeSchema,
19
+ relativePath: z.string(),
20
+ children: z.array(TreeEntrySchema).optional(),
21
+ }));
15
22
  const ErrorSchema = z.object({
16
23
  code: z.string().describe('Error code (e.g., E_NOT_FOUND)'),
17
24
  message: z.string().describe('Human-readable error message'),
@@ -24,16 +31,52 @@ const HeadLinesSchema = z
24
31
  .max(100000, 'head cannot exceed 100,000 lines')
25
32
  .optional()
26
33
  .describe('Read only the first N lines');
34
+ const LineNumberSchema = z
35
+ .number()
36
+ .int({ error: 'line numbers must be integers' })
37
+ .min(1, 'line numbers must be at least 1');
38
+ const validateReadRange = (value, ctx) => {
39
+ const hasHead = value.head !== undefined;
40
+ const hasStart = value.startLine !== undefined;
41
+ const hasEnd = value.endLine !== undefined;
42
+ if (hasHead && (hasStart || hasEnd)) {
43
+ ctx.addIssue({
44
+ code: 'custom',
45
+ path: ['head'],
46
+ message: 'head cannot be used together with startLine/endLine',
47
+ });
48
+ }
49
+ if (hasEnd && !hasStart) {
50
+ ctx.addIssue({
51
+ code: 'custom',
52
+ path: ['endLine'],
53
+ message: 'endLine requires startLine',
54
+ });
55
+ }
56
+ if (value.startLine !== undefined &&
57
+ value.endLine !== undefined &&
58
+ value.endLine < value.startLine) {
59
+ ctx.addIssue({
60
+ code: 'custom',
61
+ path: ['endLine'],
62
+ message: 'endLine must be greater than or equal to startLine',
63
+ });
64
+ }
65
+ };
27
66
  const FileInfoSchema = z.object({
28
67
  name: z.string(),
29
68
  path: z.string(),
30
69
  type: FileTypeSchema,
31
70
  size: z.number(),
32
- created: z.string().optional(),
71
+ tokenEstimate: z
72
+ .number()
73
+ .optional()
74
+ .describe('Approximate token count estimate (rule of thumb: ceil(size/4))'),
75
+ created: z.string(),
33
76
  modified: z.string(),
34
- accessed: z.string().optional(),
77
+ accessed: z.string(),
35
78
  permissions: z.string(),
36
- isHidden: z.boolean().optional(),
79
+ isHidden: z.boolean(),
37
80
  mimeType: z.string().optional(),
38
81
  symlinkTarget: z.string().optional(),
39
82
  });
@@ -42,6 +85,11 @@ const OperationSummarySchema = z.object({
42
85
  succeeded: z.number(),
43
86
  failed: z.number(),
44
87
  });
88
+ const ReadRangeInputSchema = z.strictObject({
89
+ head: HeadLinesSchema,
90
+ startLine: LineNumberSchema.optional(),
91
+ endLine: LineNumberSchema.optional(),
92
+ });
45
93
  export const ListDirectoryInputSchema = z.strictObject({
46
94
  path: z
47
95
  .string()
@@ -96,6 +144,39 @@ export const SearchFilesInputSchema = z.strictObject({
96
144
  .describe('Include normally ignored directories (node_modules, dist, .git, etc). ' +
97
145
  'Set to true when debugging in dependencies.'),
98
146
  });
147
+ export const TreeInputSchema = z.strictObject({
148
+ path: z
149
+ .string()
150
+ .optional()
151
+ .describe('Base directory to render as a tree (leave empty for workspace root). Examples: "src", "lib"'),
152
+ maxDepth: z
153
+ .number()
154
+ .int({ error: 'maxDepth must be an integer' })
155
+ .min(0, 'maxDepth must be at least 0')
156
+ .max(50, 'maxDepth cannot exceed 50')
157
+ .optional()
158
+ .default(5)
159
+ .describe('Maximum depth to recurse (0 = just the root)'),
160
+ maxEntries: z
161
+ .number()
162
+ .int({ error: 'maxEntries must be an integer' })
163
+ .min(1, 'maxEntries must be at least 1')
164
+ .max(20000, 'maxEntries cannot exceed 20,000')
165
+ .optional()
166
+ .default(1000)
167
+ .describe('Maximum number of entries to return before truncating'),
168
+ includeHidden: z
169
+ .boolean()
170
+ .optional()
171
+ .default(false)
172
+ .describe('Include hidden files and directories'),
173
+ includeIgnored: z
174
+ .boolean()
175
+ .optional()
176
+ .default(false)
177
+ .describe('Include normally ignored directories (node_modules, dist, .git, etc). ' +
178
+ 'When true, also disables root .gitignore filtering.'),
179
+ });
99
180
  export const SearchContentInputSchema = z.strictObject({
100
181
  path: z
101
182
  .string()
@@ -113,15 +194,17 @@ export const SearchContentInputSchema = z.strictObject({
113
194
  .default(false)
114
195
  .describe('Include hidden files and directories'),
115
196
  });
116
- export const ReadFileInputSchema = z.strictObject({
197
+ export const ReadFileInputSchema = ReadRangeInputSchema.extend({
117
198
  path: z
118
199
  .string()
119
200
  .min(1, 'Path cannot be empty')
120
201
  .describe('Path to the file to read. ' +
121
202
  'Examples: "README.md", "src/index.ts", "package.json"'),
122
203
  head: HeadLinesSchema.describe('Read only the first N lines of the file (useful for previewing large files)'),
123
- });
124
- export const ReadMultipleFilesInputSchema = z.strictObject({
204
+ startLine: LineNumberSchema.optional().describe('1-based line number to start reading from (inclusive). Useful for reading context around a match.'),
205
+ endLine: LineNumberSchema.optional().describe('1-based line number to stop reading at (inclusive). Requires startLine.'),
206
+ }).superRefine(validateReadRange);
207
+ export const ReadMultipleFilesInputSchema = ReadRangeInputSchema.extend({
125
208
  paths: z
126
209
  .array(z.string().min(1, 'Path cannot be empty'))
127
210
  .min(1, 'At least one path is required')
@@ -129,7 +212,9 @@ export const ReadMultipleFilesInputSchema = z.strictObject({
129
212
  .describe('Array of file paths to read. ' +
130
213
  'Examples: ["README.md", "package.json"], ["src/index.ts", "src/server.ts"]'),
131
214
  head: HeadLinesSchema.describe('Read only the first N lines of each file'),
132
- });
215
+ startLine: LineNumberSchema.optional().describe('1-based line number to start reading from (inclusive), applied to each file.'),
216
+ endLine: LineNumberSchema.optional().describe('1-based line number to stop reading at (inclusive), applied to each file. Requires startLine.'),
217
+ }).superRefine(validateReadRange);
133
218
  export const GetFileInfoInputSchema = z.strictObject({
134
219
  path: z
135
220
  .string()
@@ -165,7 +250,13 @@ export const ListDirectoryOutputSchema = z.object({
165
250
  totalEntries: z.number().optional(),
166
251
  error: ErrorSchema.optional(),
167
252
  });
168
- export const SearchFilesOutputSchema = z.object({
253
+ const SearchSummarySchema = z.object({
254
+ totalMatches: z.number().optional(),
255
+ truncated: z.boolean().optional(),
256
+ resourceUri: z.string().optional(),
257
+ error: ErrorSchema.optional(),
258
+ });
259
+ export const SearchFilesOutputSchema = SearchSummarySchema.extend({
169
260
  ok: z.boolean(),
170
261
  results: z
171
262
  .array(z.object({
@@ -174,43 +265,53 @@ export const SearchFilesOutputSchema = z.object({
174
265
  modified: z.string().optional(),
175
266
  }))
176
267
  .optional(),
177
- totalMatches: z.number().optional(),
178
- truncated: z.boolean().optional(),
179
- error: ErrorSchema.optional(),
180
268
  });
181
- export const SearchContentOutputSchema = z.object({
269
+ export const SearchContentOutputSchema = SearchSummarySchema.extend({
182
270
  ok: z.boolean(),
183
271
  matches: z
184
272
  .array(z.object({
185
273
  file: z.string().describe('Relative path from search base'),
186
274
  line: z.number(),
187
275
  content: z.string(),
276
+ matchCount: z.number(),
188
277
  contextBefore: z.array(z.string()).optional(),
189
278
  contextAfter: z.array(z.string()).optional(),
190
279
  }))
191
280
  .optional(),
192
- totalMatches: z.number().optional(),
281
+ });
282
+ export const TreeOutputSchema = z.object({
283
+ ok: z.boolean(),
284
+ root: z.string().optional(),
285
+ tree: TreeEntrySchema.optional(),
286
+ ascii: z.string().optional(),
193
287
  truncated: z.boolean().optional(),
288
+ totalEntries: z.number().optional(),
194
289
  error: ErrorSchema.optional(),
195
290
  });
196
- export const ReadFileOutputSchema = z.object({
197
- ok: z.boolean(),
198
- path: z.string().optional(),
291
+ const ReadResultSchema = z.object({
199
292
  content: z.string().optional(),
200
293
  truncated: z.boolean().optional(),
294
+ resourceUri: z.string().optional(),
201
295
  totalLines: z.number().optional(),
296
+ readMode: z.enum(['full', 'head', 'range']).optional(),
297
+ head: z.number().optional(),
298
+ startLine: z.number().optional(),
299
+ endLine: z.number().optional(),
300
+ linesRead: z.number().optional(),
301
+ hasMoreLines: z.boolean().optional(),
302
+ });
303
+ export const ReadFileOutputSchema = ReadResultSchema.extend({
304
+ ok: z.boolean(),
305
+ path: z.string().optional(),
202
306
  error: ErrorSchema.optional(),
203
307
  });
308
+ const ReadMultipleFileResultSchema = ReadResultSchema.extend({
309
+ path: z.string(),
310
+ error: z.string().optional(),
311
+ });
204
312
  export const ReadMultipleFilesOutputSchema = z.object({
205
313
  ok: z.boolean(),
206
- results: z
207
- .array(z.object({
208
- path: z.string(),
209
- content: z.string().optional(),
210
- truncated: z.boolean().optional(),
211
- error: z.string().optional(),
212
- }))
213
- .optional(),
314
+ results: z.array(ReadMultipleFileResultSchema).optional(),
214
315
  summary: OperationSummarySchema.optional(),
215
316
  error: ErrorSchema.optional(),
216
317
  });