@probelabs/probe 0.6.0-rc121 → 0.6.0-rc123
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/README.md +36 -2
- package/build/agent/ProbeAgent.js +50 -14
- package/build/agent/index.js +18689 -33570
- package/build/agent/mcp/client.js +69 -15
- package/build/agent/mcp/config.js +8 -8
- package/build/agent/mcp/xmlBridge.js +52 -7
- package/build/agent/schemaUtils.js +28 -15
- package/build/grep.js +152 -0
- package/build/index.js +2 -0
- package/build/mcp/index.js +105 -87
- package/build/mcp/index.ts +120 -97
- package/cjs/agent/ProbeAgent.cjs +13913 -2703
- package/cjs/index.cjs +23926 -12658
- package/index.d.ts +45 -0
- package/package.json +2 -2
- package/src/agent/ProbeAgent.js +50 -14
- package/src/agent/index.js +1 -1
- package/src/agent/mcp/client.js +69 -15
- package/src/agent/mcp/config.js +8 -8
- package/src/agent/mcp/xmlBridge.js +52 -7
- package/src/agent/schemaUtils.js +28 -15
- package/src/grep.js +152 -0
- package/src/index.js +2 -0
- package/src/mcp/index.ts +120 -97
package/build/mcp/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import path from 'path';
|
|
|
8
8
|
import fs from 'fs-extra';
|
|
9
9
|
import { fileURLToPath } from 'url';
|
|
10
10
|
// Import from parent package
|
|
11
|
-
import { search, extract } from '../index.js';
|
|
11
|
+
import { search, extract, grep } from '../index.js';
|
|
12
12
|
// Parse command-line arguments
|
|
13
13
|
function parseArgs() {
|
|
14
14
|
const args = process.argv.slice(2);
|
|
@@ -39,7 +39,7 @@ Usage:
|
|
|
39
39
|
|
|
40
40
|
Options:
|
|
41
41
|
--timeout, -t <seconds> Set timeout for search operations (default: 30)
|
|
42
|
-
--format <format> Set output format (
|
|
42
|
+
--format <format> Set output format (default: outline)
|
|
43
43
|
--help, -h Show this help message
|
|
44
44
|
`);
|
|
45
45
|
process.exit(0);
|
|
@@ -106,7 +106,7 @@ class ProbeServer {
|
|
|
106
106
|
});
|
|
107
107
|
this.setupToolHandlers();
|
|
108
108
|
// Error handling
|
|
109
|
-
this.server.onerror = (error) => console.error('[MCP
|
|
109
|
+
this.server.onerror = (error) => console.error('[MCP ERROR]', error);
|
|
110
110
|
process.on('SIGINT', async () => {
|
|
111
111
|
await this.server.close();
|
|
112
112
|
process.exit(0);
|
|
@@ -118,35 +118,22 @@ class ProbeServer {
|
|
|
118
118
|
tools: [
|
|
119
119
|
{
|
|
120
120
|
name: 'search_code',
|
|
121
|
-
description: "
|
|
121
|
+
description: "Semantic code search using AST parsing and ElasticSearch-style queries. Use this for finding code, not grep.",
|
|
122
122
|
inputSchema: {
|
|
123
123
|
type: 'object',
|
|
124
124
|
properties: {
|
|
125
125
|
path: {
|
|
126
126
|
type: 'string',
|
|
127
|
-
description: 'Absolute path to the directory to search
|
|
127
|
+
description: 'Absolute path to the directory to search',
|
|
128
128
|
},
|
|
129
129
|
query: {
|
|
130
130
|
type: 'string',
|
|
131
|
-
description: '
|
|
131
|
+
description: 'Search query. Use quotes for exact matches: "functionName". Supports AND, OR, NOT operators.',
|
|
132
132
|
},
|
|
133
133
|
exact: {
|
|
134
134
|
type: 'boolean',
|
|
135
|
-
description: '
|
|
136
|
-
|
|
137
|
-
allowTests: {
|
|
138
|
-
type: 'boolean',
|
|
139
|
-
description: 'Allow test files and test code blocks in results (enabled by default)',
|
|
140
|
-
default: true
|
|
141
|
-
},
|
|
142
|
-
session: {
|
|
143
|
-
type: 'string',
|
|
144
|
-
description: 'Session identifier for caching. Set to "new" if unknown, or want to reset cache. Re-use session ID returned from previous searches',
|
|
145
|
-
default: "new",
|
|
146
|
-
},
|
|
147
|
-
noGitignore: {
|
|
148
|
-
type: 'boolean',
|
|
149
|
-
description: 'Skip .gitignore files (will use PROBE_NO_GITIGNORE environment variable if not set)',
|
|
135
|
+
description: 'Use when searching for exact function/class/variable names',
|
|
136
|
+
default: false
|
|
150
137
|
}
|
|
151
138
|
},
|
|
152
139
|
required: ['path', 'query']
|
|
@@ -154,37 +141,63 @@ class ProbeServer {
|
|
|
154
141
|
},
|
|
155
142
|
{
|
|
156
143
|
name: 'extract_code',
|
|
157
|
-
description: "Extract code
|
|
144
|
+
description: "Extract code from files. Formats: file.js (whole file), file.js:42 (from line), file.js#functionName (symbol).",
|
|
158
145
|
inputSchema: {
|
|
159
146
|
type: 'object',
|
|
160
147
|
properties: {
|
|
161
148
|
path: {
|
|
162
149
|
type: 'string',
|
|
163
|
-
description: 'Absolute path to the directory
|
|
150
|
+
description: 'Absolute path to the project directory',
|
|
164
151
|
},
|
|
165
152
|
files: {
|
|
166
153
|
type: 'array',
|
|
167
154
|
items: { type: 'string' },
|
|
168
|
-
description: '
|
|
155
|
+
description: 'Array of file paths with optional line/symbol: ["file.rs:10", "file.rs#func_name"]',
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
required: ['path', 'files'],
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
name: 'grep',
|
|
163
|
+
description: "Standard grep-style search for non-code files (logs, config files, text files). Line numbers are shown by default. For code files, use search_code instead.",
|
|
164
|
+
inputSchema: {
|
|
165
|
+
type: 'object',
|
|
166
|
+
properties: {
|
|
167
|
+
pattern: {
|
|
168
|
+
type: 'string',
|
|
169
|
+
description: 'Regular expression pattern to search for',
|
|
170
|
+
},
|
|
171
|
+
paths: {
|
|
172
|
+
oneOf: [
|
|
173
|
+
{ type: 'string' },
|
|
174
|
+
{ type: 'array', items: { type: 'string' } }
|
|
175
|
+
],
|
|
176
|
+
description: 'Path or array of paths to search in',
|
|
169
177
|
},
|
|
170
|
-
|
|
178
|
+
ignoreCase: {
|
|
171
179
|
type: 'boolean',
|
|
172
|
-
description: '
|
|
173
|
-
default:
|
|
180
|
+
description: 'Case-insensitive search',
|
|
181
|
+
default: false
|
|
174
182
|
},
|
|
175
|
-
|
|
183
|
+
count: {
|
|
176
184
|
type: 'boolean',
|
|
177
|
-
description: '
|
|
185
|
+
description: 'Only show count of matches per file instead of the matches',
|
|
186
|
+
default: false
|
|
187
|
+
},
|
|
188
|
+
context: {
|
|
189
|
+
type: 'number',
|
|
190
|
+
description: 'Number of lines of context to show before and after each match',
|
|
178
191
|
}
|
|
179
192
|
},
|
|
180
|
-
required: ['
|
|
193
|
+
required: ['pattern', 'paths'],
|
|
181
194
|
},
|
|
182
195
|
},
|
|
183
196
|
],
|
|
184
197
|
}));
|
|
185
198
|
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
186
199
|
if (request.params.name !== 'search_code' && request.params.name !== 'extract_code' &&
|
|
187
|
-
request.params.name !== 'probe' && request.params.name !== 'extract') {
|
|
200
|
+
request.params.name !== 'grep' && request.params.name !== 'probe' && request.params.name !== 'extract') {
|
|
188
201
|
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
|
|
189
202
|
}
|
|
190
203
|
try {
|
|
@@ -208,6 +221,10 @@ class ProbeServer {
|
|
|
208
221
|
}
|
|
209
222
|
result = await this.executeCodeSearch(args);
|
|
210
223
|
}
|
|
224
|
+
else if (request.params.name === 'grep') {
|
|
225
|
+
const args = request.params.arguments;
|
|
226
|
+
result = await this.executeGrep(args);
|
|
227
|
+
}
|
|
211
228
|
else { // extract_code or extract
|
|
212
229
|
const args = request.params.arguments;
|
|
213
230
|
result = await this.executeCodeExtract(args);
|
|
@@ -245,54 +262,27 @@ class ProbeServer {
|
|
|
245
262
|
if (!args.query) {
|
|
246
263
|
throw new Error("Query is required");
|
|
247
264
|
}
|
|
248
|
-
//
|
|
249
|
-
console.error(`Received search arguments: path=${args.path}, query=${JSON.stringify(args.query)}`);
|
|
250
|
-
// Create a clean options object with only the essential properties first
|
|
265
|
+
// Build options with smart defaults
|
|
251
266
|
const options = {
|
|
252
|
-
path: args.path.trim(),
|
|
253
|
-
query: args.query
|
|
267
|
+
path: args.path.trim(),
|
|
268
|
+
query: args.query,
|
|
269
|
+
// Smart defaults for MCP usage
|
|
270
|
+
allowTests: true, // Include test files by default
|
|
271
|
+
session: "new", // Fresh session each time
|
|
272
|
+
maxResults: 20, // Reasonable limit for context window
|
|
273
|
+
maxTokens: 8000, // Fits in most AI context windows
|
|
254
274
|
};
|
|
255
|
-
//
|
|
275
|
+
// Only override defaults if user explicitly set them
|
|
256
276
|
if (args.exact !== undefined)
|
|
257
277
|
options.exact = args.exact;
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
options.maxTokens = args.maxTokens;
|
|
262
|
-
// Set allowTests to true by default if not specified
|
|
263
|
-
if (args.allowTests !== undefined) {
|
|
264
|
-
options.allowTests = args.allowTests;
|
|
265
|
-
}
|
|
266
|
-
else {
|
|
267
|
-
options.allowTests = true;
|
|
268
|
-
}
|
|
269
|
-
// Use noGitignore from args, or fall back to PROBE_NO_GITIGNORE environment variable
|
|
270
|
-
if (args.noGitignore !== undefined) {
|
|
271
|
-
options.noGitignore = args.noGitignore;
|
|
272
|
-
}
|
|
273
|
-
else if (process.env.PROBE_NO_GITIGNORE) {
|
|
274
|
-
options.noGitignore = process.env.PROBE_NO_GITIGNORE === 'true';
|
|
275
|
-
}
|
|
276
|
-
if (args.session !== undefined && args.session.trim() !== '') {
|
|
277
|
-
options.session = args.session;
|
|
278
|
-
}
|
|
279
|
-
else {
|
|
280
|
-
options.session = "new";
|
|
281
|
-
}
|
|
282
|
-
// Handle format options
|
|
283
|
-
if (this.defaultFormat === 'outline-xml') {
|
|
284
|
-
// For outline-xml format, we pass it as a format flag to the search command
|
|
285
|
-
options.format = 'outline-xml';
|
|
278
|
+
// Handle format based on server default
|
|
279
|
+
if (this.defaultFormat === 'outline' || this.defaultFormat === 'outline-xml') {
|
|
280
|
+
options.format = this.defaultFormat;
|
|
286
281
|
}
|
|
287
282
|
else if (this.defaultFormat === 'json') {
|
|
288
283
|
options.json = true;
|
|
289
284
|
}
|
|
290
285
|
console.error("Executing search with options:", JSON.stringify(options, null, 2));
|
|
291
|
-
// Double-check that path is still in the options object
|
|
292
|
-
if (!options.path) {
|
|
293
|
-
console.error("Path is missing from options object after construction");
|
|
294
|
-
throw new Error("Path is missing from options object");
|
|
295
|
-
}
|
|
296
286
|
try {
|
|
297
287
|
// Call search with the options object
|
|
298
288
|
const result = await search(options);
|
|
@@ -317,26 +307,13 @@ class ProbeServer {
|
|
|
317
307
|
if (!args.files || !Array.isArray(args.files) || args.files.length === 0) {
|
|
318
308
|
throw new Error("Files array is required and must not be empty");
|
|
319
309
|
}
|
|
320
|
-
//
|
|
310
|
+
// Build options with smart defaults
|
|
321
311
|
const options = {
|
|
322
312
|
files: args.files,
|
|
323
313
|
path: args.path,
|
|
324
|
-
format: 'xml'
|
|
314
|
+
format: 'xml',
|
|
315
|
+
allowTests: true, // Include test files by default
|
|
325
316
|
};
|
|
326
|
-
// Set allowTests to true by default if not specified
|
|
327
|
-
if (args.allowTests !== undefined) {
|
|
328
|
-
options.allowTests = args.allowTests;
|
|
329
|
-
}
|
|
330
|
-
else {
|
|
331
|
-
options.allowTests = true;
|
|
332
|
-
}
|
|
333
|
-
// Use noGitignore from args, or fall back to PROBE_NO_GITIGNORE environment variable
|
|
334
|
-
if (args.noGitignore !== undefined) {
|
|
335
|
-
options.noGitignore = args.noGitignore;
|
|
336
|
-
}
|
|
337
|
-
else if (process.env.PROBE_NO_GITIGNORE) {
|
|
338
|
-
options.noGitignore = process.env.PROBE_NO_GITIGNORE === 'true';
|
|
339
|
-
}
|
|
340
317
|
// Call extract with the complete options object
|
|
341
318
|
try {
|
|
342
319
|
// Track request size for token usage
|
|
@@ -380,6 +357,47 @@ class ProbeServer {
|
|
|
380
357
|
throw new McpError('MethodNotFound', `Error executing code extract: ${error.message || String(error)}`);
|
|
381
358
|
}
|
|
382
359
|
}
|
|
360
|
+
async executeGrep(args) {
|
|
361
|
+
try {
|
|
362
|
+
// Validate required parameters
|
|
363
|
+
if (!args.pattern) {
|
|
364
|
+
throw new Error("Pattern is required");
|
|
365
|
+
}
|
|
366
|
+
if (!args.paths) {
|
|
367
|
+
throw new Error("Paths are required");
|
|
368
|
+
}
|
|
369
|
+
// Build options object with good defaults
|
|
370
|
+
const options = {
|
|
371
|
+
pattern: args.pattern,
|
|
372
|
+
paths: args.paths,
|
|
373
|
+
// Default: show line numbers (makes output more useful)
|
|
374
|
+
lineNumbers: true,
|
|
375
|
+
// Default: never use color in MCP context (better for parsing)
|
|
376
|
+
color: 'never'
|
|
377
|
+
};
|
|
378
|
+
// Only add user-specified optional parameters
|
|
379
|
+
if (args.ignoreCase !== undefined)
|
|
380
|
+
options.ignoreCase = args.ignoreCase;
|
|
381
|
+
if (args.count !== undefined)
|
|
382
|
+
options.count = args.count;
|
|
383
|
+
if (args.context !== undefined)
|
|
384
|
+
options.context = args.context;
|
|
385
|
+
console.error("Executing grep with options:", JSON.stringify(options, null, 2));
|
|
386
|
+
try {
|
|
387
|
+
// Call grep with the options object
|
|
388
|
+
const result = await grep(options);
|
|
389
|
+
return result || 'No matches found';
|
|
390
|
+
}
|
|
391
|
+
catch (grepError) {
|
|
392
|
+
console.error("Grep function error:", grepError);
|
|
393
|
+
throw new Error(`Grep function error: ${grepError.message || String(grepError)}`);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
catch (error) {
|
|
397
|
+
console.error('Error executing grep:', error);
|
|
398
|
+
throw new McpError('MethodNotFound', `Error executing grep: ${error.message || String(error)}`);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
383
401
|
async run() {
|
|
384
402
|
// The @probelabs/probe package now handles binary path management internally
|
|
385
403
|
// We don't need to verify or download the binary in the MCP server anymore
|
|
@@ -389,5 +407,5 @@ class ProbeServer {
|
|
|
389
407
|
console.error('Probe MCP server running on stdio');
|
|
390
408
|
}
|
|
391
409
|
}
|
|
392
|
-
const server = new ProbeServer(cliConfig.timeout, cliConfig.format || 'outline
|
|
410
|
+
const server = new ProbeServer(cliConfig.timeout, cliConfig.format || 'outline');
|
|
393
411
|
server.run().catch(console.error);
|
package/build/mcp/index.ts
CHANGED
|
@@ -14,7 +14,7 @@ import fs from 'fs-extra';
|
|
|
14
14
|
import { fileURLToPath } from 'url';
|
|
15
15
|
|
|
16
16
|
// Import from parent package
|
|
17
|
-
import { search, query, extract, getBinaryPath, setBinaryPath } from '../index.js';
|
|
17
|
+
import { search, query, extract, grep, getBinaryPath, setBinaryPath } from '../index.js';
|
|
18
18
|
|
|
19
19
|
// Parse command-line arguments
|
|
20
20
|
function parseArgs(): { timeout?: number; format?: string } {
|
|
@@ -44,7 +44,7 @@ Usage:
|
|
|
44
44
|
|
|
45
45
|
Options:
|
|
46
46
|
--timeout, -t <seconds> Set timeout for search operations (default: 30)
|
|
47
|
-
--format <format> Set output format (
|
|
47
|
+
--format <format> Set output format (default: outline)
|
|
48
48
|
--help, -h Show this help message
|
|
49
49
|
`);
|
|
50
50
|
process.exit(0);
|
|
@@ -113,19 +113,19 @@ interface SearchCodeArgs {
|
|
|
113
113
|
path: string;
|
|
114
114
|
query: string | string[];
|
|
115
115
|
exact?: boolean;
|
|
116
|
-
maxResults?: number;
|
|
117
|
-
maxTokens?: number;
|
|
118
|
-
allowTests?: boolean;
|
|
119
|
-
session?: string;
|
|
120
|
-
noGitignore?: boolean;
|
|
121
116
|
}
|
|
122
117
|
|
|
123
|
-
|
|
124
118
|
interface ExtractCodeArgs {
|
|
125
119
|
path: string;
|
|
126
120
|
files: string[];
|
|
127
|
-
|
|
128
|
-
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
interface GrepArgs {
|
|
124
|
+
pattern: string;
|
|
125
|
+
paths: string | string[];
|
|
126
|
+
ignoreCase?: boolean;
|
|
127
|
+
count?: boolean;
|
|
128
|
+
context?: number;
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
class ProbeServer {
|
|
@@ -151,7 +151,7 @@ class ProbeServer {
|
|
|
151
151
|
this.setupToolHandlers();
|
|
152
152
|
|
|
153
153
|
// Error handling
|
|
154
|
-
this.server.onerror = (error) => console.error('[MCP
|
|
154
|
+
this.server.onerror = (error) => console.error('[MCP ERROR]', error);
|
|
155
155
|
process.on('SIGINT', async () => {
|
|
156
156
|
await this.server.close();
|
|
157
157
|
process.exit(0);
|
|
@@ -165,35 +165,22 @@ class ProbeServer {
|
|
|
165
165
|
tools: [
|
|
166
166
|
{
|
|
167
167
|
name: 'search_code',
|
|
168
|
-
description: "
|
|
168
|
+
description: "Semantic code search using AST parsing and ElasticSearch-style queries. Use this for finding code, not grep.",
|
|
169
169
|
inputSchema: {
|
|
170
170
|
type: 'object',
|
|
171
171
|
properties: {
|
|
172
172
|
path: {
|
|
173
173
|
type: 'string',
|
|
174
|
-
description: 'Absolute path to the directory to search
|
|
174
|
+
description: 'Absolute path to the directory to search',
|
|
175
175
|
},
|
|
176
176
|
query: {
|
|
177
177
|
type: 'string',
|
|
178
|
-
description: '
|
|
178
|
+
description: 'Search query. Use quotes for exact matches: "functionName". Supports AND, OR, NOT operators.',
|
|
179
179
|
},
|
|
180
180
|
exact: {
|
|
181
181
|
type: 'boolean',
|
|
182
|
-
description: '
|
|
183
|
-
|
|
184
|
-
allowTests: {
|
|
185
|
-
type: 'boolean',
|
|
186
|
-
description: 'Allow test files and test code blocks in results (enabled by default)',
|
|
187
|
-
default: true
|
|
188
|
-
},
|
|
189
|
-
session: {
|
|
190
|
-
type: 'string',
|
|
191
|
-
description: 'Session identifier for caching. Set to "new" if unknown, or want to reset cache. Re-use session ID returned from previous searches',
|
|
192
|
-
default: "new",
|
|
193
|
-
},
|
|
194
|
-
noGitignore: {
|
|
195
|
-
type: 'boolean',
|
|
196
|
-
description: 'Skip .gitignore files (will use PROBE_NO_GITIGNORE environment variable if not set)',
|
|
182
|
+
description: 'Use when searching for exact function/class/variable names',
|
|
183
|
+
default: false
|
|
197
184
|
}
|
|
198
185
|
},
|
|
199
186
|
required: ['path', 'query']
|
|
@@ -201,30 +188,56 @@ class ProbeServer {
|
|
|
201
188
|
},
|
|
202
189
|
{
|
|
203
190
|
name: 'extract_code',
|
|
204
|
-
description: "Extract code
|
|
191
|
+
description: "Extract code from files. Formats: file.js (whole file), file.js:42 (from line), file.js#functionName (symbol).",
|
|
205
192
|
inputSchema: {
|
|
206
193
|
type: 'object',
|
|
207
194
|
properties: {
|
|
208
195
|
path: {
|
|
209
196
|
type: 'string',
|
|
210
|
-
description: 'Absolute path to the directory
|
|
197
|
+
description: 'Absolute path to the project directory',
|
|
211
198
|
},
|
|
212
199
|
files: {
|
|
213
200
|
type: 'array',
|
|
214
201
|
items: { type: 'string' },
|
|
215
|
-
description: '
|
|
202
|
+
description: 'Array of file paths with optional line/symbol: ["file.rs:10", "file.rs#func_name"]',
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
required: ['path', 'files'],
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
name: 'grep',
|
|
210
|
+
description: "Standard grep-style search for non-code files (logs, config files, text files). Line numbers are shown by default. For code files, use search_code instead.",
|
|
211
|
+
inputSchema: {
|
|
212
|
+
type: 'object',
|
|
213
|
+
properties: {
|
|
214
|
+
pattern: {
|
|
215
|
+
type: 'string',
|
|
216
|
+
description: 'Regular expression pattern to search for',
|
|
217
|
+
},
|
|
218
|
+
paths: {
|
|
219
|
+
oneOf: [
|
|
220
|
+
{ type: 'string' },
|
|
221
|
+
{ type: 'array', items: { type: 'string' } }
|
|
222
|
+
],
|
|
223
|
+
description: 'Path or array of paths to search in',
|
|
216
224
|
},
|
|
217
|
-
|
|
225
|
+
ignoreCase: {
|
|
218
226
|
type: 'boolean',
|
|
219
|
-
description: '
|
|
220
|
-
default:
|
|
227
|
+
description: 'Case-insensitive search',
|
|
228
|
+
default: false
|
|
221
229
|
},
|
|
222
|
-
|
|
230
|
+
count: {
|
|
223
231
|
type: 'boolean',
|
|
224
|
-
description: '
|
|
232
|
+
description: 'Only show count of matches per file instead of the matches',
|
|
233
|
+
default: false
|
|
234
|
+
},
|
|
235
|
+
context: {
|
|
236
|
+
type: 'number',
|
|
237
|
+
description: 'Number of lines of context to show before and after each match',
|
|
225
238
|
}
|
|
226
239
|
},
|
|
227
|
-
required: ['
|
|
240
|
+
required: ['pattern', 'paths'],
|
|
228
241
|
},
|
|
229
242
|
},
|
|
230
243
|
],
|
|
@@ -232,7 +245,7 @@ class ProbeServer {
|
|
|
232
245
|
|
|
233
246
|
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
234
247
|
if (request.params.name !== 'search_code' && request.params.name !== 'extract_code' &&
|
|
235
|
-
request.params.name !== 'probe' && request.params.name !== 'extract') {
|
|
248
|
+
request.params.name !== 'grep' && request.params.name !== 'probe' && request.params.name !== 'extract') {
|
|
236
249
|
throw new McpError(
|
|
237
250
|
ErrorCode.MethodNotFound,
|
|
238
251
|
`Unknown tool: ${request.params.name}`
|
|
@@ -252,9 +265,9 @@ class ProbeServer {
|
|
|
252
265
|
if (!request.params.arguments || typeof request.params.arguments !== 'object') {
|
|
253
266
|
throw new Error("Arguments must be an object");
|
|
254
267
|
}
|
|
255
|
-
|
|
268
|
+
|
|
256
269
|
const args = request.params.arguments as unknown as SearchCodeArgs;
|
|
257
|
-
|
|
270
|
+
|
|
258
271
|
// Validate required fields
|
|
259
272
|
if (!args.path) {
|
|
260
273
|
throw new Error("Path is required in arguments");
|
|
@@ -262,8 +275,11 @@ class ProbeServer {
|
|
|
262
275
|
if (!args.query) {
|
|
263
276
|
throw new Error("Query is required in arguments");
|
|
264
277
|
}
|
|
265
|
-
|
|
278
|
+
|
|
266
279
|
result = await this.executeCodeSearch(args);
|
|
280
|
+
} else if (request.params.name === 'grep') {
|
|
281
|
+
const args = request.params.arguments as unknown as GrepArgs;
|
|
282
|
+
result = await this.executeGrep(args);
|
|
267
283
|
} else { // extract_code or extract
|
|
268
284
|
const args = request.params.arguments as unknown as ExtractCodeArgs;
|
|
269
285
|
result = await this.executeCodeExtract(args);
|
|
@@ -304,53 +320,29 @@ class ProbeServer {
|
|
|
304
320
|
throw new Error("Query is required");
|
|
305
321
|
}
|
|
306
322
|
|
|
307
|
-
//
|
|
308
|
-
console.error(`Received search arguments: path=${args.path}, query=${JSON.stringify(args.query)}`);
|
|
309
|
-
|
|
310
|
-
// Create a clean options object with only the essential properties first
|
|
323
|
+
// Build options with smart defaults
|
|
311
324
|
const options: any = {
|
|
312
|
-
path: args.path.trim(),
|
|
313
|
-
query: args.query
|
|
325
|
+
path: args.path.trim(),
|
|
326
|
+
query: args.query,
|
|
327
|
+
// Smart defaults for MCP usage
|
|
328
|
+
allowTests: true, // Include test files by default
|
|
329
|
+
session: "new", // Fresh session each time
|
|
330
|
+
maxResults: 20, // Reasonable limit for context window
|
|
331
|
+
maxTokens: 8000, // Fits in most AI context windows
|
|
314
332
|
};
|
|
315
|
-
|
|
316
|
-
//
|
|
333
|
+
|
|
334
|
+
// Only override defaults if user explicitly set them
|
|
317
335
|
if (args.exact !== undefined) options.exact = args.exact;
|
|
318
|
-
if (args.maxResults !== undefined) options.maxResults = args.maxResults;
|
|
319
|
-
if (args.maxTokens !== undefined) options.maxTokens = args.maxTokens;
|
|
320
|
-
// Set allowTests to true by default if not specified
|
|
321
|
-
if (args.allowTests !== undefined) {
|
|
322
|
-
options.allowTests = args.allowTests;
|
|
323
|
-
} else {
|
|
324
|
-
options.allowTests = true;
|
|
325
|
-
}
|
|
326
|
-
// Use noGitignore from args, or fall back to PROBE_NO_GITIGNORE environment variable
|
|
327
|
-
if (args.noGitignore !== undefined) {
|
|
328
|
-
options.noGitignore = args.noGitignore;
|
|
329
|
-
} else if (process.env.PROBE_NO_GITIGNORE) {
|
|
330
|
-
options.noGitignore = process.env.PROBE_NO_GITIGNORE === 'true';
|
|
331
|
-
}
|
|
332
|
-
if (args.session !== undefined && args.session.trim() !== '') {
|
|
333
|
-
options.session = args.session;
|
|
334
|
-
} else {
|
|
335
|
-
options.session = "new";
|
|
336
|
-
}
|
|
337
336
|
|
|
338
|
-
// Handle format
|
|
339
|
-
if (this.defaultFormat === 'outline-xml') {
|
|
340
|
-
|
|
341
|
-
options.format = 'outline-xml';
|
|
337
|
+
// Handle format based on server default
|
|
338
|
+
if (this.defaultFormat === 'outline' || this.defaultFormat === 'outline-xml') {
|
|
339
|
+
options.format = this.defaultFormat;
|
|
342
340
|
} else if (this.defaultFormat === 'json') {
|
|
343
341
|
options.json = true;
|
|
344
342
|
}
|
|
345
|
-
|
|
343
|
+
|
|
346
344
|
console.error("Executing search with options:", JSON.stringify(options, null, 2));
|
|
347
345
|
|
|
348
|
-
// Double-check that path is still in the options object
|
|
349
|
-
if (!options.path) {
|
|
350
|
-
console.error("Path is missing from options object after construction");
|
|
351
|
-
throw new Error("Path is missing from options object");
|
|
352
|
-
}
|
|
353
|
-
|
|
354
346
|
try {
|
|
355
347
|
// Call search with the options object
|
|
356
348
|
const result = await search(options);
|
|
@@ -379,27 +371,14 @@ class ProbeServer {
|
|
|
379
371
|
throw new Error("Files array is required and must not be empty");
|
|
380
372
|
}
|
|
381
373
|
|
|
382
|
-
//
|
|
374
|
+
// Build options with smart defaults
|
|
383
375
|
const options: any = {
|
|
384
376
|
files: args.files,
|
|
385
377
|
path: args.path,
|
|
386
|
-
format: 'xml'
|
|
378
|
+
format: 'xml',
|
|
379
|
+
allowTests: true, // Include test files by default
|
|
387
380
|
};
|
|
388
381
|
|
|
389
|
-
// Set allowTests to true by default if not specified
|
|
390
|
-
if (args.allowTests !== undefined) {
|
|
391
|
-
options.allowTests = args.allowTests;
|
|
392
|
-
} else {
|
|
393
|
-
options.allowTests = true;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// Use noGitignore from args, or fall back to PROBE_NO_GITIGNORE environment variable
|
|
397
|
-
if (args.noGitignore !== undefined) {
|
|
398
|
-
options.noGitignore = args.noGitignore;
|
|
399
|
-
} else if (process.env.PROBE_NO_GITIGNORE) {
|
|
400
|
-
options.noGitignore = process.env.PROBE_NO_GITIGNORE === 'true';
|
|
401
|
-
}
|
|
402
|
-
|
|
403
382
|
// Call extract with the complete options object
|
|
404
383
|
try {
|
|
405
384
|
// Track request size for token usage
|
|
@@ -454,6 +433,50 @@ class ProbeServer {
|
|
|
454
433
|
}
|
|
455
434
|
}
|
|
456
435
|
|
|
436
|
+
private async executeGrep(args: GrepArgs): Promise<string> {
|
|
437
|
+
try {
|
|
438
|
+
// Validate required parameters
|
|
439
|
+
if (!args.pattern) {
|
|
440
|
+
throw new Error("Pattern is required");
|
|
441
|
+
}
|
|
442
|
+
if (!args.paths) {
|
|
443
|
+
throw new Error("Paths are required");
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Build options object with good defaults
|
|
447
|
+
const options: any = {
|
|
448
|
+
pattern: args.pattern,
|
|
449
|
+
paths: args.paths,
|
|
450
|
+
// Default: show line numbers (makes output more useful)
|
|
451
|
+
lineNumbers: true,
|
|
452
|
+
// Default: never use color in MCP context (better for parsing)
|
|
453
|
+
color: 'never'
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
// Only add user-specified optional parameters
|
|
457
|
+
if (args.ignoreCase !== undefined) options.ignoreCase = args.ignoreCase;
|
|
458
|
+
if (args.count !== undefined) options.count = args.count;
|
|
459
|
+
if (args.context !== undefined) options.context = args.context;
|
|
460
|
+
|
|
461
|
+
console.error("Executing grep with options:", JSON.stringify(options, null, 2));
|
|
462
|
+
|
|
463
|
+
try {
|
|
464
|
+
// Call grep with the options object
|
|
465
|
+
const result = await grep(options);
|
|
466
|
+
return result || 'No matches found';
|
|
467
|
+
} catch (grepError: any) {
|
|
468
|
+
console.error("Grep function error:", grepError);
|
|
469
|
+
throw new Error(`Grep function error: ${grepError.message || String(grepError)}`);
|
|
470
|
+
}
|
|
471
|
+
} catch (error: any) {
|
|
472
|
+
console.error('Error executing grep:', error);
|
|
473
|
+
throw new McpError(
|
|
474
|
+
'MethodNotFound' as unknown as ErrorCode,
|
|
475
|
+
`Error executing grep: ${error.message || String(error)}`
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
457
480
|
async run() {
|
|
458
481
|
// The @probelabs/probe package now handles binary path management internally
|
|
459
482
|
// We don't need to verify or download the binary in the MCP server anymore
|
|
@@ -465,5 +488,5 @@ class ProbeServer {
|
|
|
465
488
|
}
|
|
466
489
|
}
|
|
467
490
|
|
|
468
|
-
const server = new ProbeServer(cliConfig.timeout, cliConfig.format || 'outline
|
|
491
|
+
const server = new ProbeServer(cliConfig.timeout, cliConfig.format || 'outline');
|
|
469
492
|
server.run().catch(console.error);
|