@znt/mcp 1.0.6 → 1.0.8
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/index.js +50 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
* `role` *(string)*: Фильтр по архитектурной роли (`"controller"`, `"service"`, `"repository"`, `"model"`).
|
|
48
48
|
* `type` *(string)*: Фильтр по типу узла AST (`"function"`, `"struct"`, `"class"`, `"interface"`).
|
|
49
49
|
* `file_pattern` *(string)*: Маска пути файла (например `"pkg/semantic/*"` или `"*.go"`).
|
|
50
|
-
* `
|
|
50
|
+
* `mode` *(string)*: Режим поиска: `"hybrid"` (RRF гибридный), `"lexical"` (точный BM25/FTS5), `"vector"` (чисто векторный). По умолчанию `"hybrid"`.
|
|
51
51
|
|
|
52
52
|
---
|
|
53
53
|
|
package/index.js
CHANGED
|
@@ -293,14 +293,15 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
293
293
|
properties: {
|
|
294
294
|
query: { type: 'string', description: 'Поисковый запрос на естественном языке (например: "обработка HTTP запросов в сервере")' },
|
|
295
295
|
limit: { type: 'number', description: 'Максимальное количество результатов поиска (по умолчанию 10)' },
|
|
296
|
-
callers_level: { type: 'number', description: 'Глубина вложенности графа входящих вызовов ("где вызывается"), по умолчанию
|
|
297
|
-
callees_level: { type: 'number', description: 'Глубина вложенности графа исходящих вызовов ("где вызывают"), по умолчанию
|
|
296
|
+
callers_level: { type: 'number', description: 'Глубина вложенности графа входящих вызовов ("где вызывается"), по умолчанию 0' },
|
|
297
|
+
callees_level: { type: 'number', description: 'Глубина вложенности графа исходящих вызовов ("где вызывают"), по умолчанию 0' },
|
|
298
|
+
compact: { type: 'boolean', description: 'Возвращать только компактный DTO {name, file, start_line, end_line, summary, role, type, score} без графа связей' },
|
|
298
299
|
include_code: { type: 'boolean', description: 'Включать ли исходный код (фрагмент узла) в результаты поиска' },
|
|
299
300
|
max_code_lines: { type: 'number', description: 'Максимальное количество строк исходного кода (по умолчанию 30)' },
|
|
300
301
|
role: { type: 'string', description: 'Фильтр по архитектурной роли компонента (например: "controller", "repository", "service", "model")' },
|
|
301
302
|
type: { type: 'string', description: 'Фильтр по типу узла AST (например: "function", "struct", "class", "interface")' },
|
|
302
303
|
file_pattern: { type: 'string', description: 'Шаблон/маска пути файла для фильтрации (например: "pkg/semantic/*" или "*.go")' },
|
|
303
|
-
|
|
304
|
+
mode: { type: 'string', description: 'Режим поиска: "hybrid" (RRF гибридный), "lexical" (точный BM25/FTS5), "vector" (чисто векторный). По умолчанию "hybrid"' }
|
|
304
305
|
},
|
|
305
306
|
required: ['query']
|
|
306
307
|
},
|
|
@@ -346,7 +347,8 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
346
347
|
type: 'object',
|
|
347
348
|
properties: {
|
|
348
349
|
path: { type: 'string', description: 'Относительный или абсолютный путь к целевому файлу (например: "internal/engine/server.go")' },
|
|
349
|
-
include_code: { type: 'boolean', description: 'Включать ли фрагменты/сигнатуры исходного кода для каждого символа' }
|
|
350
|
+
include_code: { type: 'boolean', description: 'Включать ли фрагменты/сигнатуры исходного кода для каждого символа' },
|
|
351
|
+
format: { type: 'string', description: 'Формат ответа: "text" (сверхкомпактный атлас строк, экономит до 75% токенов) или "json"' }
|
|
350
352
|
},
|
|
351
353
|
required: ['path']
|
|
352
354
|
},
|
|
@@ -409,9 +411,7 @@ async function callZntApi(endpoint, method = 'GET', body = null) {
|
|
|
409
411
|
throw new Error(data.content);
|
|
410
412
|
}
|
|
411
413
|
} catch (err) {
|
|
412
|
-
|
|
413
|
-
throw err;
|
|
414
|
-
}
|
|
414
|
+
// Ignore parse errors
|
|
415
415
|
}
|
|
416
416
|
}
|
|
417
417
|
}
|
|
@@ -419,6 +419,11 @@ async function callZntApi(endpoint, method = 'GET', body = null) {
|
|
|
419
419
|
return { content: text };
|
|
420
420
|
}
|
|
421
421
|
|
|
422
|
+
const contentType = response.headers.get('content-type') || '';
|
|
423
|
+
if (contentType.includes('text/plain')) {
|
|
424
|
+
return response.text();
|
|
425
|
+
}
|
|
426
|
+
|
|
422
427
|
return response.json();
|
|
423
428
|
}
|
|
424
429
|
|
|
@@ -496,14 +501,17 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
496
501
|
break;
|
|
497
502
|
}
|
|
498
503
|
const limit = Math.min(Math.max(1, parseInt(request.params.arguments?.limit, 10) || 10), 100);
|
|
499
|
-
const
|
|
500
|
-
const
|
|
504
|
+
const callersLevelArg = request.params.arguments?.callers_level ?? request.params.arguments?.caller_level;
|
|
505
|
+
const callersLevel = Math.min(Math.max(0, callersLevelArg !== undefined ? (parseInt(callersLevelArg, 10) || 0) : 0), 10);
|
|
506
|
+
const calleesLevelArg = request.params.arguments?.callees_level ?? request.params.arguments?.callee_level;
|
|
507
|
+
const calleesLevel = Math.min(Math.max(0, calleesLevelArg !== undefined ? (parseInt(calleesLevelArg, 10) || 0) : 0), 10);
|
|
508
|
+
const compact = Boolean(request.params.arguments?.compact);
|
|
501
509
|
const includeCode = Boolean(request.params.arguments?.include_code);
|
|
502
510
|
const maxCodeLines = parseInt(request.params.arguments?.max_code_lines, 10) || 30;
|
|
503
511
|
const role = request.params.arguments?.role || '';
|
|
504
512
|
const nodeType = request.params.arguments?.type || '';
|
|
505
513
|
const filePattern = request.params.arguments?.file_pattern || '';
|
|
506
|
-
const
|
|
514
|
+
const mode = request.params.arguments?.mode || (request.params.arguments?.hybrid === false ? 'lexical' : 'hybrid');
|
|
507
515
|
|
|
508
516
|
const apiParams = new URLSearchParams({
|
|
509
517
|
q: query,
|
|
@@ -512,8 +520,10 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
512
520
|
callees_level: calleesLevel.toString(),
|
|
513
521
|
include_code: includeCode.toString(),
|
|
514
522
|
max_code_lines: maxCodeLines.toString(),
|
|
515
|
-
|
|
523
|
+
mode: mode,
|
|
524
|
+
format: 'text'
|
|
516
525
|
});
|
|
526
|
+
if (compact) apiParams.set('compact', 'true');
|
|
517
527
|
if (role) apiParams.set('role', role);
|
|
518
528
|
if (nodeType) apiParams.set('type', nodeType);
|
|
519
529
|
if (filePattern) apiParams.set('file_pattern', filePattern);
|
|
@@ -521,16 +531,35 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
521
531
|
const rawResults = await callZntApi(`/api/search?${apiParams.toString()}`);
|
|
522
532
|
let processed = Array.isArray(rawResults) ? rawResults.map(item => {
|
|
523
533
|
const relFile = toRelativePath(item.file || item.file_path || item.filePath);
|
|
534
|
+
let codeSnippet = item.code;
|
|
535
|
+
if (includeCode && !codeSnippet && relFile && item.start_line && item.end_line) {
|
|
536
|
+
let endLine = item.end_line;
|
|
537
|
+
if (maxCodeLines > 0 && (endLine - item.start_line + 1) > maxCodeLines) {
|
|
538
|
+
endLine = item.start_line + maxCodeLines - 1;
|
|
539
|
+
}
|
|
540
|
+
codeSnippet = getSourceSnippet(relFile, item.start_line, endLine);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
if (compact) {
|
|
544
|
+
return {
|
|
545
|
+
name: item.name,
|
|
546
|
+
file: relFile,
|
|
547
|
+
start_line: item.start_line,
|
|
548
|
+
end_line: item.end_line,
|
|
549
|
+
summary: item.summary,
|
|
550
|
+
role: item.role,
|
|
551
|
+
type: item.type,
|
|
552
|
+
score: item.score,
|
|
553
|
+
...(codeSnippet ? { code: codeSnippet } : {})
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
|
|
524
557
|
const resItem = {
|
|
525
558
|
...item,
|
|
526
559
|
file: relFile
|
|
527
560
|
};
|
|
528
|
-
if (
|
|
529
|
-
|
|
530
|
-
if (maxCodeLines > 0 && (endLine - resItem.start_line + 1) > maxCodeLines) {
|
|
531
|
-
endLine = resItem.start_line + maxCodeLines - 1;
|
|
532
|
-
}
|
|
533
|
-
resItem.code = getSourceSnippet(resItem.file, resItem.start_line, endLine);
|
|
561
|
+
if (codeSnippet) {
|
|
562
|
+
resItem.code = codeSnippet;
|
|
534
563
|
}
|
|
535
564
|
return resItem;
|
|
536
565
|
}) : rawResults;
|
|
@@ -571,11 +600,15 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
571
600
|
break;
|
|
572
601
|
}
|
|
573
602
|
const includeCode = Boolean(request.params.arguments?.include_code);
|
|
603
|
+
const format = request.params.arguments?.format || '';
|
|
574
604
|
|
|
575
605
|
const queryParams = new URLSearchParams({
|
|
576
606
|
path: filePath,
|
|
577
607
|
include_code: includeCode.toString(),
|
|
578
608
|
});
|
|
609
|
+
if (format) {
|
|
610
|
+
queryParams.set('format', format);
|
|
611
|
+
}
|
|
579
612
|
|
|
580
613
|
const resData = await callZntApi(`/api/file/outline?${queryParams.toString()}`);
|
|
581
614
|
result = resData;
|