bit-1c-help
# MCP со справкой по платформе 1С
Локальный MCP-сервер для поиска по справке платформы 1С. Сервер не содержит саму справку: положите локальную выгрузку документации в `kb/` или укажите путь через `BIT_1C_HELP_ROOT`.
Поддерживаемые форматы для индексации: `.md`, `.mdx`, `.txt`, `.html`, `.htm`, `.xml`, `.bsl`.
## Запуск
У сервера два входа с одним и тем же набором инструментов: локальный (stdio) и сетевой (HTTP).
Отвечают они одинаково — это проверяется дифференциальным прогоном `npm run test:diff-entries`.
### Локальный вход (stdio)
Так сервер запускают MCP-клиенты на машине разработчика:
```powershell
npm run start
```
### Сетевой вход (HTTP)
Обслуживает `POST /mcp` по протоколу streamable HTTP без сессий:
```powershell
$env:MCP_PORT = "8770"; node .\src\entry\http.js
```
Вход слушает только `127.0.0.1` — это не настраивается. Наружу сервис выставляет nginx площадки,
и он же отвечает за TLS и доступ.
Переменные окружения:
| Переменная | Обязательна | Назначение |
| --- | --- | --- |
| `MCP_PORT` | да | Порт на `127.0.0.1`. Значения по умолчанию нет намеренно: занятый «стандартный» порт молча увёл бы запросы чужому процессу. |
| `MCP_ALLOWED_ORIGINS` | нет | Разрешённые значения заголовка `Origin`, через запятую. По умолчанию пусто. |
| `MCP_ALLOWED_HOSTS` | нет | Дополнительные разрешённые значения заголовка `Host`, через запятую. |
| `MCP_ALLOW_EPHEMERAL_PORT` | нет | `1` разрешает `MCP_PORT=0`. Нужно тестам; в бою служба поднялась бы на случайном порту, и nginx стучался бы в никуда. |
| `MCP_SERVICE_NAME` | нет | Имя жильца площадки; попадает в поле `service` ответа `/health`. |
Переменные справки (`BIT_1C_HELP_ROOT`, `BIT_1C_HELP_INDEX_ROOT`, `BIT_1C_HELP_LOG_PATH`) работают
одинаково на обоих входах. Кроме них:
| Переменная | Назначение |
| --- | --- |
| `BIT_1C_HELP_INDEX_CACHE_LIMIT` | Сколько индексов держать в памяти процесса одновременно, по умолчанию 3. Корневой индекс закреплён прогревом и не вытесняется. |
| `BIT_1C_HELP_BUILD_INFO_PATH` | Другой путь к `BUILD-INFO.json`. Нужно тестам боевой ветки `/health`. |
| `BIT_1C_HELP_MAX_FILE_BYTES` | Предел размера индексируемого файла, по умолчанию 2 000 000. |
### Состояние службы: `/health` и `/status`
У сетевого входа, кроме `/mcp`, есть два маршрута только на чтение. Оба проходят те же проверки
`Host` и `Origin`, что и `/mcp`, — исключений нет ни для одного из них.
`GET /health` — машиночитаемое состояние, оно же критерий приёмки выкладки:
```json
{
"status": "ok",
"service": "bit-1c-help",
"product": "bit-1c-help",
"version": "0.5.0",
"gitCommit": "f4b4b669e33b11afbf6725268989de7b5626aa91",
"docsVersion": "2026-08-21",
"protocolVersions": ["2025-11-25", "2025-06-18", "2025-03-26"],
"sources": [{ "source": "Platform/8.3.27.1989", "documents": 25541 }],
"index": { "state": "ready", "documents": 81204, "builtAt": "2026-08-21T01:12:27.482Z" },
"uptimeSec": 6,
"problems": []
}
```
- `version` и `gitCommit` берутся из `BUILD-INFO.json`, который кладёт в каталог версии сборочный
скрипт. Каталог кода на сервере не git-репозиторий, определить коммит на месте нечем — его
приносят с собой. В клоне разработчика этого файла нет: тогда версия берётся из `package.json`,
а коммит — из `.git`.
- `docsVersion` — содержимое `KB-VERSION.txt` в корне справки, его пишет сборщик артефакта справки.
- `sources[].documents` — число файлов во всём поддереве раздела.
- `index.state` — `ready`, `warming` или `building`, см. ниже.
- `problems` — причины, по которым `status` стал `degraded`. Абсолютных путей в них нет намеренно:
путь выкладки может выдать наружу имя учётной записи, поэтому подробности с путями уходят
только в локальный журнал.
Служба не падает ни при какой беде со справкой или индексом: она поднимается и отвечает
`degraded` со списком причин. Падение недопустимо — диспетчер служб перезапускал бы процесс по
кругу, и в журнале оказалась бы каша вместо диагноза.
**Три состояния индекса.**
| `index.state` | Что значит |
| --- | --- |
| `ready` | Индекс лежит в памяти процесса, поиск ответит сразу. |
| `warming` | Снимок индекса на диске исправен, но в память ещё не поднят: идёт прогрев после запуска. Запрос, пришедший сейчас, дождётся конца загрузки. |
| `building` | Пригодного снимка нет вовсе: индекс надо построить командой `npm run build:index`. |
Прогрев запускают оба входа сразу после старта, в фоне, и обслуживанию он не мешает. На реальном
корпусе (294 МБ, 53 588 файлов, 81 204 раздела) `/health` начинает отвечать через ~1.8 с после
запуска процесса, а `ready` наступает через ~6 с. **Скрипт выкладки обязан опрашивать `/health`
до готовности, а не один раз сразу после запуска службы:** пока идёт прогрев, `status` честно
равен `degraded`.
`GET /status` — та же картина для человека в браузере плюс статистика поиска из журнала: доля
запросов без результатов, частые запросы, задержки p50/p95, распределение по источникам. Страница
показывает, **по каким запросам справка не находится**, то есть какой источник пора добавить.
Ничем не управляет и ничего не меняет.
Оба маршрута дёшевы намеренно: `/health` смотрит только в память процесса и в маленький файл
агрегатов рядом со снимком индекса, `/status` читает ограниченный хвост журнала и запоминает
разбор по времени изменения файла. Разворачивать снимок индекса в обработчике запроса нельзя —
на реальном корпусе это 4.2 с и 2.4 ГБ памяти на один опрос.
#### Кого не пускает сетевой вход
Сервис доступен по сети внутри машины, поэтому до него может дотянуться страница, открытая в
браузере сотрудника. От этого стоят две проверки, и по отдельности ни одна не работает:
- **`Origin`.** Запрос без этого заголовка проходит: его не шлют ни `curl`, ни клиенты MCP. Если
заголовок есть — значит, запрос отправил браузер, и значение обязано быть в
`MCP_ALLOWED_ORIGINS`. Список пуст по умолчанию, то есть браузерные запросы не проходят вовсе.
- **`Host`.** При перепривязке DNS страница на чужом домене, чьё имя перепривязано на `127.0.0.1`,
шлёт запрос как одноисточниковый — заголовка `Origin` в нём нет, и первая проверка его
пропускает. Отличает такой запрос `Host`: там имя атакующего. Поэтому `Host` обязан быть
`127.0.0.1`, `localhost` (с портом или без) или тем, что перечислено в `MCP_ALLOWED_HOSTS`.
`MCP_ALLOWED_HOSTS` нужен, когда nginx площадки передаёт наверх исходный `Host` клиента
(`proxy_set_header Host $host`), а не адрес upstream: тогда до сервиса доходит публичное имя, и его
надо разрешить явно. Если nginx оставляет `Host` от upstream, переменная не нужна.
Значения `MCP_ALLOWED_ORIGINS` приводятся к виду, в котором источник шлёт браузер: схема, хост и
порт, без пути и завершающего слэша. Запись, на источник не похожую, вход отвергает при запуске с
объяснением, а не молча отвечает `403` на каждый запрос. То же самое — с `MCP_ALLOWED_HOSTS`:
сравнение с заголовком `Host` идёт точным совпадением, а не шаблоном, поэтому, например, `*` по
привычке из настроек CORS не сработает вовсе, и такую запись вход тоже отвергает при запуске.
**Внесение источника в `MCP_ALLOWED_ORIGINS` снимает нашу защиту, но браузерный клиент от этого не
заработает.** Заголовков `Access-Control-Allow-*` сервис не отдаёт и предварительные запросы
`OPTIONS` не обрабатывает, поэтому браузер отправит запрос, а прочитать ответ не даст. Чтобы
браузерный клиент работал, CORS нужно настраивать отдельно — на nginx площадки либо в самом входе.
## Воспроизводимый запуск на новой машине
1. Установите Node.js 20 или новее.
2. Положите готовый очищенный архив `mcp-docs-*.zip` в проект и распакуйте его так, чтобы появился каталог `kb/`.
3. Если готового архива нет, соберите справку из источников: импортируйте raw HTML в `build/raw`, затем выполните очистку в `kb`.
4. Запустите проверку:
```powershell
npm run smoke
```
5. Запустите MCP-сервер:
```powershell
npm run start
```
Для Codex укажите `BIT_1C_HELP_ROOT` на каталог `kb`. Сырые HTML-исходники держите вне `kb`, например в `build/raw`, иначе MCP будет индексировать шумную HTML-разметку.
Пример восстановления из готовых артефактов:
```powershell
Expand-Archive -Path ".\build\artifacts\mcp-docs-2026-08-04.zip" -DestinationPath "." -Force
Expand-Archive -Path ".\build\artifacts\raw-html-2026-08-04.zip" -DestinationPath "." -Force
```
Первый архив нужен для работы MCP. Второй нужен только как воспроизводимый raw-слой для повторной очистки.
## Как получить локальную справку
Если на машине установлена платформа 1С, в каталоге версии обычно есть индекс синтакс-помощника:
```text
C:\Program Files\1cv8\<версия>\bin\devdocs_ru.bin
```
Импортируйте его в индексируемый Markdown:
```powershell
npm run import:installed
```
Журнал изменений установленной платформы (`docs\\ru\\V8Update.htm`) импортируется
отдельно. Он разбивается на файлы по версиям платформы, чтобы документы не превышали
лимит индексатора:
```powershell
npm run import:platform-updates
```
При необходимости исходный файл и каталог назначения можно указать явно:
```powershell
node .\scripts\import-platform-updates.js "C:\Program Files\1cv8\8.3.27.1989\docs\ru\V8Update.htm" ".\kb\Platform\8.3.27.1989\PlatformUpdates"
```
Или укажите конкретный файл:
```powershell
node .\scripts\import-installed-help.js "C:\Program Files\1cv8\8.3.15.1869\bin\devdocs_ru.bin"
```
Это импортирует оглавление встроенной справки: названия объектов, методов, свойств, областей доступности и `v8help://` URI. Для полного текста статей нужен экспорт/извлечение содержимого страниц справки из поставки платформы или официальный онлайн-источник.
Для платформы 8.3.27.1989 полный текст страниц синтакс-помощника можно извлечь из `shcntx_ru.hbk`:
```powershell
npm run extract:hbk -- "C:\Program Files\1cv8\8.3.27.1989\bin\shcntx_ru.hbk" ".\build\raw\Platform\8.3.27.1989\SyntaxHelperContext"
npm run clean:html-docs -- ".\build\raw\Platform\8.3.27.1989\SyntaxHelperContext" ".\kb\Platform\8.3.27.1989\SyntaxHelperContext"
```
После этого MCP будет индексировать очищенный Markdown из `kb/Platform/8.3.27.1989`.
## Как добавить справку БСП
Документация поставки БСП лежит в каталоге шаблонов конфигураций. По умолчанию это
`%APPDATA%\1C\1cv8\tmplts`; свой путь смотрите в параметре `ConfigurationTemplatesLocation`
файла `1cestart.cfg`. Например:
```text
%APPDATA%\1C\1cv8\tmplts\1c\SSL\3_1_11_353\ExtFiles\docs
```
импортируйте HTML-документацию в небольшие фрагменты:
```powershell
npm run import:ssl-docs -- "$env:APPDATA\1C\1cv8\tmplts\1c\SSL\3_1_11_353\ExtFiles\docs" ".\build\raw\SSL\3_1_11_353"
npm run clean:html-docs -- ".\build\raw\SSL" ".\kb\SSL"
```
Фрагменты будут сохранены как raw HTML в `build/raw/SSL`, затем очищенный Markdown попадет в `kb/SSL` и MCP-поиск.
## Откуда берётся содержимое `kb/`
Репозиторий не содержит и не распространяет документацию — ни справку платформы, ни материалы
ИТС, ни документацию БСП. Всё это принадлежит фирме «1С» и её партнёрам и распространяется по
своим лицензиям. Сервер ищет по тому корпусу, который вы собрали сами из источников, к которым
у вас есть законный доступ: установленная платформа, поставка БСП, ваша подписка ИТС.
Импортёры в `scripts/` работают только с локальными файлами: `.hbk` установленной платформы,
`V8Update.htm` из каталога платформы, HTML-документация из поставки БСП, клоны открытых
репозиториев YAxUnit и Vanessa Automation. Инструментов, выкачивающих контент с сайтов фирмы
«1С», здесь нет намеренно: массовый автоматический обход противоречит условиям использования
ИТС и создаёт лишнюю нагрузку на чужие серверы.
## Очистка HTML в слой для поиска
Сырые HTML-исходники можно сохранить отдельным артефактом:
```powershell
New-Item -ItemType Directory -Force -Path .\build\artifacts
Compress-Archive -Path .\build\raw -DestinationPath .\build\artifacts\raw-html-2026-08-04.zip -CompressionLevel Optimal
```
Этот архив нужен как воспроизводимый raw-слой. Для качества MCP-поиска лучше держать в `kb` очищенный слой: убрать скрипты, стили, навигацию, служебные блоки, сохранить заголовки и основной текст в Markdown или компактный HTML.
Очищенный Markdown-слой для MCP можно построить так:
```powershell
npm run clean:html-docs -- ".\build\raw\SSL" ".\kb\SSL"
npm run clean:html-docs -- ".\build\raw\Platform\8.3.27.1989\SyntaxHelperContext" ".\kb\Platform\8.3.27.1989\SyntaxHelperContext"
```
Конвертер разбирает HTML через DOM, сохраняет source URL, заголовки, anchors,
внутренние ссылки, код и таблицы. Навигация, скрипты, стили и служебная разметка
удаляются. Блоки «Смотри также» помечаются как `[SEE_ALSO]`.
Вместе с Markdown создаётся `IMPORT-MANIFEST.json` со статистикой пустых документов,
дублирующихся URL, повреждённой кодировки, отсутствующих заголовков и слишком больших
файлов. В MCP-каталог `kb` кладите именно очищенный слой.
## Как добавить справку YAxUnit
Если локально есть репозиторий YAxUnit:
```text
<путь к репозиториям>\bia-technologies\yaxunit
```
импортируйте Markdown-документацию и BSL-комментарии API:
```powershell
npm run import:yaxunit-docs -- "<путь к репозиториям>\bia-technologies\yaxunit"
```
Если репозиторий стоит на релизном теге, файлы будут сохранены в каталог версии, например `kb/YAxUnit/25.12`, и попадут в MCP-поиск. Каталог `kb/` игнорируется Git.
## Как добавить справку Vanessa Automation
Официальный репозиторий Vanessa Automation:
```text
https://github.com/Pr-Mex/vanessa-automation.git
```
Его можно скачать в игнорируемый рабочий каталог:
```powershell
git clone --depth 1 --filter=blob:none --sparse https://github.com/Pr-Mex/vanessa-automation.git .\build\external\vanessa-automation
git -C .\build\external\vanessa-automation sparse-checkout set docs features examples training VanessaAutomation
```
Если репозиторий уже скачан локально, импортируйте Markdown-документацию, Gherkin-сценарии и BSL-модули:
```powershell
npm run import:vanessa-automation-docs -- ".\build\external\vanessa-automation"
```
Если репозиторий стоит на релизном теге, файлы будут сохранены в каталог версии, например `kb/VanessaAutomation/1.2.043.23`, и попадут в MCP-поиск. Каталог `kb/` игнорируется Git.
## Подключение к Codex
Добавьте сервер в `%USERPROFILE%\.codex\config.toml`:
```toml
[mcp_servers.onec_platform_help]
command = "node"
args = ["<путь к репозиторию>\\bit-1c-help\\src\\server.js"]
[mcp_servers.onec_platform_help.env]
BIT_1C_HELP_ROOT = "<путь к репозиторию>\\bit-1c-help\\kb"
```
Если справка лежит в другой папке, замените `BIT_1C_HELP_ROOT` на путь к ней.
## Инструменты MCP
- `search_1c_platform_help` — поиск по локальной справке.
- `get_1c_platform_help_document` — чтение найденного документа по относительному пути.
- `get_1c_platform_help_section` — чтение точного найденного раздела по стабильному `id`.
- `reindex_1c_platform_help` — инкрементальная переиндексация изменившихся файлов.
- `list_1c_platform_help_sources` — список доступных справок для фильтра `source`.
Markdown-документы индексируются по разделам. Поиск ранжирует заголовок, иерархию раздела,
путь и основной текст отдельно, а в результате возвращает заголовок найденного раздела,
`breadcrumbs`, исходный путь и релевантный фрагмент.
Индексы сохраняются в `build/index` в сжатом бинарном формате. Путь можно изменить через
`BIT_1C_HELP_INDEX_ROOT`. Для каждого значения `root`/`source` создаётся отдельный индекс.
Готовый снимок поднимается в память как есть, без обхода каталога справки: на реальном корпусе
обход стоит 24 с против 5 с на загрузку снимка. Обход остаётся там, где его просят явно, —
`npm run build:index` и инструмент `reindex_1c_platform_help`. При повторной индексации неизменённые файлы переиспользуются
по размеру и времени изменения; если метаданные изменились, содержимое дополнительно
сравнивается по SHA-256.
Для диагностики ранжирования передайте `"explain": true` в
`search_1c_platform_help`. Инструмент вернёт вклад заголовка, breadcrumbs, пути,
основного текста и специальных бонусов в итоговую оценку.
Если `source` не указан, сервер распознаёт характерные вопросы о платформе,
стандартах, методиках, БСП, YAxUnit и Vanessa Automation и лениво ищет в подходящих
источниках. Для остальных запросов сохраняется поиск по всему корпусу. В результатах
автоматически маршрутизированного поиска возвращаются `source`, полный путь и стабильный
`id` раздела.
`reindex_1c_platform_help` выполняет инкрементальную переиндексацию и возвращает статистику
по обновлённым, переиспользованным, удалённым, слишком большим и ошибочным файлам.
Полную пересборку он НЕ делает: на `"force": true` инструмент отвечает отказом и называет
команду сборки. Пересборка всего корпуса не укладывается в таймаут запроса (60 с) — клиент
отвалится, а процесс продолжит жечь память и процессор, и остановить его будет нечем. Для
полной пересборки есть `npm run build:index` (см. «Сборка индекса»).
## Логи поиска и статистика
Сервер записывает структурированный JSONL-журнал в `build/logs/search.jsonl`
относительно каталога самого MCP-проекта, а не текущего рабочего каталога процесса.
В журнал попадают события поиска, индексации и ошибки инструментов. Для поиска
сохраняются запрос, его SHA-256-идентификатор, выбранные источники, термины,
число кандидатов, задержка и первые пять результатов. Тексты документов и сниппеты
не записываются.
Каждая запись содержит `serverVersion`, полный `gitCommit` и `indexFormatVersion`.
При запуске записывается событие `server_start`, поэтому журнал можно однозначно
связать с версией сервера и исходным коммитом.
Настройки:
- `BIT_1C_HELP_LOG_PATH` — другой путь к JSONL-журналу;
- `BIT_1C_HELP_LOG_QUERIES=true` — сохранять текст запросов для отладки; по умолчанию
записывается только хеш;
- `BIT_1C_HELP_GIT_COMMIT` — явно заданный commit SHA для сборки вне Git-репозитория;
- `BIT_1C_HELP_LOG_MAX_BYTES` — размер файла перед ротацией, по умолчанию 20 МБ;
- `BIT_1C_HELP_LOG_MAX_FILES` — максимальное число файлов ротации, по умолчанию 5.
Сводный отчёт:
```powershell
npm run stats:search
```
Можно передать путь к журналу и порог слабого результата:
```powershell
npm run stats:search -- ".\build\logs\search.jsonl" 20
```
Отчёт содержит число и частоту запросов без результатов, слабые результаты,
задержки p50/p95, среднее число кандидатов, популярные запросы и распределение
по источникам.
В `search_1c_platform_help`, `get_1c_platform_help_document` и `reindex_1c_platform_help` можно передать `source`, чтобы ограничить область поиска конкретной справкой:
```json
{
"query": "ОбработкаЗаполнения",
"source": "Platform/8.3.27.1989",
"limit": 5
}
```
Большие документы читайте постранично через `get_1c_platform_help_document`: передайте `offset: 0` и `maxChars`, затем используйте значение `nextOffset` из ответа как `offset` следующего вызова. Максимальный размер одной страницы — 30000 символов.
`list_1c_platform_help_sources` показывает не только путь, но и подсказку `useWhen`. Основные источники:
| source | Когда применять |
| --- | --- |
| `Platform/8.3.27.1989` | Синтакс-помощник: объекты встроенного языка, методы, свойства, события, области доступности. |
| `Platform/8.3.15.1869` | Синтакс-помощник платформы 8.3.15: объекты встроенного языка, методы, свойства, события, области доступности. |
| `SSL/3_1_11_353` | Локальная документация БСП из поставки 3.1.11.353. |
| `VanessaAutomation/1.2.043.23` | Vanessa Automation: Gherkin, шаги, примеры, API. |
| `YAxUnit/25.12` | YAxUnit: юнит-тесты, matcher/assert API, структура тестов. |
## Сборка индекса
Индекс строится отдельной командой, вне обслуживания запросов:
```powershell
npm run build:index
```
```powershell
# только изменившиеся файлы вместо полной пересборки
node .\scripts\build-index.js --incremental
# отдельный индекс на каждый раздел: поиск с фильтром source использует именно их
node .\scripts\build-index.js --root kb --root kb\Platform\8.3.27.1989
```
Почему отдельной командой, а не инструментом MCP: полная пересборка реального корпуса не
укладывается в таймаут запроса (60 с). Поэтому `reindex_1c_platform_help` переиндексирует только
изменившиеся файлы, а на `force: true` отвечает отказом и называет эту команду. Выкладка на
сервере строит индекс **до** запуска службы и дожидается конца.
**Индексов несколько, и построить надо каждый.** Поиск с фильтром по источнику работает по
отдельному индексу этого источника. Одной сборки для всего корпуса не хватает: первый же запрос
с фильтром будет строить свой индекс сам. Список корней берут из состава справки, а не задают
руками, иначе новый источник молча останется непостроенным.
Служба поднимает в память только корневой индекс (прогрев при старте), индексы источников —
по требованию. В памяти их держится не больше `BIT_1C_HELP_INDEX_CACHE_LIMIT` (по умолчанию 3,
считая закреплённый корневой), давно не использовавшиеся вытесняются. Предел не декоративный:
на реальном корпусе корневой индекс удерживает 1046 МБ, синтакс-помощник 8.3.27 — ещё 363 МБ,
а источников всего девять.
## Проверка
```powershell
npm test
```
Единый прогон `node --test`: ядро (поиск, ранжирование, чтение разделов, фильтр по источнику),
контракт обоих входов, `/health`, `/status`, отказ `reindex` при `force`, холодный старт и предел
кеша индексов, а также золотой набор реальных запросов с ожидаемыми документами в выдаче.
Золотой набор пропускается, если в клоне нет `kb/`. Тот же прогон выполняет GitHub Actions на каждый
push и pull request.
Отдельные проверки:
```powershell
npm run smoke # локальный прогон через вход stdio поверх настоящего kb/
npm run test:diff-entries # stdio и сетевой вход отвечают одинаково
npm run test:diff-monolith # ответы против прежнего монолита src/server.js
npm run test:source-filter # фильтр по источнику
npm run test:clean-docs # качество очистки справки
npm run test:platform-updates # импорт обновлений платформы
```
`test:diff-monolith` сравнивает текущий вход с монолитным `src/server.js` из истории git.
Ревизия по умолчанию — `12ae917~1`; при слиянии со сжатием истории такого коммита не станет, и
тогда её надо задать явно:
```powershell
$env:MONOLITH_REV = "<ревизия>"; npm run test:diff-monolith
```
Скрипт проверяет наличие ревизии до начала прогона и говорит об этом прямо, а не падает
невнятной ошибкой git в середине.
### Смоук работающей службы
Тот же `smoke.js` умеет проверять уже запущенный сетевой сервис по URL — `initialize`,
`tools/list` и поисковый запрос с проверкой, что результат непустой:
```powershell
node .\scripts\smoke.js --url http://127.0.0.1:4101/mcp
node .\scripts\smoke.js --url https://mcp.example.com/bit-1c-help/mcp --query "ОбработкаЗаполнения"
```
Ключи: `--query <текст>` (по умолчанию «платформа»), `--host <значение>` — заголовок `Host`, если
служба за прокси и проверяет его, `--timeout <мс>`. Ненулевой код возврата при любой неудаче: это
инструмент приёмки, скрипт выкладки смотрит на код, а не на текст. Он же выполняет прогревочный
запрос, чтобы первое обращение после выкладки не досталось живому пользователю.
## Манифест сервиса и сборка артефактов
Манифест `mcp-service.json` в корне репозитория — единственная точка стыка с площадкой, на которой
служба работает. В нём имя службы, порт, точка входа, маршрут, переменные окружения и **состав
выкладки** (`payload`). Состав перечислен пофайлово и читается сборочным скриптом по-настоящему:
второго списка в скриптах нет. Значения `{DataRoot}`, `{PublicHost}` и `{Port}` в блоке `env`
подставляет скрипт выкладки на площадке.
Почему состав пофайловый: в `src` лежит `ssl_3_1_11_353` на 209 МБ, которому на сервере делать
нечего, а в `scripts` — импортёры справки, нужные только на рабочей машине. На сервере из
`scripts` нужны ровно три файла: сборка индекса, подсчёт статистики журнала и
смоук для приёмки.
```powershell
# артефакт кода: чистый npm ci --omit=dev, состав по манифесту, BUILD-INFO.json, zip + SHA-256
powershell -File tools\build-release.ps1
# артефакт справки: kb/ и KB-VERSION.txt внутри, zip + SHA-256
powershell -File tools\build-kb-artifact.ps1
```
Версии двух артефактов независимы: код — semver из `package.json`, справка — по дате сборки.
`node_modules` кладётся внутрь артефакта кода: на сервере не выполняется `npm install`, не нужен
доступ к реестру npm и исключён риск получить набор зависимостей, отличный от протестированного.
Всё, что эти скрипты пишут для Node (`BUILD-INFO.json`, сводки сборки), пишется в UTF-8 **без
BOM**. Это не оформление: `Set-Content -Encoding UTF8` в Windows PowerShell 5.1 добавляет BOM,
`JSON.parse` на нём падает, `/health` уходит в `degraded` с `gitCommit: "unknown"` — и приёмка
откатывает исправную выкладку.
TDQS
Scored across 5 tools
Each tool has a distinct role: search, read document, read section, list sources, and reindex. The two getters are clearly separated by document-level vs section-level retrieval with explicit guidance on which to prefer.
All tools follow the pattern [verb]_1c_platform_help[_object] with snake_case throughout. Verbs (search, get, get, reindex, list) are consistent and the two get_ tools are differentiated by their object suffixes.
Five tools form a tight, well-scoped set for an offline help retrieval server. There are no redundant tools and nothing feels missing.
The domain is offline 1C help access, and the set covers the full lifecycle: discover sources, search, retrieve documents/sections, and maintain the index. No obvious operational gaps remain for the stated purpose.