@znt/mcp 1.1.0 → 2.0.1

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.
@@ -0,0 +1,50 @@
1
+ # Recommended Znt MCP workflow
2
+
3
+ Этот фрагмент можно адаптировать для инструкций AI-агента проекта.
4
+
5
+ ## Выбор инструмента
6
+
7
+ 1. В начале работы вызови `setup` без параметров. Покажи пользователю
8
+ доступные режимы и не выбирай провайдера или передачу данных внешнему API
9
+ без его решения. После настройки проверь `setup_status`.
10
+ 2. Затем вызови `status`, при необходимости передав
11
+ абсолютный `project_path` открытого workspace. Если
12
+ `is_current_project=false`, вызови `scan` с тем же путём,
13
+ затем проверяй status до завершения scan. Если daemon уже индексирует
14
+ родительский каталог, вложенный workspace получает `coverage=ancestor` и
15
+ повторно не сканируется.
16
+ 3. Точный символ, функция, класс, CamelCase или snake_case:
17
+ `search` с `mode: "lexical"`.
18
+ 4. Описание поведения или архитектурного назначения:
19
+ `search` с `mode: "hybrid"` и подходящим boost/filter.
20
+ 5. Аналог существующей реализации:
21
+ `similar`.
22
+ 6. Call/dependency graph или путь между символами:
23
+ `graph`.
24
+ 7. Структура известного файла:
25
+ `outline` до чтения файла целиком.
26
+ 8. Ошибки scan/index/daemon:
27
+ `logs`.
28
+
29
+ ## Проверка результата
30
+
31
+ - Graph edges и semantic roles являются сильными подсказками, но критические
32
+ выводы нужно сверять с исходным кодом.
33
+ - Пустые callers/callees не доказывают отсутствие вызовов: запросите subgraph.
34
+ - При ambiguous symbol повторите запрос с квалифицированным именем кандидата.
35
+ - Для exhaustive или regex-поиска используйте локальный `rg` после Znt.
36
+ - Не смешивайте точный code token и длинное смысловое описание в одном hybrid
37
+ query; разделите exact lexical и behavioral hybrid запросы.
38
+ - Не используйте HTTP route как graph symbol: сначала найдите handler.
39
+
40
+ ## Пример последовательности
41
+
42
+ ```text
43
+ 1. setup и подтверждение выбранного пользователем режима
44
+ 2. project status и при необходимости scan current project
45
+ 3. lexical search по имени entrypoint
46
+ 4. file outline файла entrypoint
47
+ 5. subgraph от найденного qualified name
48
+ 6. hybrid search по недостающему поведению
49
+ 7. проверка ключевых мест по исходникам
50
+ ```
package/README.md CHANGED
@@ -1,140 +1,509 @@
1
- # Znt MCP Adapter ([@znt/mcp](https://www.npmjs.com/package/@znt/mcp))
1
+ # @znt/mcp
2
+
3
+ Локальный Model Context Protocol server для Znt. Он публикует инструменты
4
+ поиска и анализа кода через MCP stdio и вызывает `znt-core` напрямую через
5
+ `znt-sdk-nodejs`.
6
+
7
+ ```text
8
+ AI client / IDE
9
+ │ MCP over stdio
10
+
11
+ znt-mcp-server (Node.js)
12
+ │ znt-sdk-nodejs
13
+ │ JSON-RPC 2.0 over Unix socket / Windows named pipe
14
+
15
+ znt-core daemon
16
+
17
+
18
+ indexed workspace
19
+ ```
2
20
 
3
- Официальный адаптер **Model Context Protocol (MCP)** для системы локального понимания кодовых баз и графового анализа **[Знаток (Znt)](https://github.com/boottaa/znt)**.
21
+ Новый сервер заменяет прежнюю двойную ретрансляцию:
4
22
 
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)
23
+ ```text
24
+ Было:
25
+ MCP client -> znt_mcp stdio adapter -> HTTP/SSE -> Go MCP engine -> core internals
9
26
 
10
- Позволяет внешним ИИ-агентам и LLM-клиентам (Claude Desktop, Antigravity IDE, Cursor, Windsurf, Zed, Codex и др.) осуществлять гибридный и мультифакторный поиск по смыслу, получать семантические оглавления файлов, строить графы вызовов и трассировать зависимости с прозрачным трекингом экономии контекстных токенов.
27
+ Стало:
28
+ MCP client -> znt-mcp-server stdio -> znt-sdk-nodejs -> znt-core IPC
29
+ ```
11
30
 
12
- ---
31
+ Go-файл `internal/engine/mcp_engine.go` и HTTP-сервер для MCP больше не нужны в
32
+ runtime нового пакета. Источником контракта core является SDK.
33
+
34
+ ## Основные свойства
35
+
36
+ - Node.js 18+;
37
+ - официальный MCP stdio transport;
38
+ - одно переиспользуемое IPC-соединение;
39
+ - Unix socket на Linux/macOS и named pipe на Windows;
40
+ - десять публичных tools: `setup`, `setup_status`, `search`, `similar`, `graph`,
41
+ `outline`, `logs`, `status`, `scan`, `stats`;
42
+ - совместимые имена параметров старого MCP преобразуются в параметры SDK;
43
+ - daemon не запускается до успешного setup;
44
+ - если managed core отсутствует, server устанавливает setup-capable релиз `1.1`;
45
+ - завершение MCP server разрывает только клиентское соединение и не завершает
46
+ общий daemon;
47
+ - RPC/transport ошибки возвращаются как MCP tool result с `isError: true`;
48
+ - поддерживаются MCP cancellation и настраиваемый timeout;
49
+ - локальная статистика использования сохраняется без SQLite-зависимости.
50
+
51
+ ## Требования
52
+
53
+ - Node.js 18 или новее;
54
+ - собранный `../znt-sdk-nodejs`;
55
+ - доступ к GitHub для первой автоматической установки `znt-core`;
56
+ - доступный workspace с исходниками; при необходимости агент может запустить
57
+ его первичное сканирование;
58
+ - embeddings в core для полноценного vector search и `findSimilar()`.
59
+
60
+ MCP server не публикует download/remove. Агент может передать существующий
61
+ каталог через `project_path`; если путь не задан, используется workspace самого
62
+ MCP-процесса. Повторный scan вложенного каталога не запускается, когда его уже
63
+ покрывает индекс родительского каталога. Для интерактивного управления анализом
64
+ и мониторингом можно использовать `znt-ui-dashboard`.
65
+
66
+ ## Установка
67
+
68
+ Сначала соберите локальный SDK:
69
+
70
+ ```bash
71
+ cd znt-sdk-nodejs
72
+ npm install
73
+ npm run build
74
+ ```
13
75
 
14
- ## Быстрый старт (npx)
76
+ Затем установите зависимости MCP server:
77
+
78
+ ```bash
79
+ cd ../znt-mcp-server
80
+ npm install
81
+ ```
82
+
83
+ ## Запуск
84
+
85
+ В каталоге пакета:
86
+
87
+ ```bash
88
+ npm start
89
+ ```
15
90
 
16
- Не требуется предварительная сборка или ручная установка. Для подключения добавьте адаптер в ваш конфигурационный файл MCP (например, `~/.gemini/config/mcp_config.json`, `.cursor/mcp.json` или `claude_desktop_config.json`):
91
+ Из корня monorepo:
92
+
93
+ ```bash
94
+ npm run mcp
95
+ ```
96
+
97
+ При обычном запуске server использует stdio для MCP-протокола. Нельзя писать
98
+ диагностические сообщения в stdout: он зарезервирован для JSON-RPC. Ошибки
99
+ bootstrap выводятся в stderr.
100
+
101
+ ## Подключение MCP-клиента
102
+
103
+ Обобщённая конфигурация для клиента, поддерживающего локальные stdio servers:
17
104
 
18
105
  ```json
19
106
  {
20
107
  "mcpServers": {
21
- "znt-mcp": {
108
+ "znt": {
109
+ "command": "node",
110
+ "args": [
111
+ "/absolute/path/to/Znt/znt-mcp-server/index.js"
112
+ ],
113
+ "env": {
114
+ "ZNT_PROJECT_ROOT": "/absolute/path/to/project"
115
+ }
116
+ }
117
+ }
118
+ }
119
+ ```
120
+
121
+ Для опубликованного npm-пакета вместо полного пути можно будет использовать
122
+ `npx`:
123
+
124
+ ```json
125
+ {
126
+ "mcpServers": {
127
+ "znt": {
22
128
  "command": "npx",
23
129
  "args": ["-y", "@znt/mcp"],
24
130
  "env": {
25
- "ZNT_API_URL": "http://localhost:8080"
131
+ "ZNT_PROJECT_ROOT": "/absolute/path/to/project"
26
132
  }
27
133
  }
28
134
  }
29
135
  }
30
136
  ```
31
137
 
32
- ---
138
+ При глобальной установке доступна bin-команда `znt-mcp`.
139
+
140
+ ## Жизненный цикл core
141
+
142
+ При bootstrap server не запускает daemon и не сканирует проект:
143
+
144
+ 1. `setup_status` проверяет наличие бинарника и YAML.
145
+ 2. `setup` при необходимости устанавливает Core и получает встроенные YAML-дефолты.
146
+ 3. MCP сохраняет выбранный `config.yaml` рядом с управляемым бинарником.
147
+ 4. После валидации первый рабочий tool запускает daemon с этим конфигом.
148
+ 5. `scan` до успешного setup возвращает `setup_required`.
149
+
150
+ SDK скачивает бинарник только из официальных GitHub Releases `znt-app/core` и
151
+ проверяет SHA-256 из release manifest. Стандартные каталоги:
152
+
153
+ | Платформа | Каталог |
154
+ |---|---|
155
+ | Linux | `$XDG_DATA_HOME/znt/bin` или `~/.local/share/znt/bin` |
156
+ | macOS | `~/Library/Application Support/Znt/bin` |
157
+ | Windows | `%LOCALAPPDATA%\\Znt\\bin` |
158
+
159
+ Рабочий YAML находится в этом же каталоге под именем `config.yaml`. Явный
160
+ `ZNT_CONFIG` имеет приоритет и считается внешним: MCP проверяет, но не
161
+ перезаписывает его.
162
+
163
+ При остановке MCP server вызывается только `client.disconnect()`. Это важно,
164
+ потому что один daemon может одновременно использоваться Dashboard и другими
165
+ SDK-клиентами.
166
+
167
+ ## Переменные окружения
168
+
169
+ | Переменная | Назначение |
170
+ |---|---|
171
+ | `ZNT_ENDPOINT` | Unix socket или Windows named pipe |
172
+ | `ZNT_CORE_HOME` | Пользовательский каталог установки core |
173
+ | `ZNT_CORE_BINARY` | Полный путь к development-бинарнику |
174
+ | `ZNT_CONFIG` | Конфигурация, передаваемая при запуске daemon |
175
+ | `ZNT_CORE_CWD` | Рабочий каталог запускаемого daemon |
176
+ | `ZNT_RUNTIME_DIR` | Runtime-файлы core |
177
+ | `ZNT_PROJECT_ROOT` | Текущий проект MCP; по умолчанию `process.cwd()` |
178
+ | `ZNT_MCP_REQUEST_TIMEOUT_MS` | Timeout одного SDK-вызова, по умолчанию 30000 ms |
179
+ | `ZNT_MCP_METRICS_FILE` | Путь к JSONL-файлу MCP metrics |
180
+
181
+ Если `ZNT_ENDPOINT` не задан, SDK использует:
182
+
183
+ - Linux/macOS: `~/.znt/znt.sock`;
184
+ - Windows: `\\.\pipe\znt-core`.
185
+
186
+ `ZNT_PROJECT_ROOT` задаёт проект по умолчанию для IDE, которая запускает MCP
187
+ server не из корня открытого проекта. `status` и
188
+ `scan` также принимают необязательный `project_path`: абсолютный
189
+ путь либо путь относительно `ZNT_PROJECT_ROOT`. Приоритет выбора:
190
+ `project_path` → `ZNT_PROJECT_ROOT` → `cwd`.
191
+
192
+ ## Tools
193
+
194
+ ### `setup`
195
+
196
+ Без параметров возвращает состояние и рекомендации: BM25, Ollama или
197
+ OpenAI-compatible provider. С выбранным `mode` создаёт и проверяет managed
198
+ `config.yaml`. API-ключ запрещено передавать аргументом tool.
199
+
200
+ Для keyring MCP возвращает одноразовый loopback `setup_url`: пользователь
201
+ вводит ключ напрямую в локальную форму, после чего Core сохраняет его в
202
+ Windows Credential Manager, macOS Keychain или Linux Secret Service. В YAML
203
+ остаётся только `token_ref`.
204
+
205
+ ### `setup_status`
206
+
207
+ Проверяет Core, YAML и credential. С `check_provider: true` дополнительно
208
+ проверяет endpoint и настроенные модели. Значение секрета не возвращается.
209
+
210
+ ### `search`
211
+
212
+ Ищет компоненты в semantic index.
213
+
214
+ | Параметр | Тип | По умолчанию | Описание |
215
+ |---|---|---:|---|
216
+ | `query` | string | обязателен | Имя символа или описание поведения |
217
+ | `mode` | enum | `hybrid` | `lexical`, `vector`, `hybrid` |
218
+ | `limit` | integer | `10` | Количество результатов |
219
+ | `callers_level` | integer | `0` | Глубина входящих связей |
220
+ | `callees_level` | integer | `0` | Глубина исходящих связей |
221
+ | `compact` | boolean | `false` | Исключить граф связей |
222
+ | `include_code` | boolean | `false` | Включить тело AST-узла |
223
+ | `max_code_lines` | integer | `30` | Максимум строк кода |
224
+ | `role_boost` | string | — | Мягкий boost роли |
225
+ | `type_boost` | string | — | Мягкий boost AST-типа |
226
+ | `file_pattern` | string | — | Фильтр пути |
227
+
228
+ Старые имена `role_boost`, `type_boost`, `file_pattern` преобразуются в SDK
229
+ поля `role`, `type`, `file_path`.
230
+
231
+ Примеры:
232
+
233
+ ```json
234
+ {
235
+ "query": "SemanticService.SearchWithOptions",
236
+ "mode": "lexical",
237
+ "type_boost": "function",
238
+ "include_code": true
239
+ }
240
+ ```
241
+
242
+ ```json
243
+ {
244
+ "query": "как строится индекс после сканирования",
245
+ "mode": "hybrid",
246
+ "role_boost": "service",
247
+ "limit": 10
248
+ }
249
+ ```
250
+
251
+ Практика выбора режима:
252
+
253
+ - точный CamelCase/snake_case идентификатор — `lexical`;
254
+ - поведение или архитектурный смысл — `hybrid`;
255
+ - гипотетическое имя или чистая семантическая близость — `vector`.
256
+
257
+ ### `similar`
258
+
259
+ Ищет аналоги и возможные дубликаты. Требуется хотя бы один параметр `target`
260
+ или `query`.
261
+
262
+ ```json
263
+ {
264
+ "target": "SemanticService.SearchWithOptions",
265
+ "limit": 10,
266
+ "edge_types": "call,implements",
267
+ "include_code": true
268
+ }
269
+ ```
270
+
271
+ Дополнительные параметры: `role_boost`, `type_boost`, `file_pattern`,
272
+ `max_code_lines`. Инструмент зависит от embeddings; пустой результат без
273
+ embedding не означает, что lexical symbol отсутствует.
33
274
 
34
- ## 🛠 Доступные инструменты (MCP Tools)
275
+ ### `graph`
35
276
 
36
- Адаптер предоставляет 6 специализированных инструментов с автоматическим отслеживанием экономии контекста:
277
+ Поддерживает локальный BFS-граф и трассировку пути.
37
278
 
38
- ### 1. `znatok_semantic_search`
39
- * **Назначение**: Семантический и гибридный поиск (BM25 + Векторы + RRF) по элементам кодовой базы.
40
- * **Параметры**:
41
- * `query` *(string, обязательный)*: Поисковый запрос на естественном языке.
42
- * `limit` *(number)*: Максимальное число результатов (по умолчанию `10`, макс `100`).
43
- * `callers_level` *(number)*: Глубина графа входящих вызовов (по умолчанию `3`).
44
- * `callees_level` *(number)*: Глубина графа исходящих вызовов (по умолчанию `3`).
45
- * `include_code` *(boolean)*: Включать ли фрагменты исходного кода узлов.
46
- * `max_code_lines` *(number)*: Максимум строк кода на узел (по умолчанию `30`).
47
- * `role` *(string)*: Фильтр по архитектурной роли (`"controller"`, `"service"`, `"repository"`, `"model"`).
48
- * `type` *(string)*: Фильтр по типу узла AST (`"function"`, `"struct"`, `"class"`, `"interface"`).
49
- * `file_pattern` *(string)*: Маска пути файла (например `"pkg/semantic/*"` или `"*.go"`).
50
- * `mode` *(string)*: Режим поиска: `"hybrid"` (RRF гибридный), `"lexical"` (точный BM25/FTS5), `"vector"` (чисто векторный). По умолчанию `"hybrid"`.
279
+ Локальное окружение:
51
280
 
52
- ---
281
+ ```json
282
+ {
283
+ "from": "SemanticService.SearchWithOptions",
284
+ "depth": 2,
285
+ "edge_types": "call,implements,inherits",
286
+ "format": "text"
287
+ }
288
+ ```
53
289
 
54
- ### 2. `znatok_find_similar`
55
- * **Назначение**: Умный мультифакторный поиск аналогов и дубликатов кода (60% векторный косинус + 30% граф вызовов Jaccard + 10% AST-роли).
56
- * **Параметры**:
57
- * `target` *(string)*: Имя символа, функции или класса в проекте (например `"Server.runFullScan"`). При указании вектор берется из БД напрямую **без обращения к LLM**.
58
- * `query` *(string)*: Текстовое описание или код для поиска аналогов (используется, если `target` не задан).
59
- * `limit` *(number)*: Максимальное число результатов (по умолчанию `10`).
60
- * `callers_level` / `callees_level` *(number)*: Глубина связанных вызовов (по умолчанию `3`).
61
- * `include_code` *(boolean)* / `max_code_lines` *(number)*: Параметры включения кода (по умолчанию `30` строк).
62
- * `role` / `type` / `file_pattern` *(string)*: Фильтры по архитектуре и путям файлов.
290
+ Трассировка:
63
291
 
64
- ---
292
+ ```json
293
+ {
294
+ "from": "Server.ExecuteSearch",
295
+ "to": "SemanticStore.SearchFTS5",
296
+ "depth": 2,
297
+ "format": "mermaid"
298
+ }
299
+ ```
65
300
 
66
- ### 3. `znatok_get_subgraph`
67
- * **Назначение**: Построение подграфа окрестностей символа/файла или трассировка вызовов от точки `from` к точке `to`.
68
- * **Параметры**:
69
- * `target` *(string)*: Символ или относительный путь файла для вывода его окрестностей.
70
- * `from` / `to` *(string)*: Точки трассировки цепочки вызовов (DFS по графу).
71
- * `depth` *(number)*: Глубина обхода подграфа (по умолчанию `2`).
72
- * `max_nodes` *(number)*: Максимальное количество узлов подграфа (по умолчанию `30`).
73
- * `format` *(string)*: Формат ответа (`"mermaid"` для Markdown-диаграмм или `"json"`, по умолчанию `"mermaid"`).
301
+ Допустимые `edge_types`: `contains`, `call`, `inherits`, `implements`.
302
+ Допустимые форматы: `text`, `json`, `mermaid`. Для неоднозначного короткого
303
+ имени core возвращает кандидатов; повторите запрос с квалифицированным `name`.
74
304
 
75
- ---
305
+ ### `outline`
76
306
 
77
- ### 4. `znatok_file_outline`
78
- * **Назначение**: Анатомический семантический атлас (оглавление) файла за 1 запрос без замусоривания контекста.
79
- * **Параметры**:
80
- * `path` *(string, обязательный)*: Путь к целевому файлу (например `"internal/engine/server.go"`).
81
- * `include_code` *(boolean)*: Включать ли фрагменты исходного кода для каждого символа.
307
+ Возвращает полное top-level оглавление проиндексированного файла:
82
308
 
83
- ---
309
+ ```json
310
+ {
311
+ "path": "internal/engine/queries.go",
312
+ "include_code": true
313
+ }
314
+ ```
84
315
 
85
- ### 5. `znatok_server_logs`
86
- * **Назначение**: Чтение системных логов и событий сервера Znt в реальном времени через WebSocket.
87
- * **Параметры**: Отсутствуют.
316
+ MCP сохраняет старое имя параметра `path`, затем преобразует его в SDK
317
+ `file_path`. Используйте outline перед чтением большого файла.
88
318
 
89
- ---
319
+ ### `logs`
90
320
 
91
- ### 6. `znatok_mcp_stats`
92
- * **Назначение**: Детальная метрика работы MCP-сервера и статистика сэкономленных токенов из SQLite.
93
- * **Параметры**: Отсутствуют.
321
+ Без параметров возвращает текущий snapshot кольцевого буфера core:
94
322
 
95
- ---
323
+ ```json
324
+ {}
325
+ ```
96
326
 
97
- ## 📊 Структура ответа и трекинг контекста (`_meta`)
327
+ Для следующего delta-запроса передайте оба значения из ответа:
98
328
 
99
- Каждый инструмент возвращает обёртку со служебным объектом `_meta`:
329
+ ```json
330
+ {
331
+ "stream_id": "stream_1234_...",
332
+ "after_id": 42
333
+ }
334
+ ```
335
+
336
+ Если continuity потеряна, core возвращает `truncated: true` и полный доступный
337
+ snapshot.
338
+
339
+ ### `status`
340
+
341
+ Проверяет, совпадает ли текущий MCP workspace с проектом, загруженным в daemon:
342
+
343
+ ```json
344
+ {
345
+ "project_path": "/workspace/current"
346
+ }
347
+ ```
348
+
349
+ `project_path` необязателен. Каталог должен существовать. Символические ссылки
350
+ разворачиваются через `realpath`.
351
+
352
+ Источник истины — `status().project_root`. `info()` содержит версию,
353
+ capabilities, конфигурацию и языки, но не содержит активный project root.
354
+
355
+ Ответ включает:
100
356
 
101
357
  ```json
102
358
  {
103
- "_meta": {
104
- "tool": "znatok_semantic_search",
105
- "response_tokens": 420,
106
- "execution_ms": 15,
107
- "last_call_saved_tokens": 12500,
108
- "session_saved_tokens": 34000,
109
- "alternative_cost": {
110
- "tokens": 12920,
111
- "description": "объем 3 затрагиваемых файлов целиком",
112
- "savings_ratio": "30.8x"
113
- },
114
- "data_sources": ["core_api:search"]
359
+ "current_project": "/workspace/current",
360
+ "daemon_project": "/workspace/loaded",
361
+ "is_current_project": false,
362
+ "is_exact_project": false,
363
+ "coverage": "none",
364
+ "daemon_status": "Monitoring",
365
+ "has_index": false,
366
+ "stats": {
367
+ "files": 76,
368
+ "declarations": 249,
369
+ "functions": 75,
370
+ "members": 111,
371
+ "dependencies": 336,
372
+ "edges": 495
115
373
  },
116
- "result": [ ... ]
374
+ "scan": {}
117
375
  }
118
376
  ```
119
377
 
120
- ---
378
+ `coverage` принимает `exact`, `ancestor` или `none`. Если daemon индексирует
379
+ `/workspace`, запрос для `/workspace/src/features` получает `ancestor` и
380
+ считается покрытым существующим индексом. `stats` относятся к `daemon_project`.
381
+ `has_index` становится true, когда запрошенный путь покрыт индексом и daemon
382
+ сообщает ненулевое количество файлов.
383
+
384
+ ### `scan`
121
385
 
122
- ## ⚙️ Переменные окружения
386
+ Безопасно переключает daemon на текущий MCP workspace:
387
+
388
+ ```json
389
+ {
390
+ "project_path": "/workspace/current",
391
+ "language": "auto"
392
+ }
393
+ ```
394
+
395
+ `project_path` необязателен и разрешает агенту явно указать открытый проект.
396
+ Относительные значения вычисляются от `ZNT_PROJECT_ROOT`.
397
+
398
+ Алгоритм:
399
+
400
+ 1. получает `status().project_root`;
401
+ 2. проверяет и канонизирует выбранный каталог через `realpath`;
402
+ 3. если daemon индексирует этот каталог либо его родителя, возвращает
403
+ `started: false` (`already_current_project` или `already_covered`);
404
+ 4. если другой scan уже выполняется, возвращает `scan_in_progress` и не
405
+ переключает daemon;
406
+ 5. иначе вызывает SDK `scan()` для выбранного каталога;
407
+ 6. всегда передаёт `restart: false`, сохраняя существующий `.znt` индекс;
408
+ 7. немедленно возвращает `scan_id`; прогресс проверяется через
409
+ `status`.
410
+
411
+ Если daemon прямо сейчас сканирует другой проект, core может вернуть `Busy`.
412
+ Нужно дождаться терминального scan status и повторить вызов.
413
+
414
+ ### `stats`
415
+
416
+ Возвращает session/total calls, приблизительный объём ответа, оценку экономии,
417
+ среднее время, top tools и последние вызовы.
418
+
419
+ ```json
420
+ {}
421
+ ```
422
+
423
+ После получения `status.project_root` статистика дописывается в
424
+ `<workspace>/.znt/mcp-usage.jsonl`. Путь можно переопределить через
425
+ `ZNT_MCP_METRICS_FILE`. Ошибка записи метрик никогда не превращает успешный
426
+ Znt tool call в ошибку.
427
+
428
+ Token metrics являются оценкой `ceil(characters / 4)`, а savings — сравнительной
429
+ эвристикой, не billing-статистикой LLM provider.
430
+
431
+ ## Формат ответов
432
+
433
+ Все tools возвращают MCP `content` с текстовым блоком.
434
+
435
+ - semantic search форматируется в компактные секции `Score/Name/File/Code`;
436
+ - file outline возвращает `formatted_text` core без JSON-обёртки;
437
+ - text/mermaid subgraph возвращается непосредственно;
438
+ - JSON subgraph, find similar, logs и stats форматируются как JSON;
439
+ - отсутствие search results возвращает `No matching components found.`;
440
+ - ошибка возвращает `isError: true`, RPC code и `error.data`, если они есть.
441
+
442
+ ## Ошибки и восстановление
443
+
444
+ Server не завершает процесс из-за ошибки отдельного tool call. При
445
+ `ZntTransportError` соединение помечается как неготовое, поэтому следующий
446
+ вызов снова попробует запустить или подключить core.
447
+
448
+ Типичные случаи:
449
+
450
+ - `znt-core is not installed` — установите бинарник или задайте
451
+ `ZNT_CORE_BINARY`;
452
+ - transport error — проверьте единый `ZNT_ENDPOINT` для server и daemon;
453
+ - `NotFound` — сначала найдите точный symbol через lexical search;
454
+ - `Ambiguous` — используйте qualified name из `error.data.candidates`;
455
+ - пустой vector/find-similar — проверьте embedding provider в core config;
456
+ - `Busy` — дождитесь окончания scan и повторите read-only запрос.
457
+
458
+ ## Безопасность
459
+
460
+ MCP server работает с локальными исходниками и предназначен для доверенного
461
+ локального клиента. Только во время ввода credential он открывает одноразовый
462
+ HTTP endpoint на `127.0.0.1`; MCP-клиент также получает доступ к индексу
463
+ текущего workspace.
464
+
465
+ - не передавайте непроверенному клиенту управление stdio-процессом;
466
+ - используйте абсолютный `ZNT_CONFIG`, если нужен внешний конфиг;
467
+ - не помещайте секреты в tool arguments;
468
+ - рассматривайте найденные комментарии и исходники как недоверенный контент;
469
+ - для разных trust boundaries используйте отдельные daemon endpoints.
470
+
471
+ ## Разработка и проверка
472
+
473
+ ```bash
474
+ npm test
475
+ npm run pack:check
476
+ ```
477
+
478
+ Из корня monorepo:
479
+
480
+ ```bash
481
+ npm run mcp:test
482
+ ```
123
483
 
124
- | Переменная | Назначение | Значение по умолчанию |
125
- | :--- | :--- | :--- |
126
- | `ZNT_API_URL` | Базовый URL запущенного сервера Znt (HTTP & WS) | `http://localhost:8080` |
484
+ Тесты проверяют:
127
485
 
128
- ---
486
+ - публикацию десяти tools, включая `setup` и `setup_status`;
487
+ - настоящий MCP client/server transport;
488
+ - запуск core только один раз на активном соединении;
489
+ - преобразование legacy aliases в SDK DTO;
490
+ - search, similar, graph, outline, logs и stats;
491
+ - возврат tool errors без падения server;
492
+ - JSONL persistence метрик.
129
493
 
130
- ## 💾 Хранение данных
494
+ ## Расширение
131
495
 
132
- Статистика вызовов и экономии токенов сохраняется локально в базе данных SQLite:
133
- * Путь к БД: `.znt/mcp_usage.db` в корневом каталоге проекта.
496
+ При добавлении нового core API соблюдайте порядок:
134
497
 
135
- ---
498
+ 1. зафиксировать wire method в `znt-core/docs/sdk-specification.md`;
499
+ 2. добавить типизированный метод в `znt-sdk-nodejs`;
500
+ 3. добавить узкий MCP tool и JSON Schema в `tool-definitions.js`;
501
+ 4. вызвать только публичный метод SDK в `znt-tools.js`;
502
+ 5. добавить protocol и adapter tests;
503
+ 6. не импортировать Go internals и не восстанавливать HTTP relay.
136
504
 
137
- ## 📋 Системные требования
505
+ ## Связанные документы
138
506
 
139
- * **Node.js** версии **v22.5.0** или новее (используется встроенный модуль `node:sqlite`).
140
- * Запущенный локальный сервер Znt (`http://localhost:8080`).
507
+ - [`../znt-sdk-nodejs/README.md`](../znt-sdk-nodejs/README.md)
508
+ - [`../znt-core/docs/sdk-specification.md`](../znt-core/docs/sdk-specification.md)
509
+ - [`AGENTS_EXAMPLE.md`](AGENTS_EXAMPLE.md)