smart-context-mcp 1.13.0 → 1.14.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.
- package/README.md +1 -1
- package/package.json +2 -1
- package/server.json +2 -2
- package/src/server.js +3 -2
- package/src/tools/smart-search.js +23 -11
package/README.md
CHANGED
|
@@ -56,7 +56,7 @@ Restart your AI client. Done.
|
|
|
56
56
|
# Check installed version
|
|
57
57
|
npm list -g smart-context-mcp
|
|
58
58
|
|
|
59
|
-
# Should show: smart-context-mcp@1.
|
|
59
|
+
# Should show: smart-context-mcp@1.14.0 (or later)
|
|
60
60
|
|
|
61
61
|
# Update to latest version
|
|
62
62
|
npm update -g smart-context-mcp
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "smart-context-mcp",
|
|
3
3
|
"mcpName": "io.github.Arrayo/smart-context-mcp",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.14.0",
|
|
5
5
|
"description": "MCP server that reduces agent token usage by 90% with intelligent context compression, task checkpoint persistence, and workflow-aware agent guidance.",
|
|
6
6
|
"author": "Francisco Caballero Portero <fcp1978@hotmail.com>",
|
|
7
7
|
"type": "module",
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
"init:clients": "node ./scripts/init-clients.js",
|
|
61
61
|
"smoke:formats": "node ./scripts/format-smoke.js",
|
|
62
62
|
"test": "node --test --test-concurrency=1 ./tests/*.test.js",
|
|
63
|
+
"test:fast": "node --test --test-concurrency=4 ./tests/*.test.js",
|
|
63
64
|
"verify": "node ./scripts/verify-features-direct.js",
|
|
64
65
|
"benchmark": "node ./scripts/run-benchmark.js",
|
|
65
66
|
"benchmark:orchestration": "node ./evals/orchestration-benchmark.js",
|
package/server.json
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/Arrayo/smart-context-mcp",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "1.
|
|
9
|
+
"version": "1.14.0",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "smart-context-mcp",
|
|
14
|
-
"version": "1.
|
|
14
|
+
"version": "1.14.0",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|
package/src/server.js
CHANGED
|
@@ -146,13 +146,14 @@ export const createDevctxServer = () => {
|
|
|
146
146
|
|
|
147
147
|
server.tool(
|
|
148
148
|
'smart_search',
|
|
149
|
-
'Search code
|
|
149
|
+
'Search code with ranked, deduplicated results and index boosting. Best for: finding where a symbol is defined/used, understanding call chains, locating implementations. NOT ideal for: exact string matching (use Grep), finding files by name (use Glob), broad multi-word queries (generates noise). Optional intent adjusts ranking. maxFiles caps the number of files returned (default 15). When >30 files match, results include a hint suggesting Grep instead.',
|
|
150
150
|
{
|
|
151
151
|
query: z.string(),
|
|
152
152
|
cwd: z.string().optional(),
|
|
153
153
|
intent: z.enum(['implementation', 'debug', 'tests', 'config', 'docs', 'explore']).optional(),
|
|
154
|
+
maxFiles: z.number().int().min(1).max(50).optional(),
|
|
154
155
|
},
|
|
155
|
-
async ({ query, cwd = '.', intent }) => asTextResult(await smartSearch({ query, cwd, intent })),
|
|
156
|
+
async ({ query, cwd = '.', intent, maxFiles }) => asTextResult(await smartSearch({ query, cwd, intent, maxFiles })),
|
|
156
157
|
);
|
|
157
158
|
|
|
158
159
|
server.tool(
|
|
@@ -324,16 +324,20 @@ const buildZeroResultsMessage = (query, searchMode, provenance) => {
|
|
|
324
324
|
return lines.join('\n');
|
|
325
325
|
};
|
|
326
326
|
|
|
327
|
-
const
|
|
327
|
+
const MAX_RESULT_FILES = 15;
|
|
328
|
+
|
|
329
|
+
const buildCompactResult = (groups, totalMatches, query, root, searchMode, provenance, totalFiles) => {
|
|
328
330
|
if (totalMatches === 0) {
|
|
329
331
|
return buildZeroResultsMessage(query, searchMode, provenance);
|
|
330
332
|
}
|
|
331
333
|
|
|
332
334
|
const modeLabel = searchMode === 'exact' ? '' : searchMode === 'regex' ? ' [regex fallback]' : ` [term expansion: ${(provenance?.expandedTerms ?? []).join(', ')}]`;
|
|
333
335
|
|
|
336
|
+
const topGroups = groups.slice(0, MAX_RESULT_FILES);
|
|
337
|
+
|
|
334
338
|
if (totalMatches <= 20) {
|
|
335
339
|
const header = modeLabel ? `# Search mode:${modeLabel}\n\n` : '';
|
|
336
|
-
return header +
|
|
340
|
+
return header + topGroups
|
|
337
341
|
.flatMap((group) => group.matches)
|
|
338
342
|
.map(formatMatch)
|
|
339
343
|
.join('\n');
|
|
@@ -341,29 +345,34 @@ const buildCompactResult = (groups, totalMatches, query, root, searchMode, prove
|
|
|
341
345
|
|
|
342
346
|
const lines = [
|
|
343
347
|
`query: ${query}${modeLabel}`,
|
|
344
|
-
`
|
|
345
|
-
`total matches: ${totalMatches}`,
|
|
346
|
-
`matched files: ${groups.length}`,
|
|
348
|
+
`total: ${totalMatches} matches in ${totalFiles ?? groups.length} files${totalFiles && totalFiles > groups.length ? ` (showing top ${groups.length})` : ''}`,
|
|
347
349
|
'',
|
|
348
350
|
'# Top files',
|
|
349
351
|
];
|
|
350
352
|
|
|
351
|
-
for (const group of
|
|
353
|
+
for (const group of topGroups.slice(0, 10)) {
|
|
352
354
|
lines.push(`${group.count} match(es), score ${group.score} :: ${group.file}`);
|
|
353
355
|
}
|
|
354
356
|
|
|
355
357
|
lines.push('', '# Sample matches');
|
|
356
358
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
+
const topScore = topGroups[0]?.score ?? 0;
|
|
360
|
+
for (const group of topGroups.slice(0, 5)) {
|
|
361
|
+
const linesPerFile = group.score >= topScore * 0.7 ? 5 : 2;
|
|
362
|
+
for (const match of group.matches.slice(0, linesPerFile)) {
|
|
359
363
|
lines.push(formatMatch(match));
|
|
360
364
|
}
|
|
361
365
|
}
|
|
362
366
|
|
|
367
|
+
const fileCount = totalFiles ?? groups.length;
|
|
368
|
+
if (fileCount > 30) {
|
|
369
|
+
lines.push('', `# Note: ${fileCount} files matched — query may be too broad. Use Grep for exact pattern matching.`);
|
|
370
|
+
}
|
|
371
|
+
|
|
363
372
|
return lines.join('\n');
|
|
364
373
|
};
|
|
365
374
|
|
|
366
|
-
export const smartSearch = async ({ query, cwd = '.', intent, _testForceWalk = false, progress: enableProgress = false }) => {
|
|
375
|
+
export const smartSearch = async ({ query, cwd = '.', intent, maxFiles, _testForceWalk = false, progress: enableProgress = false }) => {
|
|
367
376
|
const progress = enableProgress ? createProgressReporter('smart_search') : null;
|
|
368
377
|
const startTime = Date.now();
|
|
369
378
|
|
|
@@ -463,8 +472,11 @@ export const smartSearch = async ({ query, cwd = '.', intent, _testForceWalk = f
|
|
|
463
472
|
}
|
|
464
473
|
}
|
|
465
474
|
|
|
475
|
+
const effectiveMaxFiles = maxFiles ?? MAX_RESULT_FILES;
|
|
476
|
+
const cappedGroups = groups.slice(0, effectiveMaxFiles);
|
|
477
|
+
|
|
466
478
|
const rawText = dedupedMatches.map(formatMatch).join('\n');
|
|
467
|
-
const compressedText = truncate(buildCompactResult(
|
|
479
|
+
const compressedText = truncate(buildCompactResult(cappedGroups, dedupedMatches.length, query, root, searchMode, provenance, groups.length), 5000);
|
|
468
480
|
const metrics = buildMetrics({
|
|
469
481
|
tool: 'smart_search',
|
|
470
482
|
target: `${root} :: ${query}`,
|
|
@@ -522,7 +534,7 @@ export const smartSearch = async ({ query, cwd = '.', intent, _testForceWalk = f
|
|
|
522
534
|
...(indexHits ? { indexBoosted: indexHits.size } : {}),
|
|
523
535
|
totalMatches: dedupedMatches.length,
|
|
524
536
|
matchedFiles: groups.length,
|
|
525
|
-
topFiles:
|
|
537
|
+
topFiles: cappedGroups.slice(0, 10).map((group) => ({ file: group.file, count: group.count, score: group.score })),
|
|
526
538
|
matches: compressedText,
|
|
527
539
|
};
|
|
528
540
|
|