@znt/mcp 1.0.5 → 1.0.7

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.
Files changed (3) hide show
  1. package/README.md +7 -2
  2. package/index.js +37 -14
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,11 @@
1
- # Znt MCP Adapter (@znt/mcp v1.1.0)
1
+ # Znt MCP Adapter ([@znt/mcp](https://www.npmjs.com/package/@znt/mcp))
2
2
 
3
- Официальный адаптер **Model Context Protocol (MCP)** для системы локального понимания кодовых баз и графового анализа **Знаток (Znt)**.
3
+ Официальный адаптер **Model Context Protocol (MCP)** для системы локального понимания кодовых баз и графового анализа **[Знаток (Znt)](https://github.com/boottaa/znt)**.
4
+
5
+ ## 🔗 Ссылки
6
+ * 📦 **npm пакет**: [https://www.npmjs.com/package/@znt/mcp](https://www.npmjs.com/package/@znt/mcp)
7
+ * 🚀 **Основной репозиторий Znt**: [https://github.com/boottaa/znt](https://github.com/boottaa/znt)
8
+ * 🛠 **Репозиторий MCP-адаптера**: [https://github.com/boottaa/znt_mcp](https://github.com/boottaa/znt_mcp)
4
9
 
5
10
  Позволяет внешним ИИ-агентам и LLM-клиентам (Claude Desktop, Antigravity IDE, Cursor, Windsurf, Zed, Codex и др.) осуществлять гибридный и мультифакторный поиск по смыслу, получать семантические оглавления файлов, строить графы вызовов и трассировать зависимости с прозрачным трекингом экономии контекстных токенов.
6
11
 
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: 'Глубина вложенности графа входящих вызовов ("где вызывается"), по умолчанию 3' },
297
- callees_level: { type: 'number', description: 'Глубина вложенности графа исходящих вызовов ("где вызывают"), по умолчанию 3' },
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
- hybrid: { type: 'boolean', description: 'Использовать гибридный поиск (RRF: BM25/Лексика + Векторы, по умолчанию true)' }
304
+ mode: { type: 'string', description: 'Режим поиска: "hybrid" (RRF гибридный), "lexical" (точный BM25/FTS5), "vector" (чисто векторный). По умолчанию "hybrid"' }
304
305
  },
305
306
  required: ['query']
306
307
  },
@@ -496,14 +497,16 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
496
497
  break;
497
498
  }
498
499
  const limit = Math.min(Math.max(1, parseInt(request.params.arguments?.limit, 10) || 10), 100);
499
- const callersLevel = Math.min(Math.max(0, parseInt(request.params.arguments?.callers_level ?? request.params.arguments?.caller_level, 10) ?? 3), 10);
500
- const calleesLevel = Math.min(Math.max(0, parseInt(request.params.arguments?.callees_level ?? request.params.arguments?.callee_level, 10) ?? 3), 10);
500
+ const callersLevelArg = request.params.arguments?.callers_level ?? request.params.arguments?.caller_level;
501
+ const callersLevel = Math.min(Math.max(0, callersLevelArg !== undefined ? (parseInt(callersLevelArg, 10) || 0) : 0), 10);
502
+ const calleesLevelArg = request.params.arguments?.callees_level ?? request.params.arguments?.callee_level;
503
+ const calleesLevel = Math.min(Math.max(0, calleesLevelArg !== undefined ? (parseInt(calleesLevelArg, 10) || 0) : 0), 10);
504
+ const compact = Boolean(request.params.arguments?.compact);
501
505
  const includeCode = Boolean(request.params.arguments?.include_code);
502
506
  const maxCodeLines = parseInt(request.params.arguments?.max_code_lines, 10) || 30;
503
507
  const role = request.params.arguments?.role || '';
504
508
  const nodeType = request.params.arguments?.type || '';
505
- const filePattern = request.params.arguments?.file_pattern || '';
506
- const hybrid = request.params.arguments?.hybrid !== false;
509
+ const mode = request.params.arguments?.mode || (request.params.arguments?.hybrid === false ? 'lexical' : 'hybrid');
507
510
 
508
511
  const apiParams = new URLSearchParams({
509
512
  q: query,
@@ -512,8 +515,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
512
515
  callees_level: calleesLevel.toString(),
513
516
  include_code: includeCode.toString(),
514
517
  max_code_lines: maxCodeLines.toString(),
515
- hybrid: hybrid.toString(),
518
+ mode: mode,
516
519
  });
520
+ if (compact) apiParams.set('compact', 'true');
517
521
  if (role) apiParams.set('role', role);
518
522
  if (nodeType) apiParams.set('type', nodeType);
519
523
  if (filePattern) apiParams.set('file_pattern', filePattern);
@@ -521,16 +525,35 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
521
525
  const rawResults = await callZntApi(`/api/search?${apiParams.toString()}`);
522
526
  let processed = Array.isArray(rawResults) ? rawResults.map(item => {
523
527
  const relFile = toRelativePath(item.file || item.file_path || item.filePath);
528
+ let codeSnippet = item.code;
529
+ if (includeCode && !codeSnippet && relFile && item.start_line && item.end_line) {
530
+ let endLine = item.end_line;
531
+ if (maxCodeLines > 0 && (endLine - item.start_line + 1) > maxCodeLines) {
532
+ endLine = item.start_line + maxCodeLines - 1;
533
+ }
534
+ codeSnippet = getSourceSnippet(relFile, item.start_line, endLine);
535
+ }
536
+
537
+ if (compact) {
538
+ return {
539
+ name: item.name,
540
+ file: relFile,
541
+ start_line: item.start_line,
542
+ end_line: item.end_line,
543
+ summary: item.summary,
544
+ role: item.role,
545
+ type: item.type,
546
+ score: item.score,
547
+ ...(codeSnippet ? { code: codeSnippet } : {})
548
+ };
549
+ }
550
+
524
551
  const resItem = {
525
552
  ...item,
526
553
  file: relFile
527
554
  };
528
- if (includeCode && !resItem.code && resItem.file && resItem.start_line && resItem.end_line) {
529
- let endLine = resItem.end_line;
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);
555
+ if (codeSnippet) {
556
+ resItem.code = codeSnippet;
534
557
  }
535
558
  return resItem;
536
559
  }) : rawResults;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@znt/mcp",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Model Context Protocol adapter for Znt",
5
5
  "main": "index.js",
6
6
  "type": "module",