mcp-1c
# MCP-сервер для разработки на 1С
`mcp-1c` помогает AI-агенту писать BSL с опорой на вашу конфигурацию и справку
целевой версии платформы. Он даёт доступ к метаданным, модулям, формам, связям
объектов и ролям. Несколько конфигураций работают в одной установке.
Например, агент может найти справочник по описанию, прочитать процедуру,
найти её вызовы или проверить сигнатуру метода для нужной версии 1С.
Сервер запускается готовым Docker-образом; всё состояние
конкретной установки находится в каталоге `data/`.
<picture>
<source media="(prefers-color-scheme: dark)" srcset=".github/assets/dashboard-overview-dark.png">
<source media="(prefers-color-scheme: light)" srcset=".github/assets/dashboard-overview-light.png">
<img alt="Дашборд MCP-1C: конфигурации, источники и состояние сервера" src=".github/assets/dashboard-overview-light.png">
</picture>
<p align="center"><sub>Интерфейс дашборда на полностью синтетических данных.</sub></p>
## Возможности
- Поиск объектов и процедур по имени и назначению, чтение кода и поиск вызовов.
- Структура объектов, связи, таблицы запросов и сравнение конфигураций.
- Справка нескольких версий платформы: сигнатуры, доступность и рекомендации.
- Чтение управляемых форм и объявленных прав ролей.
- Дашборд для загрузки источников, просмотра конфигураций и настройки модулей.
- Локальные skills для форматирования BSL, ревью, создания форм и метаданных.
## Быстрый запуск
Нужны **Docker с Compose v2.17+, curl и OpenSSL**. Команды ниже рассчитаны на
терминал Linux/macOS; на Windows используйте WSL. Python, Node и клонирование
репозитория для запуска готового образа не требуются.
### 1. Скачать файлы запуска
Создайте новый каталог установки:
```bash
mkdir mcp-1c
cd mcp-1c
curl --fail --show-error --location --output compose.yaml \
https://raw.githubusercontent.com/AzeevAN/mcp-1c/v4.5.0/compose.yaml
curl --fail --show-error --location --output .env.example \
https://raw.githubusercontent.com/AzeevAN/mcp-1c/v4.5.0/.env.example
```
### 2. Создать .env и токены
Следующий блок копирует шаблон в `.env` и записывает два разных случайных токена:
```bash
umask 077
mcp1c_api_token=$(openssl rand -hex 32)
mcp1c_admin_token=$(openssl rand -hex 32)
sed -e "s/^API_TOKEN=$/API_TOKEN=$mcp1c_api_token/" \
-e "s/^ADMIN_TOKEN=$/ADMIN_TOKEN=$mcp1c_admin_token/" \
.env.example > .env
unset mcp1c_api_token mcp1c_admin_token
```
Сохраните `.env`: `API_TOKEN` нужен агенту для чтения, `ADMIN_TOKEN` — для входа
в дашборд и изменения источников. При обновлении установки сохраняйте свои
токены; этот блок предназначен для первого запуска.
### 3. Создать каталог данных
**Linux с обычным Docker:**
```bash
sudo install -d -o 10001 -g 10001 -m 0750 ./data
```
**macOS или Windows с Docker Desktop:**
```bash
mkdir -p data
```
Rootless Docker, user namespace и особенности прав каталогов описаны в
[полной инструкции установки](docs/installation.md#3-подготовить-каталог-данных-на-linux).
### 4. Запустить и открыть
```bash
docker compose config --quiet
docker compose up -d --wait --wait-timeout 180
curl --fail http://127.0.0.1:5001/health
```
Откройте **[http://127.0.0.1:5001](http://127.0.0.1:5001)** в браузере и войдите
с `ADMIN_TOKEN` из `.env`. MCP endpoint: `http://127.0.0.1:5001/mcp`.
При первом запуске Docker скачивает образ; команда `--wait` ждёт готовности
контейнера до 180 секунд. Если запуск завершился ошибкой, см.
[диагностику](docs/installation.md#12-диагностика-запуска).
По умолчанию сервер доступен только на вашей машине. Для подключения с другой
машины, HTTPS, изменения порта, установки без Docker и диагностики используйте
[руководство установки](docs/installation.md).
## Загрузить данные
Сервер может запуститься без конфигураций. Откройте страницу **«Источники»**
в дашборде и добавьте нужные данные:
1. **Конфигурацию:** ZIP структуры из обработки экспортера (Source A) или
полную файловую выгрузку из Конфигуратора (Source B).
2. **Справку платформы:** `shcntx_ru.hbk` из установленной версии 1С.
Версия определяется по имени файла или родительского каталога:
`shcntx_ru_8.3.27.2130.hbk`, `shcntx_ru.8.3.27.hbk` или
`8.3.27.2130/shcntx_ru.hbk`.
3. **Расширения:** отдельную файловую выгрузку с выбранной конфигурацией-родителем.
Если дисковое поколение конфигурации повреждено или недоступно, сервер
сообщает причину в журнале запуска и поднимает остальные конфигурации.
Указатель пропущенного поколения и его расширений сохраняется в реестре:
после исправления файлов выполните перезагрузку. Удаление такого источника
снимает и сохранённый указатель.
Недоступная конфигурация продолжает занимать своё внутреннее имя:
новая полная загрузка требует восстановления источника или явного удаления.
Переход на загрузку только структуры снимает прежние расширения, включая
временно недоступные; возврат их каталогов не активирует их заново.
При публикации контрольные суммы содержимого поколения проверяются при
копировании. Для следующих запусков сохраняется расходный подписанный
маркер `.verified`: он связывает SHA манифеста со штампами файлов поколения
(устройство, inode, размер, `mtime_ns`, `ctime_ns`). Неизменное поколение
не требует повторного чтения всего пакета. Отсутствующий, повреждённый или
устаревший маркер возвращает полную проверку; после неё старт владельца
может восстановить маркер. Прямое чтение реестра и гостевой процесс его
не записывают. Для принудительной полной проверки удалите `.verified`
нужного поколения и выполните перезагрузку. Штампы предполагают неизменность
канонических файлов и не обнаруживают повреждение носителя без изменения
их метаданных.
Ключи маркеров временных поколений освобождаются из памяти после чтения
и записи; файлы ключей сохраняются для проверки подписи.
Source A даёт структуру объектов; Source B дополнительно содержит код, формы
и роли. Подключение Source B требует предварительной проверки и подтверждения
публикации. Индексы и загруженные данные сохраняются в `data/`.
Статус готовой предварительной проверки показывает сохранённый план и его
влияние на расширения. При подтверждении содержимое слоёв проверяется
заново. Старый preview без сохранённого расчёта влияния нужно отменить и
подготовить заново; отмена сохраняет исходный кандидат для повторной загрузки.
История возвращает 50 последних по времени изменения читаемых jobs
и все нечитаемые записи.
При обновлении списка подтверждённые jobs с commit старше 30 суток
очищаются; эта очистка не удаляет источники и загруженные поколения.
Публикация поколения записывает реестр и WAL вне блокировки снимка Registry.
Во время записи снимок содержит целостное прежнее состояние, после commit —
целостное новое; удаление источника также очищает кэш после смены состояния.
Если исход атомарной записи неопределён, следующие изменения требуют
успешной перезагрузки реестра. Она принимает уже записанное удаление,
даже если ошибка возникла после замены файла реестра. Изолированные ошибки отдельных источников
обрабатываются по обычному правилу сохранения их записей.
Список подключённых каталогов доступен во время публикации после проверки
входа. Изменение привязки ждёт завершения confirm; перед публикацией
привязка и содержимое выбранного каталога проверяются повторно.
Полное обновление сохраняет редакцию — первые два числа версии. Для
конфигурации, загруженной без версии, разрешено назначить номерную версию;
переход из непустой нечисловой версии в номерную остаётся запрещённым.
«Розница» 3.0 не обновляет загруженную «Розницу» 2.3: это другое
поколение с тем же внутренним именем, и на карточке выгрузки вместо кнопки
будет причина. Чтобы перейти, удалите загруженную конфигурацию (вместе с
расширениями) и загрузите выгрузку как новую. Держать две редакции одной
конфигурации рядом — значит поднять второй сервер со своим каталогом
`data/`. Подробности — в [загрузке конфигураций](docs/configuration-loading.md).
На страницах «Обзор» и «Источники» формат загрузки показан отдельной полосой:
«Структура конфигурации», «Полная выгрузка» или «Формат загрузки неизвестен».
На странице источников версия, платформа, объекты и связи идут в одной строке
на широком экране. Состояние кода показано отдельно; обычные теги активации
скрыты, предупреждение о необходимости повторной загрузки остаётся видимым.
Дата последней успешной загрузки показана отдельно у основной конфигурации
и каждого расширения: в карточках кода она находится рядом с подписями
«Основной код» и «Расширение» и видна без раскрытия подробностей. Дата
сохраняется после перезапуска; новая принятая загрузка, включая повторную
загрузку тех же данных, обновляет её. Предпросмотр, отмена и ошибка дату
не меняют. Время показано в часовом поясе браузера. Для старых данных без
сохранённой даты выводится «Дата не сохранена»; дата запуска сервера её
не заменяет. Загрузка расширения не меняет дату основной конфигурации.
Опубликованный корпус кода содержит полный комплект индексов: различаются
отсутствие кода, готовность и ограничения покрытия. Ход загрузки и её ошибки
показаны в задании приёма; до успешного обновления доступен прежний корпус.
При необходимости повторной активации код указан как недоступный, а не как
незагруженный.
В schema v1 `truncated=true` означает неполную выгрузку: `reg-add` принимает
её только с явным `--allow-truncated`, сохраняя отметку неполноты.
Подробности — в [операциях с источниками](docs/operations.md).
Во входящих ZIP с тем же SHA, что у активного поколения, помечается
«загружено». После изменения содержимого это снова «не разобрано»;
версия или имя файла сами по себе совпадение не доказывают. Кэш SHA
учитывает устройство, inode, размер, `mtime_ns` и `ctime_ns`, поэтому распознаёт
замену и правку файла на месте с сохранёнными размером и временем. Ручная проверка списка и успешное
подтверждение загрузки обновляют отметку. Если файл изменился или не
читается во время расчёта SHA, строка остаётся в списке как «не разобрано»
с просьбой повторить обновление.
Загрузка ZIP из браузера пишет тело сразу в staging и считает SHA-256
во время записи. Повторное открытие использует проверенный SHA в пределах
процесса при совпадении устройства, inode, размера, `mtime_ns` и `ctime_ns`;
структура ZIP проверяется каждый раз. После перезапуска первая проверка
снова читает весь ZIP. Обрыв загрузки удаляет незавершённый файл.
Уже записанный ZIP не требует второго такого же объёма свободного места:
при приёме проверяется только запас на служебные файлы. Нехватка места
на томе данных — ответ `507`, превышение предела размера файла — `413`.
Полная выгрузка — ZIP из браузера и `data/incoming/`, а также подключённый
каталог `/config-sources/<id>` — читается под одним бюджетом: сумма распакованного — `MCP1C_INTAKE_MAX_UNPACKED` (по умолчанию
16 ГиБ), одна запись — до 4 ГиБ, сжатие записи крупнее 1 МиБ — до 512:1.
Размер и число записей центрального каталога ZIP проверяются до его разбора;
предел размера каталога — 29 534 470 байт. Описание метаданных, форма,
`Package.bin` и дескриптор роли, которые
разбираются в памяти целиком, — до 24 МиБ каждый; текстовый модуль — до
17 МиБ (больший отвергает всю выгрузку с именем записи; скомпилированный
`.Module` текстом не читается и этим пределом не ограничен); перед сборкой
проверяется свободное место. Специальные файлы в каталоге выгрузки
отвергаются без зависания, в том числе после подмены обычного файла.
Записи внутри V8-контейнеров форм читаются
с отдельными пределами: `module` — до 883 773 байт, `form` — до 5 263 508 байт;
сумма распакованных записей с атрибутами — до 5 477 165 байт, не больше пяти
записей. Превышение делает соответствующую форму или её модуль нечитаемыми;
остальная конфигурация остаётся доступной. При открытии V8-контейнера
суммарный размер просмотренных заголовков блоков таблицы и атрибутов
не превышает физический размер файла, умноженный на 2,5: общие хвосты пустых блоков
не могут обходиться для каждой строки неограниченно. Повторное чтение
данных сохраняет обычный бюджет распаковки. `Rights.xml` — до 36 558 648 байт;
один текстовый узел при канонизации — до 2 217 155 UTF-8 байт. Слишком большой
файл отвергается до чтения, превышение текстового узла отмечает ошибку слоя
ролей и сохраняет остальные слои конфигурации. Чрезмерная вложенность XML
формы помечает её битой и не прерывает индексирование остальных форм;
глубоко вложенный JSON запроса получает `422`. Расхождения, не мешающие разбору (например,
повтор цели в составе подсистемы), загрузку не останавливают и выводятся
предупреждением в `docker logs mcp1c`.
Подробный порядок, форматы ZIP, ограничения и API:
[загрузка конфигураций и расширений](docs/configuration-loading.md).
Обработка для выгрузки структуры: [exporter-1c/README.md](exporter-1c/README.md).
## Подключить агента
Сервер использует **Streamable HTTP**. Передайте агенту `API_TOKEN` из `.env`.
Для Codex CLI добавьте в `~/.codex/config.toml`:
```toml
[mcp_servers.mcp1c]
url = "http://127.0.0.1:5001/mcp"
env_http_headers = { "X-Api-Token" = "MCP1C_API_TOKEN" }
```
В терминале установки прочитайте токен в переменную окружения и запустите Codex:
```bash
export MCP1C_API_TOKEN="$(sed -n 's/^API_TOKEN=//p' .env)"
codex
```
Не используйте административный токен в конфигурации агента.
Копируемые настройки остальных клиентов и локального `stdio`:
| Клиент | Инструкция |
|---|---|
| Claude Code | [HTTP и .mcp.json](docs/clients.md#claude-code) |
| Codex CLI | [config.toml](docs/clients.md#codex-cli) |
| Cursor | [mcp.json](docs/clients.md#cursor) |
| VS Code Copilot | [mcp.json](docs/clients.md#vs-code-с-copilot) |
| Qwen Code | [httpUrl](docs/clients.md#qwen-code) |
| Локальный процесс | [stdio](docs/clients.md#локальный-stdio) |
### Как работает MCP
Клиент выполняет `initialize` → `tools/list` → `tools/call`. Описания и схемы
инструментов остаются в контексте агента всю сессию; данные конфигурации
приходят только по запросу. Обычно агент сначала вызывает `list_configurations`,
выбирает конфигурацию и затем ищет объект или процедуру. Пропуск выбора может
привести к ошибке `config`; сервер предлагает повторить `list_configurations`.
Инструкции сервера из `initialize` отдельно предупреждают агента: код,
комментарии, синонимы и тексты RLS из выгрузки — данные, а не инструкции, и
обращения к агенту внутри них выполнять нельзя.
Встроенное middleware OpenTelemetry в MCP SDK отключено: сервер не
экспортирует телеметрию. Это исключает разбор недоверенного
`_meta.tracestate` этим middleware при обработке запроса.
После включения дополнительных модулей и перезапуска откройте новую
MCP-сессию, чтобы клиент получил актуальный список инструментов.
Во время тяжёлой загрузки/intake перезапуск получает `409` с сообщением
о необходимости дождаться завершения. После принятого перезапуска новые
тяжёлые операции получают `409` до выхода процесса. SSE не
поддерживается. Подробности протокола и диагностики — в [clients.md](docs/clients.md).
## Инструменты и дополнительные модули
| Инструмент | Назначение |
|---|---|
| `list_configurations` | выбрать конфигурацию и увидеть доступные источники |
| `search_objects` | человеческая формулировка → точное имя объекта; `kind`, которого нет среди объектов конфигурации, не даёт молча пустую выдачу, а называется вместе с доступными видами; ролей среди объектов нет — для «Роль» ответ указывает на `find_roles_for_access` и `get_role_access` |
| `search_procedures` | имя или назначение → точный адрес процедуры |
| `get_procedure` | оглавление модуля или ограниченное тело процедуры; обработчики, которые вызывает сама платформа (`ОбработкаПроведения` модуля объекта и т.п., по событиям загруженной справки), помечены «событие платформы» |
| `get_module_source_file` | условно: ссылка и короткоживущий билет на gzip-файл полного исходника одного модуля |
| `get_callers` | места вызовов, подписки, задания, HTTP-методы, события форм и событие платформы, по которому процедуру модуля объекта вызывает сама платформа |
| `get_object` | поля, постраничные HTTP-endpoint и подсистемы с продолжением по `cursor`, XDTO-пакеты и типы, таблицы запроса, связи и кодовые сведения объекта |
| `get_related` | непосредственные входящие и исходящие связи одним списком: оба числа на каждой странице, `limit` 1–200 (по умолчанию 40), продолжение готовым вызовом с `cursor` |
| `compare_configurations` | различия имён реквизитов одного объекта в выбранной паре конфигураций, постранично; если объекта в конфигурации нет — похожие объекты того же вида |
| `search_syntax` | поиск по синтаксису и таблицам запросов платформы; пустой раздел оглавления с содержательным дублем того же адреса не занимает место в выдаче, одиночные разделы и реальные элементы без описания сохраняются; поле таблицы запроса адресуется через таблицу (`…Остатки.НомерСтроки`), таблица, описанная дважды, — одной строкой с пометкой вариантов; на имя объекта конфигурации с таблицами запроса — ссылка на `get_object` |
| `get_syntax` | сигнатура, доступность, версия, тип и описание возвращаемого значения, пример и замена; `full` добавляет первые 50 ссылок на связанные карточки, `links` продолжает список через `links_offset`; одноимённые варианты с одинаковым адресом возвращаются вместе; пустые страницы разделов оглавления справки вариантами не считаются; голое имя метода открывает глобальный контекст и называет остальные одноимённые; конкретное имя (`Справочники.Номенклатура.ПустаяСсылка`) открывает шаблон справки |
| `search_reference` | условно: короткие карточки из доверенной общей справки |
| `get_reference` | условно: точная карточка или раздел с продолжением по курсору |
| `find_roles_for_access` | условно: роли-кандидаты по объекту и точным базовым либо интерактивным операциям из объявленных прав; ошибка неизвестной или повторной операции перечисляет допустимые значения `operations`, например `read` |
| `get_role_access` | условно: компактные объекты роли, явная дочерняя/аудитная детализация и окна RLS; ненайденная роль называется вместе с конфигурацией и похожими именами, пустой `detail=children` — с пояснением `note` |
Адрес, которого нет (объект в `get_object`/`get_related`, модуль или процедура
в `get_procedure`/`get_callers`), — ошибка инструмента (`isError`) с тем же
текстом и подсказками похожих адресов; поиск без результатов остаётся обычным
ответом.
Две ролевые операции регистрируются при старте с capability `role_access`,
включая запуск без готового слоя ролей. После удаления источника сервер
повторно синхронизирует каталог и при ошибке очистки intake, перед возвратом
этого отказа клиенту.
Синхронизация выполняется в пуле потоков: запрос ждёт её результат,
а event loop может обслуживать другие запросы.
Повторные обращения к коду одного расширения переиспользуют последнее
согласованное разрешение его структуры относительно родителя. Registry
удерживает 1 такой результат; переключение на другое расширение вытесняет
его, а обновление или снятие источника сбрасывает. Первый вызов по-прежнему
собирает разрешение. Кэш не меняет доступность и порядок наложения слоёв.
Стенд времени, памяти и совпадения ответов:
`PYTHONPATH=src .venv/bin/python tools/lab/measure_backlog_costs.py --help`;
`--baseline-src` и `--candidate-src` задают сравниваемые версии,
`--archives` и `--group ZUP:base.zip,extension.zip` — исходные ZIP и явно
согласованную пару. Исходные архивы читаются без изменения, временные реестры
удаляются после прогона. `--synthetic-extension` проверяет стоимость на
искусственном расширении и не подтверждает совместимость реальных слоёв.
Живая приёмка рядом с работающим контейнером:
`.venv/bin/python tools/lab/accept_live_stand.py --help`.
`--image` задаёт тестовый образ, `--data-copy` — отдельный новый каталог копии
без символьных ссылок (на macOS — под `/private/tmp`, а не `/tmp`),
`--report` — JSON-отчёт, `--port` — порт стенда
(по умолчанию 5091). `--scenarios S1,S2` запускает пилот старта и всех
MCP-инструментов; без списка выбираются S1–S18. `--compare` сравнивает с
сохранённым отчётом, `--timeout-seconds` ограничивает весь прогон (5400 с).
После перезапуска стенд ждёт новый `runtime_id`, пережидая обрывы
соединения и неполные HTTP-ответы в пределах таймаута ожидания.
Стенд читает рабочий `data/`, работает на копии и удаляет свой контейнер;
`--cleanup` удаляет также копию с проверенным маркером принадлежности.
Рабочие токены не используются, токены стенда генерируются заново.
В отчёте различаются PASS, FAIL и SKIP с причиной. S16 (вход и все страницы
дашборда через навигацию, ошибки консоли, скриншоты) выполняется с `--ui`
и обязательным `--evidence-dir`; нужен Python-пакет Playwright и Chromium,
`--chrome` задаёт свой браузер. Без `--ui` S16 — SKIP, и итог прогона
`PASS_WITHOUT_UI` (код выхода 3), а не полный `PASS` (код 0); любой сбой —
`FAIL` (код 1). Итог записывается в поле `result` отчёта.
RSS измеряется выборкой раз в 2 с — это оценка пика.
Пределы приёма измеряет
`.venv/bin/python tools/lab/measure_audit_limits.py --help`:
`--archive` / `--hbk` выбирают отдельные входы, `--archives` / `--hbk-root` —
каталоги для рекурсивного поиска (ключи можно повторять). `--report` задаёт
JSON-отчёт, `--timeout-seconds` — общий таймаут (3600 с). Скрипт читает
источники без изменения, контейнеры форм извлекает во временный каталог.
Измеряются центральный каталог ZIP, записи `module`/`form`, `Rights.xml`,
текстовые узлы (UTF-8 байты и символы), длина версии в символах и страницы
HBK. Версия конфигурации в `Configuration.xml` — до 64 символов; более
длинная отвергается при probe. Страница справки ограничена 454 773 байтами; превышение пропускает
эту страницу с предупреждением источника, остальные продолжают разбираться.
При неполном проходе максимумы явно помечены как нижние оценки;
предлагаемый запас ×2,5 выводится отдельно от текущих лимитов сервера.
Действующие пределы приёма выведены этим измерителем 2026-10-23 на 18 ZIP
и 30 HBK (крупные типовые конфигурации и книги справки):
`.venv/bin/python tools/lab/measure_audit_limits.py --archives <каталог ZIP> --hbk-root <каталог HBK> --report limits.json --timeout-seconds 2400`.
Предел — реальный максимум × 2,5 с округлением вверх:
| Метрика | Реальный максимум | Предел |
|---|---:|---:|
| Центральный каталог ZIP, байт | 11 813 788 | 29 534 470 |
| Запись `module` в контейнере формы, байт | 353 509 | 883 773 |
| Запись `form` в контейнере формы, байт | 2 105 403 | 5 263 508 |
| `Rights.xml`, байт | 14 623 459 | 36 558 648 |
| Текстовый узел при канонизации, байт UTF-8 | 886 862 | 2 217 155 |
| HTML-страница справки, байт | 181 909 | 454 773 |
| Версия конфигурации, символов | 14 | 64 (с запасом, решение владельца) |
Повторное обнаружение входящих ZIP измеряется через локальный ASGI-клиент:
`.venv/bin/python tools/lab/measure_audit_perf.py --incoming-archive incoming/configuration.zip --repeat 2 --timeout-seconds 180 --report intake-perf.json`.
Нужно [окружение разработчика](CONTRIBUTING.md#запуск-и-тесты).
`--incoming-archive` добавляет обычный ZIP, который копируется во временные
данные; параметр можно повторять для основной конфигурации и расширений.
`--repeat` — число GET в одном сервисе (не меньше двух),
`--timeout-seconds` — общий предел с копированием и хешами (по умолчанию 180 с).
`--report` необязателен и создаёт только новый файл. Один JSON также выводится
в stdout: длительности GET, счётчики discovery/SHA, контроль исходника,
идентификация кода и результат уборки. Код выхода `0` — измерение завершено,
`2` — неполный результат или ошибка. Копирование прогревает файловый кэш;
измеряется обработка API в процессе. Собственный процесс и временные данные
убираются и при таймауте.
Повторное обнаружение неизменных ZIP в `incoming` использует кэш процесса.
Замена файла или изменение размера/`mtime_ns` сбрасывают кэш; проверка при запуске загрузки и
публикации сохраняется. Запись кандидата восстанавливается и после удаления
конфигурации, если сам ZIP остался во входящих.
Замер 2026-10-23, по одному прогону до/после (код до изменения — `5261158`):
| Входы | Общий размер, байт | GET 1 до → после, с | GET 2 до → после, с |
|---|---:|---:|---:|
| ЗУП + 2 расширения | 574 416 149 | 0,690920 → 0,701557 | 0,676938 → 0,002038 |
| Розница + расширение | 1 447 908 965 | 1,044251 → 1,000603 | 1,012909 → 0,001593 |
На втором GET после изменения discovery и SHA не вызываются; до изменения
они выполнялись для каждого архива. Команды для этих входов (данные в
репозиторий не входят):
```bash
.venv/bin/python tools/lab/measure_audit_perf.py --incoming-archive __data/zup/ZUP.zip \
--incoming-archive "__data/zup/ZUPext1 (2).zip" --incoming-archive "__data/zup/ZUPext2 (2).zip"
.venv/bin/python tools/lab/measure_audit_perf.py --incoming-archive __data/retail/RetailConfigFiles_04092026.zip \
--incoming-archive __data/retail/RetailConfigFiles_ext_04092026.zip
```
Подготовку, публикацию и восстановление поколений измеряет
`.venv/bin/python tools/lab/measure_generation_verify.py --base-archive incoming/configuration.zip --timeout-seconds 900 --report generation-perf.json`.
`--extension-archive` можно повторять для расширений этой базы. Скрипт
читает исходные ZIP без изменения, публикует их в отдельные временные данные,
затем в последовательных процессах измеряет старт, reload и CLI `reg-list`.
Флаг `--tool-latency` перед этими проверками запускает настоящий
`tools/measure_tool_latency.py` на том же временном стенде с 20 повторами.
В этом режиме `--report` обязателен: рядом сохраняются новые приватные
файлы `<отчёт>.latency.stdout.txt` и `<отчёт>.latency.stderr.txt`.
Отчёт содержит аргументы, код выхода, времена первого вызова и медианы,
полноту набора из 12 строк. Отсутствующая справка оставляет `search_syntax`
как `not_checked`; остальные пропуски делают прогон неполным. Результаты
самих вызовов этот инструмент не проверяет. Контрольные суммы пакета,
измерителя и вызываемого скрипта сверяются до и после запуска.
Флаг `--graph-memory` в отдельном процессе измеряет Python-выделения
нового `Graph(config)` на уже загруженной конфигурации. Загрузка и импорты
идут до `tracemalloc`, контрольные суммы рёбер — после его остановки.
Отчёт показывает текущий и пиковый объём, а также приращение после GC
при живом графе. Это память нового экземпляра, не RSS процесса или
контейнера; пиковый объём может остаться прежним.
Общий таймаут по умолчанию — 900 с; `--report` создаёт только новый файл,
тот же JSON выводится в stdout. Код выхода `0` означает полный результат,
`2` — ошибку или неполный проход. Отчёт содержит время этапов, байты
копирования и повторной проверки pack, контроль исходников и совпадения
манифестов. Собственные процессы и временные данные удаляются и при ошибке.
Отдельные счётчики показывают время холодной сборки индексов кода,
число разборов BSL и число модулей. Контрольные суммы четырёх состояний
индексов и ответы поисковых запросов сверяются после публикации, старта
и reload. Шесть запросов берутся из `modules-procedures`; вызывающие
процедуры проверяются отдельной выборкой до пяти точных адресов.
Время вычисления контрольных сумм состояний и запросов выводится отдельно
и не входит во время этапов сборки. Сборка измеряется с накладными
расходами счётчиков.
Контрольный SHA прогревает файловый кэш; холодный диск этим способом
не измеряется.
При восстановлении каталог пропускает чтение модулей нулевого размера.
Остальные тела целиком проверяются на UTF-8 и пустоту без нормализации;
при чтении исходного текста сохраняется нормализация переводов строк.
Кэш проверяет подпись
и распаковывает сжатые данные через представление исходного буфера;
при записи заголовок, подпись и сжатый блок записываются отдельно.
Холодная сборка повторно использует первый разбор исходных модулей для
оглавления, вызовов и поиска. Временный кэш вызовов ограничен бюджетом памяти:
при превышении он освобождается, а этап вызовов разбирает модули заново
с сохранением полного результата. Экспортные заголовки освобождаются
по завершении поиска; полные результаты разбора всего корпуса в памяти
не сохраняются.
Подробные карточки объектов повторно используют индекс принадлежности
модулей и форм; поиск точного адреса без учёта регистра использует таблицы
адресов. Подсказки к неизвестному модулю ограничены тем же видом объекта
(например, `Документ`). Если модулей такого вида в корпусе нет, подсказки
используют весь список. Подсказки к имени процедуры остаются в её модуле.
Готовый граф не удерживает вспомогательные словари разрешения адресов:
они используются только во время построения.
Замер 2026-10-24, по одному прогону до/после (код до изменения — `4077457`,
одинаковый измеритель в обоих деревьях исходников):
| Входы | Confirm, с | Старт, с | Reload, с | CLI `reg-list`, с |
|---|---:|---:|---:|---:|
| ЗУП + 2 расширения | 92,507 → 85,050 | 6,741 → 4,471 | 6,989 → 4,467 | 7,300 → 4,501 |
| Розница + расширение | 71,835 → 63,078 | 7,315 → 4,496 | 7,467 → 4,356 | 7,513 → 4,606 |
Confirm — сумма по базе и расширениям; старт и reload измеряют
`Registry.startup()`, CLI запускается отдельным процессом. Счётчики подтвердили
однократное копирование с проверкой 494 710 275 байт ЗУП и 402 316 602 байт
Розницы. Повторное чтение pack внутри verify после изменения — ноль байт
при confirm, старте и reload. Манифесты, количество members и контрольные
суммы исходных ZIP совпали до/после; временные данные и процессы убраны.
Это отдельные прогоны с прогретым файловым кэшем, без оценки p95.
```bash
.venv/bin/python tools/lab/measure_generation_verify.py --base-archive __data/zup/ZUP.zip \
--extension-archive "__data/zup/ZUPext1 (2).zip" --extension-archive "__data/zup/ZUPext2 (2).zip"
.venv/bin/python tools/lab/measure_generation_verify.py --base-archive __data/retail/RetailConfigFiles_04092026.zip \
--extension-archive __data/retail/RetailConfigFiles_ext_04092026.zip
```
Отдельный замер тёплого старта без нормализации тел — 2026-10-24,
те же команды, по одному прогону до/после, код до изменения — `2317817`:
| Входы | Старт, с | Reload, с | CLI `reg-list`, с |
|---|---:|---:|---:|
| ЗУП + 2 расширения | 4,115 → 3,570 | 4,233 → 3,708 | 4,280 → 3,865 |
| Розница + расширение | 4,448 → 3,995 | 4,310 → 3,962 | 4,681 → 4,213 |
Контрольные суммы исходников, манифесты и состав слоёв совпали до/после.
Это тёплый файловый кэш; холодный диск, RSS и p95 не измерялись.
Холодная сборка измерена отдельно 2026-10-24 теми же командами, по одному
прогону до/после; код до изменения — `fcb94c8`, измеритель одинаковый:
| Входы | Доступных модулей | Разборов BSL | Сборка четырёх индексов, с | Confirm, с |
|---|---:|---:|---:|---:|
| ЗУП + 2 расширения | 8 540 | 22 725 → 8 540 | 61,673 → 26,366 | 78,143 → 43,713 |
| Розница + расширение | 7 949 | 20 842 → 7 949 | 46,777 → 20,359 | 59,458 → 33,631 |
Времена сборки и confirm суммируются по базе и расширениям. Все четыре
состояния индексов, ответы шести поисковых запросов, результаты шести
случаев `bench.py` и пяти запросов вызывающих процедур совпали до/после.
При повторных старте и reload сборщик не вызывался. Это измерение
с накладными расходами счётчиков, без замера RSS, p95 и холодного диска.
Задержки запросов на ЗУП с двумя расширениями проверены 2026-10-24,
по одному прогону инструмента до/после; код до изменения — `f217fa5`.
В каждой измеренной строке — первый вызов и медиана 20 повторов.
| Вызов | Первый, мс | Медиана, мс |
|---|---:|---:|
| `get_object fields` | 37,29 → 50,58 | 8,12 → 0,18 |
| `get_object full` | 8,22 → 0,21 | 8,13 → 0,18 |
| `get_procedure`: оглавление | 390,66 → 387,81 | 15,34 → 14,99 |
| `get_procedure`: процедура | 25,80 → 27,67 | 24,61 → 23,99 |
| `get_procedure`: опечатка в модуле | 57,49 → 14,52 | 57,71 → 14,30 |
| `get_callers` | 11,72 → 7,91 | 10,77 → 6,86 |
Первый подробный запрос подготавливает индекс принадлежности объектов;
его время в этой паре прогонов выросло. Из 12 строк измерены 11;
`search_syntax` остался `not_checked`, поскольку справка на стенд не
загружалась. Отдельная задержка карточки XDTO и расширений не измерялась.
Проверка 20 синтетических ответов побайтна; на реальных данных совпали
четыре состояния индексов и проверенные ответы поиска и вызывающих процедур.
Прогон идёт без сети, с прогретым файловым кэшем; p95 не оценивался.
```bash
.venv/bin/python tools/lab/measure_generation_verify.py --base-archive __data/zup/ZUP.zip \
--extension-archive "__data/zup/ZUPext1 (2).zip" --extension-archive "__data/zup/ZUPext2 (2).zip" \
--tool-latency --timeout-seconds 900 --report latency-zup.json
```
Память нового графа базовой конфигурации ЗУП проверена отдельно 2026-10-24,
по одному прогону до/после, код до изменения — `f547aee`:
| Метрика `tracemalloc` | До | После |
|---|---:|---:|
| Удерживаемое приращение после GC, байт | 19 577 054 | 6 725 946 |
| Пиковое приращение при построении, байт | 19 578 406 | 19 578 406 |
| Построение при активном tracing, с | 0,526 | 0,600 |
Конфигурация загружена до измерения; новый граф остаётся жив при GC.
Все 44 940 рёбер, индексы смежности и unresolved совпали для 17 897 объектов.
Это приращение Python-выделений нового экземпляра, а не RSS или память
контейнера; пиковое потребление в этом прогоне не уменьшилось.
```bash
.venv/bin/python tools/lab/measure_generation_verify.py --base-archive __data/zup/ZUP.zip \
--extension-archive "__data/zup/ZUPext1 (2).zip" --extension-archive "__data/zup/ZUPext2 (2).zip" \
--graph-memory --timeout-seconds 900 --report graph-zup.json
```
Готовый неподтверждённый preview измеряется через ASGI GET:
`.venv/bin/python tools/lab/measure_intake_preview.py --base-archive incoming/configuration.zip --repeat 2 --timeout-seconds 900 --report preview-perf.json`.
Измеритель готовит Source B во временных данных и вызывает настоящий
`GET /api/v1/sources/intake` через локальный TestClient. Подтверждение
публикации не выполняется. `--repeat` задаёт число GET (не меньше двух),
`--timeout-seconds` — общий предел вместе с подготовкой и SHA (900 с).
`--report` создаёт только новый файл; итоговый JSON также идёт в stdout,
прогресс — в stderr. Код выхода `0` означает полный результат, `2` —
ошибку или неполный проход. Отчёт содержит время, счётчики чтения payload,
семантический SHA preview, контроль исходника и кода, результат уборки.
Собственные процессы и временные данные убираются и при таймауте.
Файловый кэш прогрет контрольным SHA и подготовкой; холодный диск не измеряется.
Замер 2026-10-24 на ЗУП, по одному прогону до/после (код до — `a7f004b`,
одинаковый измеритель):
| Этап | До, с | После, с |
|---|---:|---:|
| Подготовка preview | 52,660 | 53,771 |
| GET 1 | 3,061 | 0,648 |
| GET 2 | 3,055 | 0,662 |
На каждом GET вызовы `load_layer_payload` сократились с 6 до 0,
`configuration_from_base_layer` — с 1 до 0. Семантический SHA preview,
16 185 members / 491 652 819 байт и SHA исходника совпали до/после;
preview остался неподтверждённым. ZIP подключён как локальный источник,
поэтому GET включает и его обнаружение. Измеряется обработка ASGI в процессе,
после подготовки и контрольного SHA, без оценки сети, холодного диска и p95.
```bash
.venv/bin/python tools/lab/measure_intake_preview.py --base-archive __data/zup/ZUP.zip \
--repeat 2 --timeout-seconds 900
```
Отдельную загрузку ZIP из браузера измеряет
`.venv/bin/python tools/lab/measure_intake_upload.py --archive incoming/configuration.zip --timeout-seconds 900 --report upload-perf.json`.
`--archive` обязателен и указывает ZIP основной конфигурации. Измеритель
передаёт файл потоком в `POST /api/v1/sources/intake/upload` через локальный
ASGI, затем дважды открывает принятый ZIP. Подготовка preview и публикация
не выполняются. Счётчики отдельно показывают записи multipart spool и
staging, полные SHA-256 и повторное использование SHA. Контроль исходника
и кода выполняется вне этих счётчиков. JSON содержит времена, размеры,
семантические контрольные суммы кандидата и probe с явным списком
исключённых непостоянных полей, результат уборки процессов и данных.
`--timeout-seconds` ограничивает весь проход (по умолчанию 900 с),
`--report` создаёт только новый файл. Итоговый JSON выводится в stdout,
прогресс — в stderr; коды выхода: `0` — полный результат, `2` — ошибка или
неполный проход. Временные данные и дочерний процесс удаляются при ошибке
и таймауте. Это обработка ASGI с прогретым файловым кэшем и накладными
расходами счётчиков; сеть, RSS, физические операции диска и холодный диск не измеряются.
Замер 2026-10-24, по одному прогону до/после на двух согласованных ZIP;
код до изменения — `164c0bc`, измеритель одинаковый. Для каждого ZIP
выполнена указанная выше команда с его путём в `--archive`;
имена источников обезличены:
| Размер ZIP, байт | POST, с | Записано тела, байт | Полных SHA при POST |
|---:|---:|---:|---:|
| 27 409 575 | 0,209 → 0,134 | 54 819 150 → 27 409 575 | 2 → 1 |
| 204 508 961 | 1,133 → 0,707 | 409 017 922 → 204 508 961 | 2 → 1 |
При каждом повторном открытии число полных SHA сократилось с 1 до 0;
чтение центрального каталога ZIP сохранилось. Кандидат, probe и схема
ответов совпали до/после; загрузка не создала job или активное поколение.
Исходники не изменились, временные данные и процессы измерителя удалены.
Перед обновлением формата данных:
`.venv/bin/python tools/lab/find_legacy_generations.py --data data`.
Команда только читает активные поколения через `GenerationBundleStore`:
реестр, манифесты и структурные слои; архивы и код не разбирает.
Один JSON содержит полноту проверки, найденные старые поколения,
строки снятых видов источников и ошибки. Код выхода `0` означает полный
проход без старых данных, `1` — старые данные найдены, `2` — проверка неполна
или аргументы неверны. Найденные конфигурации сначала перезагрузите теми же
архивами в прежнем сервере и повторите проверку до кода `0`;
[подробности](docs/operations.md#структура-каталога).
Снимок памяти явно выбранного контейнера:
`.venv/bin/python tools/lab/measure_container_memory.py --mode observe --container mcp1c-audit-memory --timeout 30`.
`observe` читает cgroup `memory.current`/`memory.peak`, RSS/HWM процесса PID1,
состояние контейнера и `docker stats`; данные и кэш не нужны. Пик cgroup
относится ко всему времени жизни контейнера, поэтому профиль нагрузки
проверяется отдельно. Ошибка даёт один JSON с `completed:false`, без ложного
нулевого пика. Режимы `cold`/`warm` того же скрипта требуют `--data PATH`,
поддерживают `--timeout` и `--poll-interval` и управляют запуском контейнера
`mcp1c`; `--container` доступен только в `observe`.
Замер 2026-10-23 на отдельном контейнере с копией текущих данных и полной
загрузкой «Розницы» с расширением: cgroup peak **3 025 649 664 байта**,
событий ограничения памяти/OOM — 0, оба подтверждения выполнили загрузку.
Метрика снята командой
`.venv/bin/python tools/lab/measure_container_memory.py --mode observe --container mcp1c-audit-stand --timeout 30`
после этой нагрузки. В Compose задан `mem_limit: 7564124160` — точный пик
×2,5 (около 7,04 ГиБ), и `pids_limit: 256`. Запас относится к измеренному
набору источников; для более крупного набора повторите замер на отдельном
контейнере. cgroup учитывает все процессы и файловый кэш; PID1 при
`init: true` показывает только init и не заменяет эту метрику.
Повторный замер 2026-10-26 на образе ветки с теми же входами, тестовым
пределом памяти 4 ГиБ (Docker VM 8,3 ГБ не вмещает предел 7,56 ГБ рядом с
работающими контейнерами) и `--pids-limit 256`, как в Compose: пик cgroup
**3 029 372 928 байт**, событий ограничения памяти и OOM — 0; пик процессов
cgroup `pids.peak` — **28 из 256**, событий `pids max` — 0. Снимок
`observe` дополнен чтением `pids.current`/`pids.peak`/`pids.max`.
События обработчиков формы группируются при первом обращении и
переиспользуются для её оглавления и карточек процедур. Индекс форм удерживает
1 последнюю группировку, другая форма вытесняет её. Кэш не содержит текста
модуля и не сохраняется на диск; выдаваемый состав формы можно менять,
не изменяя последующие ответы сервера.
Чтение BSL ограничено 17 МиБ исходных байтов до декодирования, включая
сохранённые исторические файлы; запись `module` внутри V8-контейнера формы
ограничена отдельно — 883 773 байтами (см. пределы приёма выше). Потоковая
распаковка останавливается при превышении предела; несжатая запись также
читается ограниченными блоками. Отказ имеет категорию `budget_exceeded`.
Остальные записи и внешний контейнер сохраняют общие бюджеты V8;
скомпилированный `.Module` остаётся без доступного исходника.
Предел скачивания полного нормализованного исходника — отдельные 16 МиБ.
Замер встроенных текстов (2026-10-03):
`PYTHONPATH=src .venv/bin/python tools/lab/measure_module_containers.py --archives data/incoming`;
обычные файлы измеряет приведённый выше `measure_backlog_costs.py`.
Параметры, порядок вызовов, пагинация и ограничения каждого инструмента:
[полное описание MCP-инструментов](docs/tools.md).
Постоянное read-only ядро дополняется подключаемыми capability-модулями. На экране **«Дополнительные модули»** можно
включить общую справку, инструменты ролей и скачивание полного модуля.
Сохраните выбор и перезапустите сервер; отключённые модули не публикуют свои
инструменты в MCP. Для скачивания исходника задайте `MCP1C_PUBLIC_BASE_URL`
с адресом сервера, доступным агенту. Без него ссылка не выдаётся.
Ролевые инструменты показывают объявленные права; фактический доступ
пользователя по совокупности ролей и значений RLS они не вычисляют.
Настройки, API и измеренная стоимость контекста модулей:
[руководство эксплуатации](docs/operations.md#внутренние-capability-модули).
## Skills
Skills устанавливаются в клиентский агент отдельно от MCP-сервера:
| Skill | Назначение |
|---|---|
| [bslfmt](skills/bslfmt/SKILL.md) | Форматирование файла или полного метода BSL с сохранением комментариев. |
| [bsl-change-review](skills/bsl-change-review/SKILL.md) | Визуальное ревью или инструкция ручного внесения изменений. |
| [1c-form-creator](skills/1c-form-creator/SKILL.md) | Создание, изменение и проверка управляемых форм. |
| [1c-metadata-creator](skills/1c-metadata-creator/SKILL.md) | Сборка объекта метаданных с формой или без неё. |
Формы и метаданные создаются локальными скриптами, исходники остаются на клиенте.
Эти операции не публикуются как MCP-инструменты.
Для этих скриптов нужен Python 3.12+. Сборка проверяет структуру файлов;
конкретный BSL-код компилируется и проверяется в целевой версии 1С.
Установка, обновление и команды — в [каталоге skills](skills/README.md).
## Источники данных
| Источник | Откуда берётся | Что будет без него |
|---|---|---|
| Структура конфигурации | обработка из `exporter-1c/` | нет объектов, реквизитов и графа |
| Код конфигурации | выгрузка конфигурации в файлы | нет процедур основной реализации |
| Слой расширения | отдельная файловая выгрузка расширения с явно выбранным родителем | нет собственных объектов, кода, форм, ролей и проверяемых borrowed overlays этого расширения |
| Справка платформы | `shcntx_ru.hbk` установленной 1С | нет методов, свойств и событий платформы |
| Общая справка | отдельная каноническая SQLite schema v1 | нет `search_reference` и `get_reference`; остальные инструменты работают |
| Объявленные права ролей | role snapshot полной файловой выгрузки | нет данных прав для инструментов и страницы `/roles`; структура и код работают |
| Локальный словарь | `data/dictionary.json` | нет терминологии конкретной установки |
Конфигурации и справки платформы загружаются из ваших файлов; в репозитории их
нет. Необязательная общая справка поставляется подписанным read-only артефактом.
Разобранный индекс справки платформы заменяется атомарно после синхронизации
нового файла; затем синхронизируется его каталог. При отказе синхронизации
файла прежний читаемый индекс сохраняется.
Подробное происхождение данных: [data-sources.md](docs/data-sources.md).
## CLI и установка без Docker
CLI помогает управлять источниками, словарём, общей справкой и замерами поиска:
`python -m mcp1c.cli`, `python -m mcp1c.server`, `python -m mcp1c.bench`.
Полные списки команд, флагов и воспроизводимые примеры:
[руководство эксплуатации](docs/operations.md).
Установка без Docker и `stdio`: [installation.md](docs/installation.md#запуск-без-docker).
## Данные и доступ
`data/` хранит состояние установки и монтируется отдельно от образа. Сохраняйте
этот каталог при обновлениях. В официальном образе обязательные разные токены
разделяют чтение и администрирование; `.env` и реальные данные не публикуются в Git.
При старте и перезагрузке владелец каталога убирает брошенные
`generations/.staging-*` после восстановления совместимого реестра.
Оставшийся журнал восстановления (WAL) откладывает эту уборку; живые
подготовленные поколения защищены и до записи WAL. Гость уборку не выполняет.
Прямой HTTP передаёт токены без шифрования — для внешнего доступа используйте
HTTPS по [инструкции](docs/installation.md#9-удалённый-сервер-через-https).
После записи реестра через CLI сервер перечитывает его перед своей записью,
включая подтверждение загрузки без изменений. Неустранимый конфликт
при подтверждении intake возвращает `409`; порядок работы CLI описан
в [руководстве эксплуатации](docs/operations.md).
Параллельная регистрация источников сохраняет работоспособность уборки кэша
и разобранных справок: обход использует согласованные снимки реестра.
Параллельные проверки `incoming/` внутри одного серверного процесса разделяют
один сканер на каталог данных, чтобы состояние проверок обновлялось согласованно.
В режиме `local` проверка `Host`/`Origin` включена всегда: разрешены loopback,
`host.docker.internal`, конкретный адрес публикации, публичный URL и явный
список `MCP1C_ALLOWED_HOSTS`. В `http` проверка включается конкретной
публикацией или публичным URL/списком; в `https-proxy` — публичным URL/списком.
При отключённой проверке сервер предупреждает. Без `API_TOKEN` или на
loopback проверка включена при любом режиме; открытое чтение в сети требует
явного `--insecure-open-read`.
Compose передаёт `MCP1C_PUBLISHED_ADDRESS` из `MCP1C_BIND_ADDRESS` специально
для этой проверки; порт адреса публикации не ограничивается. При bare-запуске
без этой переменной используется `--host`. Адреса доверенных HTTPS proxy
задаёт `MCP1C_TRUSTED_PROXIES`.
При HTTP bind вне loopback любой заданный `API_TOKEN` или `ADMIN_TOKEN`
проверяется на стойкость и без `--require-tokens`: нужны 32+ печатных ASCII
символа без пробелов и признаков предсказуемости. `ADMIN_TOKEN` без этого
флага необязателен; сам флаг требует оба разных стойких токена.
`--insecure-open-read` разрешает пустой `API_TOKEN`, но не заданный слабый
токен. Loopback и `stdio` без `--require-tokens` сохраняют прежние правила.
Сетевой `https-proxy` с пустым `MCP1C_TRUSTED_PROXIES` выводит предупреждение.
Изменения версии платформы используют общую административную проверку:
без `ADMIN_TOKEN` API отвечает `404`, без прав администратора или при чужом
источнике запроса — `403`. Дашборд показывает причину отказа.
Подробно: [переменные окружения](docs/installation.md#2-подготовить-окружение).
## Документация
| Задача | Руководство |
|---|---|
| Подробная установка, обновление, права и диагностика | [installation.md](docs/installation.md) |
| Загрузка конфигураций, расширений и справки | [configuration-loading.md](docs/configuration-loading.md) |
| Подключение MCP-клиентов | [clients.md](docs/clients.md) |
| Все инструменты и сценарии вызовов | [tools.md](docs/tools.md) |
| CLI, настройки и обслуживание | [operations.md](docs/operations.md) |
| Источники и схема выгрузки | [data-sources.md](docs/data-sources.md), [schema-v1.md](docs/schema-v1.md) |
| Дашборд | [dashboard/README.md](dashboard/README.md) |
| Архитектура и разработка | [architecture.md](docs/architecture.md), [CONTRIBUTING.md](CONTRIBUTING.md) |
| Контракты дашборда и обработки кода | [dashboard-design.md](docs/dashboard-design.md), [modules-intake-design.md](docs/modules-intake-design.md), [modules-provider-design.md](docs/modules-provider-design.md) |
| Типовые события процедур | [standard-procedure-intents.md](docs/standard-procedure-intents.md) |
| История изменений и безопасность | [CHANGELOG.md](CHANGELOG.md), [SECURITY.md](SECURITY.md) |
Переход с предыдущих версий: [обновление установки](docs/installation.md#переход-на-новую-версию).
## Помочь проекту реальным примером
Если ответ сервера неверен или неполон, создайте
[issue](https://github.com/AzeevAN/mcp-1c/issues/new): укажите, какую задачу вы решали,
что ожидали получить и что получили. Перед публикацией обезличьте пример.
Не прикладывайте содержимое каталога `data/`, реальные имена и токены.
Полный формат примера описан в [CONTRIBUTING.md](CONTRIBUTING.md).
## Лицензия
Apache-2.0: [LICENSE](LICENSE) и [NOTICE](NOTICE). Проект не связан с ООО «1С».
В репозиторий не входят выгрузки конкретных внедрений и исходные справки 1С.
TDQS
Scored across 10 tools
The set is organized around a deliberate search→detail pattern (search_objects→get_object, search_syntax→get_syntax, search_procedures→get_procedure), and each description explicitly states what the search step omits and why the detail step is mandatory. The three search_* tools target clearly separate domains (metadata objects, platform API, module code), and get_related (dependency graph) vs get_callers (call sites) are distinguished by scope. No two tools appear to do the same thing.
All ten tools follow a strict snake_case verb_noun convention (list_configurations, search_objects, get_object, compare_configurations, get_callers). Verb choice is semantically regular: search_* returns candidates, get_* returns detail, compare_* diffs, list_* enumerates.
Ten tools is well within the ideal range, and each one covers a distinct slice of the domain: configuration discovery, metadata exploration, platform syntax reference, and code navigation. Nothing looks redundant or bolted on.
The surface covers discovery, metadata structure, relations, cross-configuration diffing, platform API documentation, procedure search, procedure reading, and caller lookup — a coherent lifecycle for static analysis. Minor gaps remain: compare_configurations only diffs a single object's attribute names (no full-object or type/TabularSection diff), and there is no tool to validate or execute a constructed query, so agents must verify queries outside the server.