@znt/mcp 1.0.2 → 1.0.4
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 +63 -12
- package/package.json +2 -3
package/README.md
CHANGED
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
| Инструмент | Описание |
|
|
34
34
|
| :--- | :--- |
|
|
35
35
|
| `znatok_semantic_search` | **Гибридный поиск (BM25 + Векторы + RRF)** по кодовой базе. Находит узлы, архитектурные роли (`controller`, `service`, `repository`), аннотации и связи. |
|
|
36
|
-
| `znatok_find_similar` |
|
|
36
|
+
| `znatok_find_similar` | **Мультифакторный поиск аналогов и дубликатов**. Находит схожие реализации по имени символа (`target`) или описанию (`query`) на основе векторного сходства, связей в графе (Jaccard) и AST-структур. |
|
|
37
37
|
| `znatok_get_subgraph` | **Графовый анализ и трассировка вызовов**. Возвращает подграф зависимостей или трассировку потока данных от узла A к узлу B (`from` ➔ `to`) в формате Mermaid / JSON. |
|
|
38
38
|
| `znatok_file_outline` | **Семантический атлас (оглавление) файла**. Мгновенно отдает список всех символов (функции, структуры, методы) с номерами строк и их ролями. |
|
|
39
39
|
| `znatok_server_logs` | **Логи сервера Znt**. Мониторинг событий индексации и состояния графа в реальном времени. |
|
package/index.js
CHANGED
|
@@ -307,11 +307,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
307
307
|
},
|
|
308
308
|
{
|
|
309
309
|
name: 'znatok_find_similar',
|
|
310
|
-
description: 'Ищет элементы кода
|
|
310
|
+
description: 'Ищет аналогичные элементы кода и дубликаты на основе комбинированного мультифакторного анализа (векторное косинусное сходство, графовые соседи Jaccard и совпадение типов AST/ролей). Позволяет передавать как имя существующего символа (target), так и фрагмент текста/кода (query).',
|
|
311
311
|
inputSchema: {
|
|
312
312
|
type: 'object',
|
|
313
313
|
properties: {
|
|
314
|
-
|
|
314
|
+
target: { type: 'string', description: 'Имя существующего символа, функции или класса в проекте для поиска аналогов (например: "Server.runFullScan"). Если указано, вектор берется напрямую из БД без запроса к LLM.' },
|
|
315
|
+
query: { type: 'string', description: 'Текстовый фрагмент или описание функции/класса для поиска аналогов (используется, если target не задан)' },
|
|
315
316
|
limit: { type: 'number', description: 'Максимальное количество возвращаемых элементов (по умолчанию 10)' },
|
|
316
317
|
callers_level: { type: 'number', description: 'Глубина вложенности входящего графа вызовов ("где вызывается"), по умолчанию 3' },
|
|
317
318
|
callees_level: { type: 'number', description: 'Глубина вложенности исходящего графа вызовов ("где вызывают"), по умолчанию 3' },
|
|
@@ -319,22 +320,20 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
319
320
|
max_code_lines: { type: 'number', description: 'Максимальное количество строк исходного кода (по умолчанию 30)' },
|
|
320
321
|
role: { type: 'string', description: 'Фильтр по архитектурной роли компонента (например: "controller", "repository", "service", "model")' },
|
|
321
322
|
type: { type: 'string', description: 'Фильтр по типу узла AST (например: "function", "struct", "class", "interface")' },
|
|
322
|
-
file_pattern: { type: 'string', description: 'Шаблон/маска пути файла для фильтрации (например: "pkg/semantic/*" или "*.go")' }
|
|
323
|
-
|
|
324
|
-
},
|
|
325
|
-
required: ['query']
|
|
323
|
+
file_pattern: { type: 'string', description: 'Шаблон/маска пути файла для фильтрации (например: "pkg/semantic/*" или "*.go")' }
|
|
324
|
+
}
|
|
326
325
|
},
|
|
327
326
|
},
|
|
328
327
|
{
|
|
329
328
|
name: 'znatok_get_subgraph',
|
|
330
|
-
description: 'Возвращает ориентированный подграф (в формате Mermaid или JSON) вокруг заданного символа/файла (target) или
|
|
329
|
+
description: 'Возвращает ориентированный подграф (в формате Mermaid или JSON) вокруг заданного символа/файла (target) или ищет цепочку вызовов между двумя точками (from + to). Режим target: строит окрестности символа на заданную глубину. Режим трассировки (from + to): DFS запускается от `to` вверх по входящим рёбрам и ищет пути, в которых встречается `from`. Ограничение: если from вызывает to не напрямую, а через промежуточный узел, рёбра могут не отобразиться — в таком случае edges будет пустым и вернутся два изолированных узла.',
|
|
331
330
|
inputSchema: {
|
|
332
331
|
type: 'object',
|
|
333
332
|
properties: {
|
|
334
|
-
target: { type: 'string', description: 'Имя символа, функции, класса или относительный путь файла для построения подграфа окрестностей (например: "SemanticService" или "server.go")' },
|
|
335
|
-
from: { type: 'string', description: '
|
|
336
|
-
to: { type: 'string', description: '
|
|
337
|
-
depth: { type: 'number', description: 'Глубина обхода подграфа (по умолчанию 2)' },
|
|
333
|
+
target: { type: 'string', description: 'Имя символа, функции, класса или относительный путь файла для построения подграфа окрестностей (например: "SemanticService" или "server.go"). Используется только если from/to не заданы.' },
|
|
334
|
+
from: { type: 'string', description: 'Фильтр: символ/функция, которая должна встречаться в путях вызовов, найденных от `to`. Алгоритм ищет пути где from предшествует to по цепочке. Требует совместного указания с `to`.' },
|
|
335
|
+
to: { type: 'string', description: 'Точка старта трассировки — символ/функция, от которой DFS идёт вверх по входящим рёбрам (PredecessorMap). Именно `to` является началом обхода, а не концом. Требует совместного указания с `from`.' },
|
|
336
|
+
depth: { type: 'number', description: 'Глубина обхода подграфа (по умолчанию 2). В режиме трассировки используется как depth*2.' },
|
|
338
337
|
max_nodes: { type: 'number', description: 'Максимальное количество узлов подграфа (по умолчанию 30)' },
|
|
339
338
|
format: { type: 'string', description: 'Формат ответа: "mermaid" для диаграммы в Markdown или "json" (по умолчанию "mermaid")' }
|
|
340
339
|
}
|
|
@@ -437,7 +436,59 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
437
436
|
let sources = [];
|
|
438
437
|
|
|
439
438
|
switch (toolName) {
|
|
440
|
-
case 'znatok_find_similar':
|
|
439
|
+
case 'znatok_find_similar': {
|
|
440
|
+
const target = request.params.arguments?.target || request.params.arguments?.target_symbol || '';
|
|
441
|
+
const query = request.params.arguments?.query || request.params.arguments?.text || '';
|
|
442
|
+
if (!target && !query) {
|
|
443
|
+
result = 'Either target or query parameter is required.';
|
|
444
|
+
break;
|
|
445
|
+
}
|
|
446
|
+
const limit = Math.min(Math.max(1, parseInt(request.params.arguments?.limit, 10) || 10), 100);
|
|
447
|
+
const callersLevel = Math.min(Math.max(0, parseInt(request.params.arguments?.callers_level ?? request.params.arguments?.caller_level, 10) ?? 3), 10);
|
|
448
|
+
const calleesLevel = Math.min(Math.max(0, parseInt(request.params.arguments?.callees_level ?? request.params.arguments?.callee_level, 10) ?? 3), 10);
|
|
449
|
+
const includeCode = Boolean(request.params.arguments?.include_code);
|
|
450
|
+
const maxCodeLines = parseInt(request.params.arguments?.max_code_lines, 10) || 30;
|
|
451
|
+
const role = request.params.arguments?.role || '';
|
|
452
|
+
const nodeType = request.params.arguments?.type || '';
|
|
453
|
+
const filePattern = request.params.arguments?.file_pattern || '';
|
|
454
|
+
|
|
455
|
+
const apiParams = new URLSearchParams({
|
|
456
|
+
limit: limit.toString(),
|
|
457
|
+
callers_level: callersLevel.toString(),
|
|
458
|
+
callees_level: calleesLevel.toString(),
|
|
459
|
+
include_code: includeCode.toString(),
|
|
460
|
+
max_code_lines: maxCodeLines.toString(),
|
|
461
|
+
});
|
|
462
|
+
if (target) apiParams.set('target', target);
|
|
463
|
+
if (query) apiParams.set('q', query);
|
|
464
|
+
if (role) apiParams.set('role', role);
|
|
465
|
+
if (nodeType) apiParams.set('type', nodeType);
|
|
466
|
+
if (filePattern) apiParams.set('file_pattern', filePattern);
|
|
467
|
+
|
|
468
|
+
const rawResults = await callZntApi(`/api/find_similar?${apiParams.toString()}`);
|
|
469
|
+
let processed = Array.isArray(rawResults) ? rawResults.map(item => {
|
|
470
|
+
const relFile = toRelativePath(item.file || item.file_path || item.filePath);
|
|
471
|
+
const resItem = {
|
|
472
|
+
...item,
|
|
473
|
+
file: relFile
|
|
474
|
+
};
|
|
475
|
+
if (includeCode && !resItem.code && resItem.file && resItem.start_line && resItem.end_line) {
|
|
476
|
+
let endLine = resItem.end_line;
|
|
477
|
+
if (maxCodeLines > 0 && (endLine - resItem.start_line + 1) > maxCodeLines) {
|
|
478
|
+
endLine = resItem.start_line + maxCodeLines - 1;
|
|
479
|
+
}
|
|
480
|
+
resItem.code = getSourceSnippet(resItem.file, resItem.start_line, endLine);
|
|
481
|
+
}
|
|
482
|
+
return resItem;
|
|
483
|
+
}) : rawResults;
|
|
484
|
+
if (Array.isArray(processed)) {
|
|
485
|
+
processed = processed.slice(0, limit);
|
|
486
|
+
}
|
|
487
|
+
result = processed;
|
|
488
|
+
sources = ['core_api:find_similar'];
|
|
489
|
+
break;
|
|
490
|
+
}
|
|
491
|
+
|
|
441
492
|
case 'znatok_semantic_search': {
|
|
442
493
|
const query = request.params.arguments?.query || request.params.arguments?.text;
|
|
443
494
|
if (!query) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@znt/mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Model Context Protocol adapter for Znt",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -29,7 +29,6 @@
|
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@modelcontextprotocol/sdk": "^1.0.1",
|
|
32
|
-
"ws": "^8.21.1"
|
|
33
|
-
"yaml": "^2.4.5"
|
|
32
|
+
"ws": "^8.21.1"
|
|
34
33
|
}
|
|
35
34
|
}
|