@mcpc-tech/core 0.3.8 → 0.3.10
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/index.cjs +4174 -0
- package/index.mjs +120 -83
- package/package.json +12 -7
- package/plugins/large-result.cjs +382 -0
- package/plugins/large-result.mjs +6 -2
- package/plugins/search.cjs +291 -0
- package/plugins/search.mjs +4 -2
- package/plugins.cjs +382 -0
- package/plugins.mjs +6 -2
- package/types/src/plugins/large-result.d.ts.map +1 -1
- package/types/src/plugins/search-tool.d.ts +1 -0
- package/types/src/plugins/search-tool.d.ts.map +1 -1
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// __mcpc__core_latest/node_modules/@mcpc/core/src/plugins/large-result.ts
|
|
31
|
+
var large_result_exports = {};
|
|
32
|
+
__export(large_result_exports, {
|
|
33
|
+
createLargeResultPlugin: () => createLargeResultPlugin,
|
|
34
|
+
createPlugin: () => createPlugin,
|
|
35
|
+
default: () => large_result_default
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(large_result_exports);
|
|
38
|
+
var import_promises = require("node:fs/promises");
|
|
39
|
+
var import_node_path3 = require("node:path");
|
|
40
|
+
var import_node_os2 = require("node:os");
|
|
41
|
+
|
|
42
|
+
// __mcpc__core_latest/node_modules/@mcpc/core/src/plugins/search-tool.js
|
|
43
|
+
var import_ripgrep_napi = __toESM(require("@mcpc-tech/ripgrep-napi"), 1);
|
|
44
|
+
var import_node_os = require("node:os");
|
|
45
|
+
|
|
46
|
+
// __mcpc__core_latest/node_modules/@mcpc/core/src/utils/schema.js
|
|
47
|
+
var schemaSymbol = Symbol.for("mcpc.schema");
|
|
48
|
+
var vercelSchemaSymbol = Symbol.for("vercel.ai.schema");
|
|
49
|
+
var validatorSymbol = Symbol.for("mcpc.validator");
|
|
50
|
+
function jsonSchema(schema, options = {}) {
|
|
51
|
+
if (isWrappedSchema(schema)) {
|
|
52
|
+
return schema;
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
[schemaSymbol]: true,
|
|
56
|
+
[validatorSymbol]: true,
|
|
57
|
+
_type: void 0,
|
|
58
|
+
jsonSchema: schema,
|
|
59
|
+
validate: options.validate
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function isWrappedSchema(value) {
|
|
63
|
+
return typeof value === "object" && value !== null && (schemaSymbol in value && value[schemaSymbol] === true || vercelSchemaSymbol in value && value[vercelSchemaSymbol] === true);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// __mcpc__core_latest/node_modules/@mcpc/core/src/plugins/search-tool.js
|
|
67
|
+
var import_node_path = require("node:path");
|
|
68
|
+
var import_node_path2 = require("node:path");
|
|
69
|
+
function createSearchPlugin(options = {}) {
|
|
70
|
+
const maxResults = options.maxResults || 20;
|
|
71
|
+
const maxOutputSize = options.maxOutputSize || 5e3;
|
|
72
|
+
const allowedSearchDir = options.allowedDir || (0, import_node_os.tmpdir)();
|
|
73
|
+
const timeoutMs = options.timeoutMs || 3e4;
|
|
74
|
+
const global = options.global ?? true;
|
|
75
|
+
const activeTimeouts = /* @__PURE__ */ new Set();
|
|
76
|
+
return {
|
|
77
|
+
name: "plugin-search",
|
|
78
|
+
version: "1.0.0",
|
|
79
|
+
configureServer: (server) => {
|
|
80
|
+
const defaultDescription = `Search for text patterns in files and directories. Use this to find specific content, code, or information within files. Provide a simple literal string or a regular expression. If your pattern is a regex, ensure it's valid; otherwise use quotes or escape special characters to treat it as a literal string.
|
|
81
|
+
Only search within the allowed directory: ${allowedSearchDir}`;
|
|
82
|
+
const toolDescription = options.toolDescription || defaultDescription;
|
|
83
|
+
server.tool("search-tool-result", toolDescription, jsonSchema({
|
|
84
|
+
type: "object",
|
|
85
|
+
properties: {
|
|
86
|
+
pattern: {
|
|
87
|
+
type: "string",
|
|
88
|
+
description: "Text to search for. Can be a plain string or a regular expression. For regexes, don't include delimiters (e.g. use `^foo` not `/^foo/`). If you get a regex parse error, try escaping special chars or using a simpler literal search."
|
|
89
|
+
},
|
|
90
|
+
path: {
|
|
91
|
+
type: "string",
|
|
92
|
+
description: "File or folder path to limit the search (optional). Must be within the allowed directory."
|
|
93
|
+
},
|
|
94
|
+
maxResults: {
|
|
95
|
+
type: "number",
|
|
96
|
+
description: "Maximum number of matches to return (optional). Lower this to reduce output size and runtime."
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
required: [
|
|
100
|
+
"pattern"
|
|
101
|
+
]
|
|
102
|
+
}), async (args) => {
|
|
103
|
+
const isBroad = (raw) => {
|
|
104
|
+
const t = (raw ?? "").trim();
|
|
105
|
+
if (!t) return true;
|
|
106
|
+
if (/^[*.\s]{2,}$/.test(t)) return true;
|
|
107
|
+
if (t === ".*" || t === "." || t === "^.*$") return true;
|
|
108
|
+
if (/^\^?\.\*\$?$/.test(t)) return true;
|
|
109
|
+
if (/^\\s?\*+$/.test(t)) return true;
|
|
110
|
+
return false;
|
|
111
|
+
};
|
|
112
|
+
const appendMatchSafely = (current, addition, limit) => {
|
|
113
|
+
if ((current + addition).length > limit) {
|
|
114
|
+
return {
|
|
115
|
+
current,
|
|
116
|
+
added: false
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
current: current + addition,
|
|
121
|
+
added: true
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
let timeoutId;
|
|
125
|
+
try {
|
|
126
|
+
const requestedPath = args.path || allowedSearchDir;
|
|
127
|
+
const limit = args.maxResults || maxResults;
|
|
128
|
+
if (args.path) {
|
|
129
|
+
const resolvedRequested = (0, import_node_path.resolve)(args.path);
|
|
130
|
+
const resolvedAllowed = (0, import_node_path.resolve)(allowedSearchDir);
|
|
131
|
+
const relativePath = (0, import_node_path2.relative)(resolvedAllowed, resolvedRequested);
|
|
132
|
+
if (relativePath && relativePath.startsWith("..")) {
|
|
133
|
+
return {
|
|
134
|
+
content: [
|
|
135
|
+
{
|
|
136
|
+
type: "text",
|
|
137
|
+
text: `\u274C Path "${args.path}" not allowed. Must be within: ${allowedSearchDir}`
|
|
138
|
+
}
|
|
139
|
+
],
|
|
140
|
+
isError: true
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const searchPath = requestedPath;
|
|
145
|
+
const rawPattern = args.pattern ?? "";
|
|
146
|
+
if (isBroad(rawPattern)) {
|
|
147
|
+
return {
|
|
148
|
+
content: [
|
|
149
|
+
{
|
|
150
|
+
type: "text",
|
|
151
|
+
text: `\u274C Search pattern too broad: "${rawPattern}"
|
|
152
|
+
Provide a more specific pattern (e.g. include a filename fragment, a keyword, or limit with the "path" parameter). Avoid patterns that only contain wildcards like "*" or ".*".`
|
|
153
|
+
}
|
|
154
|
+
],
|
|
155
|
+
isError: true
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
159
|
+
timeoutId = setTimeout(() => {
|
|
160
|
+
reject(new Error(`Search timeout after ${timeoutMs}ms`));
|
|
161
|
+
}, timeoutMs);
|
|
162
|
+
activeTimeouts.add(timeoutId);
|
|
163
|
+
});
|
|
164
|
+
const searchPromise = new Promise((resolve2, reject) => {
|
|
165
|
+
try {
|
|
166
|
+
const result2 = import_ripgrep_napi.default.search(args.pattern, [
|
|
167
|
+
searchPath
|
|
168
|
+
]);
|
|
169
|
+
resolve2(result2);
|
|
170
|
+
} catch (error) {
|
|
171
|
+
reject(error);
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
const result = await Promise.race([
|
|
175
|
+
searchPromise,
|
|
176
|
+
timeoutPromise
|
|
177
|
+
]);
|
|
178
|
+
if (timeoutId) {
|
|
179
|
+
clearTimeout(timeoutId);
|
|
180
|
+
activeTimeouts.delete(timeoutId);
|
|
181
|
+
}
|
|
182
|
+
if (!result.success || !result.matches?.length) {
|
|
183
|
+
return {
|
|
184
|
+
content: [
|
|
185
|
+
{
|
|
186
|
+
type: "text",
|
|
187
|
+
text: `No matches found for: "${args.pattern}"
|
|
188
|
+
|
|
189
|
+
Try:
|
|
190
|
+
- **Simpler pattern** or \`*\`
|
|
191
|
+
- Check if files exist in: ${searchPath}
|
|
192
|
+
- Use specific file path`
|
|
193
|
+
}
|
|
194
|
+
]
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
const matches = result.matches.slice(0, limit);
|
|
198
|
+
let output = `Found ${result.matches.length} matches (showing up to ${matches.length}):
|
|
199
|
+
|
|
200
|
+
`;
|
|
201
|
+
let matchesIncluded = 0;
|
|
202
|
+
for (const match of matches) {
|
|
203
|
+
const baseMatchText = `**${match.path}:${match.lineNumber}**
|
|
204
|
+
`;
|
|
205
|
+
const fullMatchText = `${baseMatchText}\`\`\`
|
|
206
|
+
${match.line}
|
|
207
|
+
\`\`\`
|
|
208
|
+
|
|
209
|
+
`;
|
|
210
|
+
const res = appendMatchSafely(output, fullMatchText, maxOutputSize);
|
|
211
|
+
if (!res.added) {
|
|
212
|
+
if (matchesIncluded === 0) {
|
|
213
|
+
const remainingSpace = maxOutputSize - output.length - 100;
|
|
214
|
+
if (remainingSpace > 50) {
|
|
215
|
+
const truncatedLine = match.line.slice(0, remainingSpace);
|
|
216
|
+
output += `${baseMatchText}\`\`\`
|
|
217
|
+
${truncatedLine}...
|
|
218
|
+
\`\`\`
|
|
219
|
+
|
|
220
|
+
`;
|
|
221
|
+
output += `\u26A0\uFE0F Content truncated
|
|
222
|
+
`;
|
|
223
|
+
matchesIncluded++;
|
|
224
|
+
} else {
|
|
225
|
+
output += `\u26A0\uFE0F Content too large, use specific file path
|
|
226
|
+
`;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
output = res.current;
|
|
232
|
+
matchesIncluded++;
|
|
233
|
+
}
|
|
234
|
+
if (matchesIncluded < matches.length) {
|
|
235
|
+
output += `
|
|
236
|
+
\u26A0\uFE0F Showing ${matchesIncluded}/${matches.length} matches (size limit)
|
|
237
|
+
`;
|
|
238
|
+
output += `
|
|
239
|
+
For more results:
|
|
240
|
+
`;
|
|
241
|
+
output += `- Use specific pattern: "${args.pattern} keyword"
|
|
242
|
+
`;
|
|
243
|
+
output += `- Search specific file: {"pattern": "${args.pattern}", "path": "/file.txt"}
|
|
244
|
+
`;
|
|
245
|
+
output += `- Use fewer results: {"maxResults": 5}`;
|
|
246
|
+
}
|
|
247
|
+
return {
|
|
248
|
+
content: [
|
|
249
|
+
{
|
|
250
|
+
type: "text",
|
|
251
|
+
text: output
|
|
252
|
+
}
|
|
253
|
+
]
|
|
254
|
+
};
|
|
255
|
+
} catch (error) {
|
|
256
|
+
if (timeoutId) {
|
|
257
|
+
clearTimeout(timeoutId);
|
|
258
|
+
activeTimeouts.delete(timeoutId);
|
|
259
|
+
}
|
|
260
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
261
|
+
const isTimeout = errorMsg.includes("timeout");
|
|
262
|
+
return {
|
|
263
|
+
content: [
|
|
264
|
+
{
|
|
265
|
+
type: "text",
|
|
266
|
+
text: `Search error: ${errorMsg}
|
|
267
|
+
|
|
268
|
+
${isTimeout ? `Timeout after ${timeoutMs}ms. Try simpler pattern or smaller directory.` : `Check pattern syntax or directory exists.`}`
|
|
269
|
+
}
|
|
270
|
+
]
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
}, {
|
|
274
|
+
internal: !global
|
|
275
|
+
});
|
|
276
|
+
},
|
|
277
|
+
dispose: () => {
|
|
278
|
+
for (const timeoutId of activeTimeouts) {
|
|
279
|
+
clearTimeout(timeoutId);
|
|
280
|
+
}
|
|
281
|
+
activeTimeouts.clear();
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
var defaultSearchPlugin = createSearchPlugin({
|
|
286
|
+
global: true,
|
|
287
|
+
maxResults: 20,
|
|
288
|
+
maxOutputSize: 5e3,
|
|
289
|
+
caseSensitive: false,
|
|
290
|
+
timeoutMs: 3e4
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
// __mcpc__core_latest/node_modules/@mcpc/core/src/plugins/large-result.ts
|
|
294
|
+
function createLargeResultPlugin(options = {}) {
|
|
295
|
+
const maxSize = options.maxSize || 8e3;
|
|
296
|
+
const previewSize = options.previewSize || 4e3;
|
|
297
|
+
let tempDir = options.tempDir || null;
|
|
298
|
+
const configuredServers = /* @__PURE__ */ new Map();
|
|
299
|
+
const defaultSearchDescription = `Search within large tool result files that were saved due to size limits. Use when: a tool result was saved to file because it exceeded the context limit. Do NOT use this tool before calling the actual tool first. Provide specific keywords or patterns related to the content you're looking for.`;
|
|
300
|
+
const searchConfig = {
|
|
301
|
+
maxResults: options.search?.maxResults || 15,
|
|
302
|
+
maxOutputSize: options.search?.maxOutputSize || 4e3,
|
|
303
|
+
toolDescription: options.search?.toolDescription || defaultSearchDescription,
|
|
304
|
+
global: true
|
|
305
|
+
};
|
|
306
|
+
return {
|
|
307
|
+
name: "plugin-large-result-handler",
|
|
308
|
+
version: "1.0.0",
|
|
309
|
+
dependencies: [],
|
|
310
|
+
// Search plugin will be added dynamically
|
|
311
|
+
configureServer: async (server) => {
|
|
312
|
+
if (!configuredServers.has(server)) {
|
|
313
|
+
const searchPlugin = createSearchPlugin(searchConfig);
|
|
314
|
+
await server.addPlugin(searchPlugin);
|
|
315
|
+
configuredServers.set(server, true);
|
|
316
|
+
}
|
|
317
|
+
},
|
|
318
|
+
transformTool: (tool, context) => {
|
|
319
|
+
const originalExecute = tool.execute;
|
|
320
|
+
tool.execute = async (args) => {
|
|
321
|
+
try {
|
|
322
|
+
const result = await originalExecute(args);
|
|
323
|
+
const resultText = JSON.stringify(result);
|
|
324
|
+
if (resultText.length <= maxSize) {
|
|
325
|
+
return result;
|
|
326
|
+
}
|
|
327
|
+
if (!tempDir) {
|
|
328
|
+
tempDir = await (0, import_promises.mkdtemp)((0, import_node_path3.join)((0, import_node_os2.tmpdir)(), "mcpc-results-"));
|
|
329
|
+
}
|
|
330
|
+
const safeToolName = encodeURIComponent(context.toolName ?? "tool");
|
|
331
|
+
const fileName = `${safeToolName}-${Date.now()}.txt`;
|
|
332
|
+
const filePath = (0, import_node_path3.join)(tempDir, fileName);
|
|
333
|
+
await (0, import_promises.writeFile)(filePath, resultText);
|
|
334
|
+
const preview = resultText.slice(0, previewSize);
|
|
335
|
+
const sizeKB = (resultText.length / 1024).toFixed(1);
|
|
336
|
+
return {
|
|
337
|
+
content: [
|
|
338
|
+
{
|
|
339
|
+
type: "text",
|
|
340
|
+
text: `**Result too large (${resultText.length} chars), saved to file**
|
|
341
|
+
|
|
342
|
+
\u{1F4C1} **File:** ${filePath}
|
|
343
|
+
\u{1F4CA} **Size:** ${sizeKB} KB
|
|
344
|
+
|
|
345
|
+
**Preview (${previewSize} chars):**
|
|
346
|
+
\`\`\`
|
|
347
|
+
${preview}
|
|
348
|
+
\`\`\`
|
|
349
|
+
|
|
350
|
+
**To read/understand the full content:**
|
|
351
|
+
- Use the \`search-tool-result\` tool with pattern: \`search-tool-result {"pattern": "your-search-term"}\`
|
|
352
|
+
- Search supports regex patterns for advanced queries`
|
|
353
|
+
}
|
|
354
|
+
]
|
|
355
|
+
};
|
|
356
|
+
} catch (error) {
|
|
357
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
358
|
+
console.error(
|
|
359
|
+
`Large result plugin error for ${context.toolName}: ${errorMsg}`
|
|
360
|
+
);
|
|
361
|
+
throw error;
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
return tool;
|
|
365
|
+
},
|
|
366
|
+
dispose: () => {
|
|
367
|
+
configuredServers.clear();
|
|
368
|
+
tempDir = null;
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
var defaultLargeResultPlugin = createLargeResultPlugin({
|
|
373
|
+
maxSize: 8e3,
|
|
374
|
+
previewSize: 4e3
|
|
375
|
+
});
|
|
376
|
+
var createPlugin = createLargeResultPlugin;
|
|
377
|
+
var large_result_default = defaultLargeResultPlugin;
|
|
378
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
379
|
+
0 && (module.exports = {
|
|
380
|
+
createLargeResultPlugin,
|
|
381
|
+
createPlugin
|
|
382
|
+
});
|
package/plugins/large-result.mjs
CHANGED
|
@@ -45,8 +45,10 @@ function createSearchPlugin(options = {}) {
|
|
|
45
45
|
name: "plugin-search",
|
|
46
46
|
version: "1.0.0",
|
|
47
47
|
configureServer: (server) => {
|
|
48
|
-
|
|
49
|
-
Only search within the allowed directory: ${allowedSearchDir}
|
|
48
|
+
const defaultDescription = `Search for text patterns in files and directories. Use this to find specific content, code, or information within files. Provide a simple literal string or a regular expression. If your pattern is a regex, ensure it's valid; otherwise use quotes or escape special characters to treat it as a literal string.
|
|
49
|
+
Only search within the allowed directory: ${allowedSearchDir}`;
|
|
50
|
+
const toolDescription = options.toolDescription || defaultDescription;
|
|
51
|
+
server.tool("search-tool-result", toolDescription, jsonSchema({
|
|
50
52
|
type: "object",
|
|
51
53
|
properties: {
|
|
52
54
|
pattern: {
|
|
@@ -262,9 +264,11 @@ function createLargeResultPlugin(options = {}) {
|
|
|
262
264
|
const previewSize = options.previewSize || 4e3;
|
|
263
265
|
let tempDir = options.tempDir || null;
|
|
264
266
|
const configuredServers = /* @__PURE__ */ new Map();
|
|
267
|
+
const defaultSearchDescription = `Search within large tool result files that were saved due to size limits. Use when: a tool result was saved to file because it exceeded the context limit. Do NOT use this tool before calling the actual tool first. Provide specific keywords or patterns related to the content you're looking for.`;
|
|
265
268
|
const searchConfig = {
|
|
266
269
|
maxResults: options.search?.maxResults || 15,
|
|
267
270
|
maxOutputSize: options.search?.maxOutputSize || 4e3,
|
|
271
|
+
toolDescription: options.search?.toolDescription || defaultSearchDescription,
|
|
268
272
|
global: true
|
|
269
273
|
};
|
|
270
274
|
return {
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// __mcpc__core_latest/node_modules/@mcpc/core/src/plugins/search-tool.ts
|
|
31
|
+
var search_tool_exports = {};
|
|
32
|
+
__export(search_tool_exports, {
|
|
33
|
+
createPlugin: () => createPlugin,
|
|
34
|
+
createSearchPlugin: () => createSearchPlugin,
|
|
35
|
+
default: () => search_tool_default
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(search_tool_exports);
|
|
38
|
+
var import_ripgrep_napi = __toESM(require("@mcpc-tech/ripgrep-napi"), 1);
|
|
39
|
+
var import_node_os = require("node:os");
|
|
40
|
+
|
|
41
|
+
// __mcpc__core_latest/node_modules/@mcpc/core/src/utils/schema.js
|
|
42
|
+
var schemaSymbol = Symbol.for("mcpc.schema");
|
|
43
|
+
var vercelSchemaSymbol = Symbol.for("vercel.ai.schema");
|
|
44
|
+
var validatorSymbol = Symbol.for("mcpc.validator");
|
|
45
|
+
function jsonSchema(schema, options = {}) {
|
|
46
|
+
if (isWrappedSchema(schema)) {
|
|
47
|
+
return schema;
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
[schemaSymbol]: true,
|
|
51
|
+
[validatorSymbol]: true,
|
|
52
|
+
_type: void 0,
|
|
53
|
+
jsonSchema: schema,
|
|
54
|
+
validate: options.validate
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function isWrappedSchema(value) {
|
|
58
|
+
return typeof value === "object" && value !== null && (schemaSymbol in value && value[schemaSymbol] === true || vercelSchemaSymbol in value && value[vercelSchemaSymbol] === true);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// __mcpc__core_latest/node_modules/@mcpc/core/src/plugins/search-tool.ts
|
|
62
|
+
var import_node_path = require("node:path");
|
|
63
|
+
var import_node_path2 = require("node:path");
|
|
64
|
+
function createSearchPlugin(options = {}) {
|
|
65
|
+
const maxResults = options.maxResults || 20;
|
|
66
|
+
const maxOutputSize = options.maxOutputSize || 5e3;
|
|
67
|
+
const allowedSearchDir = options.allowedDir || (0, import_node_os.tmpdir)();
|
|
68
|
+
const timeoutMs = options.timeoutMs || 3e4;
|
|
69
|
+
const global = options.global ?? true;
|
|
70
|
+
const activeTimeouts = /* @__PURE__ */ new Set();
|
|
71
|
+
return {
|
|
72
|
+
name: "plugin-search",
|
|
73
|
+
version: "1.0.0",
|
|
74
|
+
configureServer: (server) => {
|
|
75
|
+
const defaultDescription = `Search for text patterns in files and directories. Use this to find specific content, code, or information within files. Provide a simple literal string or a regular expression. If your pattern is a regex, ensure it's valid; otherwise use quotes or escape special characters to treat it as a literal string.
|
|
76
|
+
Only search within the allowed directory: ${allowedSearchDir}`;
|
|
77
|
+
const toolDescription = options.toolDescription || defaultDescription;
|
|
78
|
+
server.tool(
|
|
79
|
+
"search-tool-result",
|
|
80
|
+
toolDescription,
|
|
81
|
+
jsonSchema({
|
|
82
|
+
type: "object",
|
|
83
|
+
properties: {
|
|
84
|
+
pattern: {
|
|
85
|
+
type: "string",
|
|
86
|
+
description: "Text to search for. Can be a plain string or a regular expression. For regexes, don't include delimiters (e.g. use `^foo` not `/^foo/`). If you get a regex parse error, try escaping special chars or using a simpler literal search."
|
|
87
|
+
},
|
|
88
|
+
path: {
|
|
89
|
+
type: "string",
|
|
90
|
+
description: "File or folder path to limit the search (optional). Must be within the allowed directory."
|
|
91
|
+
},
|
|
92
|
+
maxResults: {
|
|
93
|
+
type: "number",
|
|
94
|
+
description: "Maximum number of matches to return (optional). Lower this to reduce output size and runtime."
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
required: ["pattern"]
|
|
98
|
+
}),
|
|
99
|
+
async (args) => {
|
|
100
|
+
const isBroad = (raw) => {
|
|
101
|
+
const t = (raw ?? "").trim();
|
|
102
|
+
if (!t) return true;
|
|
103
|
+
if (/^[*.\s]{2,}$/.test(t)) return true;
|
|
104
|
+
if (t === ".*" || t === "." || t === "^.*$") return true;
|
|
105
|
+
if (/^\^?\.\*\$?$/.test(t)) return true;
|
|
106
|
+
if (/^\\s?\*+$/.test(t)) return true;
|
|
107
|
+
return false;
|
|
108
|
+
};
|
|
109
|
+
const appendMatchSafely = (current, addition, limit) => {
|
|
110
|
+
if ((current + addition).length > limit) {
|
|
111
|
+
return { current, added: false };
|
|
112
|
+
}
|
|
113
|
+
return { current: current + addition, added: true };
|
|
114
|
+
};
|
|
115
|
+
let timeoutId;
|
|
116
|
+
try {
|
|
117
|
+
const requestedPath = args.path || allowedSearchDir;
|
|
118
|
+
const limit = args.maxResults || maxResults;
|
|
119
|
+
if (args.path) {
|
|
120
|
+
const resolvedRequested = (0, import_node_path.resolve)(args.path);
|
|
121
|
+
const resolvedAllowed = (0, import_node_path.resolve)(allowedSearchDir);
|
|
122
|
+
const relativePath = (0, import_node_path2.relative)(resolvedAllowed, resolvedRequested);
|
|
123
|
+
if (relativePath && relativePath.startsWith("..")) {
|
|
124
|
+
return {
|
|
125
|
+
content: [
|
|
126
|
+
{
|
|
127
|
+
type: "text",
|
|
128
|
+
text: `\u274C Path "${args.path}" not allowed. Must be within: ${allowedSearchDir}`
|
|
129
|
+
}
|
|
130
|
+
],
|
|
131
|
+
isError: true
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const searchPath = requestedPath;
|
|
136
|
+
const rawPattern = args.pattern ?? "";
|
|
137
|
+
if (isBroad(rawPattern)) {
|
|
138
|
+
return {
|
|
139
|
+
content: [
|
|
140
|
+
{
|
|
141
|
+
type: "text",
|
|
142
|
+
text: `\u274C Search pattern too broad: "${rawPattern}"
|
|
143
|
+
Provide a more specific pattern (e.g. include a filename fragment, a keyword, or limit with the "path" parameter). Avoid patterns that only contain wildcards like "*" or ".*".`
|
|
144
|
+
}
|
|
145
|
+
],
|
|
146
|
+
isError: true
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
150
|
+
timeoutId = setTimeout(() => {
|
|
151
|
+
reject(new Error(`Search timeout after ${timeoutMs}ms`));
|
|
152
|
+
}, timeoutMs);
|
|
153
|
+
activeTimeouts.add(timeoutId);
|
|
154
|
+
});
|
|
155
|
+
const searchPromise = new Promise((resolve2, reject) => {
|
|
156
|
+
try {
|
|
157
|
+
const result2 = import_ripgrep_napi.default.search(args.pattern, [searchPath]);
|
|
158
|
+
resolve2(result2);
|
|
159
|
+
} catch (error) {
|
|
160
|
+
reject(error);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
const result = await Promise.race([
|
|
164
|
+
searchPromise,
|
|
165
|
+
timeoutPromise
|
|
166
|
+
]);
|
|
167
|
+
if (timeoutId) {
|
|
168
|
+
clearTimeout(timeoutId);
|
|
169
|
+
activeTimeouts.delete(timeoutId);
|
|
170
|
+
}
|
|
171
|
+
if (!result.success || !result.matches?.length) {
|
|
172
|
+
return {
|
|
173
|
+
content: [
|
|
174
|
+
{
|
|
175
|
+
type: "text",
|
|
176
|
+
text: `No matches found for: "${args.pattern}"
|
|
177
|
+
|
|
178
|
+
Try:
|
|
179
|
+
- **Simpler pattern** or \`*\`
|
|
180
|
+
- Check if files exist in: ${searchPath}
|
|
181
|
+
- Use specific file path`
|
|
182
|
+
}
|
|
183
|
+
]
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
const matches = result.matches.slice(0, limit);
|
|
187
|
+
let output = `Found ${result.matches.length} matches (showing up to ${matches.length}):
|
|
188
|
+
|
|
189
|
+
`;
|
|
190
|
+
let matchesIncluded = 0;
|
|
191
|
+
for (const match of matches) {
|
|
192
|
+
const baseMatchText = `**${match.path}:${match.lineNumber}**
|
|
193
|
+
`;
|
|
194
|
+
const fullMatchText = `${baseMatchText}\`\`\`
|
|
195
|
+
${match.line}
|
|
196
|
+
\`\`\`
|
|
197
|
+
|
|
198
|
+
`;
|
|
199
|
+
const res = appendMatchSafely(
|
|
200
|
+
output,
|
|
201
|
+
fullMatchText,
|
|
202
|
+
maxOutputSize
|
|
203
|
+
);
|
|
204
|
+
if (!res.added) {
|
|
205
|
+
if (matchesIncluded === 0) {
|
|
206
|
+
const remainingSpace = maxOutputSize - output.length - 100;
|
|
207
|
+
if (remainingSpace > 50) {
|
|
208
|
+
const truncatedLine = match.line.slice(0, remainingSpace);
|
|
209
|
+
output += `${baseMatchText}\`\`\`
|
|
210
|
+
${truncatedLine}...
|
|
211
|
+
\`\`\`
|
|
212
|
+
|
|
213
|
+
`;
|
|
214
|
+
output += `\u26A0\uFE0F Content truncated
|
|
215
|
+
`;
|
|
216
|
+
matchesIncluded++;
|
|
217
|
+
} else {
|
|
218
|
+
output += `\u26A0\uFE0F Content too large, use specific file path
|
|
219
|
+
`;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
output = res.current;
|
|
225
|
+
matchesIncluded++;
|
|
226
|
+
}
|
|
227
|
+
if (matchesIncluded < matches.length) {
|
|
228
|
+
output += `
|
|
229
|
+
\u26A0\uFE0F Showing ${matchesIncluded}/${matches.length} matches (size limit)
|
|
230
|
+
`;
|
|
231
|
+
output += `
|
|
232
|
+
For more results:
|
|
233
|
+
`;
|
|
234
|
+
output += `- Use specific pattern: "${args.pattern} keyword"
|
|
235
|
+
`;
|
|
236
|
+
output += `- Search specific file: {"pattern": "${args.pattern}", "path": "/file.txt"}
|
|
237
|
+
`;
|
|
238
|
+
output += `- Use fewer results: {"maxResults": 5}`;
|
|
239
|
+
}
|
|
240
|
+
return {
|
|
241
|
+
content: [
|
|
242
|
+
{
|
|
243
|
+
type: "text",
|
|
244
|
+
text: output
|
|
245
|
+
}
|
|
246
|
+
]
|
|
247
|
+
};
|
|
248
|
+
} catch (error) {
|
|
249
|
+
if (timeoutId) {
|
|
250
|
+
clearTimeout(timeoutId);
|
|
251
|
+
activeTimeouts.delete(timeoutId);
|
|
252
|
+
}
|
|
253
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
254
|
+
const isTimeout = errorMsg.includes("timeout");
|
|
255
|
+
return {
|
|
256
|
+
content: [
|
|
257
|
+
{
|
|
258
|
+
type: "text",
|
|
259
|
+
text: `Search error: ${errorMsg}
|
|
260
|
+
|
|
261
|
+
${isTimeout ? `Timeout after ${timeoutMs}ms. Try simpler pattern or smaller directory.` : `Check pattern syntax or directory exists.`}`
|
|
262
|
+
}
|
|
263
|
+
]
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
{ internal: !global }
|
|
268
|
+
);
|
|
269
|
+
},
|
|
270
|
+
dispose: () => {
|
|
271
|
+
for (const timeoutId of activeTimeouts) {
|
|
272
|
+
clearTimeout(timeoutId);
|
|
273
|
+
}
|
|
274
|
+
activeTimeouts.clear();
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
var defaultSearchPlugin = createSearchPlugin({
|
|
279
|
+
global: true,
|
|
280
|
+
maxResults: 20,
|
|
281
|
+
maxOutputSize: 5e3,
|
|
282
|
+
caseSensitive: false,
|
|
283
|
+
timeoutMs: 3e4
|
|
284
|
+
});
|
|
285
|
+
var createPlugin = createSearchPlugin;
|
|
286
|
+
var search_tool_default = defaultSearchPlugin;
|
|
287
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
288
|
+
0 && (module.exports = {
|
|
289
|
+
createPlugin,
|
|
290
|
+
createSearchPlugin
|
|
291
|
+
});
|