Skip to main content
Glama
README.md
# 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

A4.2/5.0

Scored across 5 tools

Disambiguation5/5

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.

Naming Consistency5/5

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.

Tool Count5/5

Five tools form a tight, well-scoped set for an offline help retrieval server. There are no redundant tools and nothing feels missing.

Completeness5/5

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.

Maintenance

ActivityMaintained
ResponsivenessNo issues