Skip to main content
Glama

MCP-сервер структуры конфигураций 1С

Справочник по метаданным нескольких конфигураций 1С, по синтаксису платформы и по языку запросов — для агентов, пишущих код на BSL. Отдаёт минимально достаточный срез: разрешение человеческой формулировки в точное имя объекта, структуру объекта на нужном уровне детализации, его связи, описание методов платформы с учётом версии конкретной конфигурации и конструкции языка запросов.

Не заменяет grep по исходникам проекта: код живёт в файлах, сервер отвечает за медленно меняющееся знание о конфигурации. Граница зафиксирована в docs/data-sources.md.

Состояние — на 2026-08-18

Этап

Статус

Обработка выгрузки для 1С

✅ 20 видов метаданных, 8.3.5 и 8.3.23, XML и JSON

Формат выгрузки

schema v1

Загрузчик, модель, граф связей, рендер

✅ 5 конфигураций, 20 522 объекта, 322 тыс. рёбер

Справка платформы

✅ слитый индекс трёх версий, 25 691 элемент, границы since/until

Язык запросов

shquery_ru.hbk, 127 страниц, отдельный источник без версий

Поиск

✅ 97,1% справка, 94,7% язык запросов, 90,5% метаданные — см. «Измерено»

Виртуальные таблицы регистров

✅ готовые имена полей запроса (КоличествоОстаток)

Таблица замен для старых платформ

✅ недоступное не просто запрещено, а заменено рецептом

Реестр источников, сопоставление версий

MCP-сервер, 7 инструментов

✅ streamable-http и stdio

Docker

✅ один контейнер, 354 МБ

Кэш поисковых индексов

✅ 12 МБ, поднимается вместо повторного разбора

Стенд замеров

python -m mcp1c.bench, P@k, MRR, отрыв, сверка пометок

Тесты

pytest, 371

Дашборд

✅ реестр, источники, прогон запросов, граф связей, карточки, словарь

Авторизация

API_TOKEN на чтение, ADMIN_TOKEN на запись

Индекс модулей из .cf

Содержание

  1. Запуск — Docker, дашборд, граф связей, без Docker

  2. Подключение агентакак работает MCP, если не подключается, токен, конфиги клиентов: Claude Code, Codex CLI, Cursor, VS Code, Qwen Code, stdio

  3. Инструментыпорядок вызовов, источники, язык запросов, версии платформы, слияние справок, замены

  4. Управление данными — источники, словарь и поисковые ключи, CLI, стенд замеров, сервер вручную, откуда брать данные

  5. Как устроено — модули, замеры, тесты

  6. Безопасность — токены, что открыто без них

  7. Документы


1. Запуск

Docker (основной способ)

# 1. Положить исходные данные
mkdir -p data/bootstrap
cp ВыгрузкаКонфигурации.zip                     data/bootstrap/
cp /opt/1cv8/8.3.27.2130/shcntx_ru.hbk          data/bootstrap/

# 2. Поднять
docker compose up -d --build

# 3. Проверить
curl http://localhost:5001/health
{"status":"ok",
 "configurations_total":2,
 "syntax_loaded":true,
 "query_language_loaded":true,
 "configurations":["РозницаДляКазахстана","ЮвелирныйТорговыйДомДляКазахстана"],
 "syntax":["8.3.5.1570","8.3.23.1997","8.3.27"]}

Справка платформы и язык запросов — разные источники и разные поля: syntax_loaded относится только к первой, syntax перечисляет версии загруженных справок. Имена конфигураций и версии справок отдаются лишь запросу, прошедшему проверку на чтение; без токена остаются status, счётчик и два флага.

Всё, что лежит в data/bootstrap/, индексируется при старте: *.zip — выгрузки конфигураций, *.hbk — справка платформы. Повторно один и тот же файл не разбирается: сверка идёт по хешу.

Каталог ./data монтируется в контейнер как /data. Внутри него сервер держит исходники, индексы, кэш и registry.json; пути в реестре относительные, поэтому каталог можно переносить между машиной разработчика и контейнером.

data/ целиком вне git — это том, а не часть репозитория. Переносится копированием каталога. Поэтому после клонирования справку нужно положить самому: репозиторий её не содержит и содержать не может, это контент фирмы «1С».

После изменения кода контейнер нужно пересоздать, а не перезапустить:

docker compose up -d --build --force-recreate

restart поднимет прежний контейнер на прежнем образе, и правки не применятся.

Про порт. Наружу сервер отдан на 5001, внутри контейнера слушает 8000 — проброс 5001:8000 в docker-compose.yml. Все адреса в этом файле внешние, то есть 5001. Занят другим сервисом — поменяйте левую часть проброса, правую не трогайте: на неё завязаны EXPOSE и healthcheck образа.

Дашборд

http://localhost:5001/ — шесть страниц:

Страница

Что там

Обзор

что загружено: объекты, связи, версия платформы, предупреждения из манифестов

Источники

список загруженного, загрузка .zip и .hbk, удаление

Запросы

прогон списка формулировок с оценкой и причиной ранжирования

Связи

граф окрестности объекта картинкой

Карточка

состав объекта или описание элемента платформы — то же, что видит агент

Словарь

правила с происхождением; завести псевдоним или группу синонимов

Связи — граф объекта

/graph рисует окрестность объекта: цвет по виду, стрелка по направлению ссылки, подпись ребра по наведению. Клик по узлу строит граф вокруг него, перетаскивание двигает, колесо масштабирует. Предел соседей выбирается на странице (15…400), обрезка называется числом — «показано 30 из 102».

Отвечает на «что сломается, если тронуть»: регистр, окружённый оранжевыми документами, сразу говорит, кто его двигает.

Глубина всегда один шаг. На двух шагах от ходового справочника достаётся тысяча объектов, на трёх — треть конфигурации; дальше связь идёт через общие механизмы вроде дополнительных реквизитов, которые соединяют почти всё со всем. Отсечь их порогом по числу связей нельзя: у такого узла их 34, а у осмысленного Справочник.Пользователи — 323. Поэтому раскрывает узлы человек, а не эвристика — он видит, куда идти не стоит.

У агента такого инструмента нет намеренно. Разбор и условия возврата — в docs/TASKBOARD.md, раздел «Отложено».

Промах лечится не выходя из браузера: на странице запросов у каждой фразы есть ссылка «не то — завести псевдоним», она ведёт в словарь с уже подставленной фразой. Правка действует сразу — индексы не пересобираются, перезапуск не нужен.

Чтение закрывается API_TOKEN, запись — ADMIN_TOKEN. Пока API_TOKEN не задан, читать может кто угодно, кто дотянется до адреса, — включая структуру конфигураций и доработки. Для localhost это приемлемо, для сервера в сети нет.

Токены разделены потому, что токен чтения лежит в конфиге каждого MCP-клиента и утекает вместе с ним; прав удалять источники у агента быть не должно. Админский токен годится и за токен чтения — держать два заголовка не надо.

// .mcp.json — как клиент передаёт токен
{"mcpServers": {"1c": {"type": "http", "url": "http://localhost:5001/mcp",
                       "headers": {"X-Api-Token": "..."}}}}

Только ASCII: заголовки HTTP кодируются latin-1, кириллица в них не дойдёт. /health остаётся открытым для healthcheck, но имена конфигураций отдаёт только по токену.

Загрузка, удаление и правка словаря требуют ADMIN_TOKEN — того же, что у /admin/reload; без него этих ручек не существует, а не «они закрыты». Токен вводится один раз в форме, в браузер уходит не он, а идентификатор сессии.

Задаётся через .env рядом с docker-compose.yml — шаблон со всеми переменными лежит в .env.example:

cp .env.example .env
python3 -c "import secrets; print(secrets.token_urlsafe(32))"   # значение
docker compose up -d --force-recreate

Имя в результатах — ссылка на карточку: у объекта это реквизиты с типами, табличные части и движения, у элемента платформы — сигнатура, параметры, доступность и версия появления. Тот же текст, что получает агент, с переключателем brief / fields / full. У реквизита своей карточки нет — ссылка ведёт на объект-владелец.

Страница «Запросы» отвечает на вопрос «почему сервер выдал именно это»: рядом с каждым попаданием стоит причина — точное совпадение, псевдоним из словаря, все слова запроса. По ней видно, чем лечить промах — синонимом, псевдонимом или весом.

Разбор справки занимает несколько секунд: страница ответит после него, но MCP-клиентов это не задерживает — индексация уходит в отдельный поток.

Без Docker

python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
PYTHONPATH=src .venv/bin/python -m mcp1c.server --host 0.0.0.0 --port 5001

2. Подключение агента

Сервер реализует протокол MCP штатными транспортами официального SDK, поэтому подходит любому MCP-клиенту. Никаких обёрток вокруг HTTP не требуется.

Транспорт

Когда

Адрес

streamable-http

сервер в Docker или на отдельной машине

http://адрес:5001/mcp

stdio

клиент сам запускает процесс локально

sse

только для старых клиентов

--transport sse

Оба основных транспорта проверены официальным клиентом MCP: рукопожатие initialize, tools/list, tools/call, протокол 2025-11-25.

Как это работает

Полезно понимать до того, как что-то не подключится. Адрес один — /mcp, ручки по инструменту не бывает; какой инструмент вызывается, написано в теле запроса, а не в пути.

Дальше — две разные механики, и путать их не стоит:

Описания инструментов

Данные

Когда

один раз, при подключении

по каждому вызову

Кто начинает

клиент, сам, без участия модели

модель, по решению

Метод

POST initialize, затем POST tools/list

POST tools/call

Куда попадает

системный промпт модели

тело разговора

Цена

разово, лежит весь сеанс

за каждый вызов

При подключении клиент делает POST initialize — сервер отвечает названием, версией и текстом instructions, а в заголовке возвращает mcp-session-id. Затем POST tools/list отдаёт инструменты разом: имя, описание, JSON-схему параметров. Всё это кладётся в контекст модели до того, как человек напечатал первое слово. Модель не ходит за описанием, когда оно понадобится, — оно уже у неё.

Отсюда следствие, важное при правке описаний: они занимают место в окне весь сеанс, независимо от того, вызовет модель хоть один инструмент или ни одного.

Инструментов всегда семь, независимо от того, что загружено. Набор — это контракт, а не переменная: инструменты связаны между собой, и на рабочем сервере загружены все три источника — конфигурации, справка платформы, язык запросов. Контракт tools/list плюс instructionsоколо 3 900 токенов, и эта цифра не зависит от состояния реестра.

Отсюда прямое следствие, которое надо знать заранее: если источник не загружен, вы всё равно платите за его инструменты. Без справки платформы search_syntax и get_syntax лежат в контексте и стоят 1 185 токенов, отвечая «справка не подключена»; compare_configurations при одной конфигурации — 262 токена ради ответа «нужно минимум две». Лечится это загрузкой источника, а не отбором инструментов: отбор пробовали 2026-08-19 и отменили — подробности и цифры в «Отложено».

Описания поэтому пишутся плотно, а подробности уезжают в выдачу самого инструмента: за неё платят только когда она нужна.

GET /mcp — не «неправильный POST», а третий метод на том же адресе: он открывает поток сообщений от сервера к клиенту и требует уже полученный mcp-session-id. DELETE /mcp закрывает сессию.

Если клиент не подключается

Код ответа в логе (docker logs -f mcp1c) называет причину:

Код

Что не так

406

клиент не шлёт Accept: application/json, text/event-stream — нужны оба типа

400 Missing session ID

клиент не вернул заголовок mcp-session-id, полученный при initialize

400 на первом же GET /mcp

клиент начал рукопожатие с GET — он говорит старым транспортом HTTP+SSE, а на этом адресе streamable-http

404 на /sse

то же самое: старый транспорт наружу не выведен

401

не передан X-Api-Token при заданном API_TOKEN

в логе пусто

клиент не отправил запрос вовсе — дело в его конфиге, до сервера не дошло

Живой случай: Qwen Code не подключался, потому что в его конфиге стоял ключ url — в семействе Gemini CLI (Qwen наследует формат) он означает старый SSE-транспорт, и клиент начинал с GET, получая 400. С httpUrl — то есть streamable-http — подключение проходит сразу.

Токен: что добавить в настройки клиента

Если на сервере задан API_TOKEN, каждый клиент обязан слать его заголовком. Без заголовка /mcp отвечает 401, и агент просто не увидит инструментов.

Годится любой из двух заголовков — сервер принимает оба:

X-Api-Token: <токен>
Authorization: Bearer <токен>

Три вещи, о которые спотыкаются:

  • Только ASCII. Заголовки HTTP кодируются latin-1, кириллический токен через них не дойдёт. Генерировать так: python3 -c "import secrets; print(secrets.token_urlsafe(32))".

  • В клиент кладётся API_TOKEN, а не ADMIN_TOKEN. Админский тоже примут, но конфиг клиента уезжает в git и в бэкапы: утёкший токен чтения даёт просмотр, утёкший админский — право снести источники.

  • stdio токена не требует вовсе. Там клиент сам запускает процесс, сеть не участвует и проверять нечего. Если клиент не умеет задавать заголовки — это рабочий обходной путь.

Проверить, что сервер видит токен, до всякой настройки клиента:

curl -s -o /dev/null -w '%{http_code}\n' -X POST \
  -H 'x-api-token: ВАШ_ТОКЕН' \
  -H 'content-type: application/json' \
  -H 'accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"1"}}}' \
  http://localhost:5001/mcp

200 — токен принят. 401 — не тот токен или заголовок не дошёл.

Как не закоммитить секрет

.mcp.json и подобные файлы обычно лежат в репозитории. Варианты:

  1. Подстановка переменной — если клиент это умеет (Claude Code умеет): "X-Api-Token": "${MCP1C_API_TOKEN}", а сама переменная в ~/.zshrc. В git уезжает имя переменной, не значение.

  2. Вынести файл из-под git: git rm --cached .mcp.json && echo ".mcp.json" >> .gitignore.

  3. Держать настройку не в проекте, а в пользовательском конфиге клиента — тогда репозиторий вообще ни при чём.

Claude Code

Файл .mcp.json в корне проекта:

{
  "mcpServers": {
    "1c": {
      "type": "http",
      "url": "http://localhost:5001/mcp",
      "headers": { "X-Api-Token": "${MCP1C_API_TOKEN}" }
    }
  }
}

Блок headers нужен, только если на сервере задан API_TOKEN. Значение взято из переменной окружения, чтобы файл можно было держать в репозитории:

echo 'export MCP1C_API_TOKEN=ваш_токен' >> ~/.zshrc && source ~/.zshrc

Либо командой:

claude mcp add --transport http 1c http://localhost:5001/mcp \
  --header "X-Api-Token: $MCP1C_API_TOKEN"

Codex CLI

~/.codex/config.toml или .codex/config.toml в проекте:

[mcp_servers.mcp1c]
url = "http://localhost:5001/mcp"

# Только если задан API_TOKEN. Имя ключа для заголовков у Codex менялось между
# версиями — сверьтесь со своей (`codex --help`, раздел MCP). Не подхватилось —
# используйте stdio, там токен не нужен вовсе.
[mcp_servers.mcp1c.http_headers]
X-Api-Token = "ваш_токен"

Cursor

.cursor/mcp.json:

{
  "mcpServers": {
    "1c": {
      "type": "streamable-http",
      "url": "http://localhost:5001/mcp",
      "headers": { "X-Api-Token": "ваш_токен" }
    }
  }
}

VS Code (Copilot)

.vscode/mcp.json — здесь ключ называется servers:

{
  "servers": {
    "1c": {
      "type": "http",
      "url": "http://localhost:5001/mcp",
      "headers": { "X-Api-Token": "ваш_токен" }
    }
  }
}

Qwen Code

Формат от Gemini CLI, и ключ выбирает транспорт — это единственная тонкость:

{
  "mcpServers": {
    "1c": {
      "httpUrl": "http://localhost:5001/mcp",
      "headers": { "X-Api-Token": "ваш_токен" }
    }
  }
}

httpUrl — streamable-http, наш случай. url в этом формате означает старый SSE-транспорт: клиент начнёт рукопожатие с GET /mcp, получит 400 Missing session ID и не подключится.

Прочие клиенты

Windsurf, Antigravity, Cline, Roo Code, консольные агенты — форма записи та же: тип транспорта, URL и, если задан API_TOKEN, блок заголовков. Различия только в имени файла и в ключе верхнего уровня (mcpServers или servers) — сверьтесь с документацией конкретного клиента.

Клиент не умеет задавать заголовки — не тупик: подключайтесь через stdio, там токен не нужен, потому что нет сети.

Локальный запуск через stdio

Когда клиент должен поднимать сервер сам. Токен здесь не нужен: процесс запускается клиентом, общение идёт через каналы процесса, а не через сеть — проверять нечего и не от кого защищаться.

{
  "mcpServers": {
    "1c": {
      "command": "python3",
      "args": ["-m", "mcp1c.server", "--transport", "stdio", "--data", "/путь/к/data"],
      "env": { "PYTHONPATH": "/путь/к/проекту/src" }
    }
  }
}

3. Инструменты

Набор фиксирован и намеренно мал: каждый инструмент постоянно висит в контексте агента. Новый источник данных обогащает ответы существующих, а не добавляет свои.

Инструмент

Назначение

list_configurations

что загружено, какие провайдеры доступны по каждой конфигурации

search_objects(query, config, kind, limit)

человеческая формулировка → точное имя объекта

get_object(full_name, config, detail)

состав объекта; detail: brief / fields / full

get_related(full_name, config)

движения, ссылки, зависимости — только прямые

compare_configurations(full_name, configs)

один объект в двух конфигурациях

search_syntax(query, config, kind, limit)

поиск по справке платформы и по языку запросов

get_syntax(name, config, detail)

сигнатура, параметры, доступность, версия, замена для старой платформы

config обязателен, когда загружено больше одной конфигурации: сервер намеренно не подставляет её молча — иначе агент напишет код по чужой базе, и об этом никто не узнает.

Одно имя может жить в двух доменах сразу: СтрНайти есть и в платформе (с 8.3.6), и в языке запросов. Тогда get_syntax перечисляет одноимённые с готовым адресом каждого, и повторить вызов можно строкой из выдачи:

get_syntax("СтрНайти")                    → Одноимённых элементов: 2
                                            - `Глобальный контекст.СтрНайти` — Метод, с 8.3.6
                                            - `Запрос.СтрНайти` — Функция запроса
get_syntax("Запрос.СтрНайти")             → карточка функции языка запросов

Квалификатор Запрос. нужен потому, что у элемента языка запросов нет владельца: назвать его через Объект.Член, как платформенный, невозможно.

Порядок вызовов — и что теряется, если его нарушить

list_configurations → search_objects → get_object → search_syntax → get_syntax

Шаг get_object пропускать нельзя. Поиск отдаёт только имена и счётчики; всё, от чего зависит код, живёт в карточке объекта:

  • вид и периодичность регистра. СрезПоследних есть только у периодического регистра сведений, а непериодических 566 из 603;

  • готовые имена полей виртуальных таблиц. В запросе ресурс Количество называется КоличествоОстаток, КоличествоОборот, КоличествоПриход — в конфигураторе таких имён не видно нигде, их порождает платформа;

  • предел субконто, корреспонденция, ресурсы графика — без них поля вида СубконтоДт1 назвать нечем;

  • строки неограниченной длины. Помечены прямо в типе: Строка (неогр. — только через ПОДСТРОКА) против Строка(200). Такое поле нельзя ставить в запрос как есть — платформа не даст его ни сравнить, ни сгруппировать, ни упорядочить. Таких полей от 23% до 38% строковых в живых конфигурациях, поэтому на карточках, где они встречаются (2 474 из 20 522), перед списком полей печатается оговорка с рецептом.

Запрос, написанный сразу после search_objects, выглядит правильным и падает на «поле не найдено». Пример того, что приходит только из get_object:

## Таблицы запроса
- `РегистрНакопления.ТоварыНаСкладах.Остатки`
  измерения: Склад, Номенклатура, Характеристика
  ресурсы: КоличествоОстаток, РезервОстаток

Второй такой же — и он найден живым промахом 2026-08-18. Агент сгруппировал запрос по строке без ограничения длины; данные мы отдали верные, но разница читалась только по отсутствию числа в скобках:

> **Строки неограниченной длины** помечены `(неогр.)`. Платформа не даёт их
> сравнивать, группировать и упорядочивать и не пускает в РАЗЛИЧНЫЕ,
> ОБЪЕДИНИТЬ и агрегатные КОЛИЧЕСТВО, МИНИМУМ, МАКСИМУМ. Ограничивайте
> длину — одинаково в списке выборки и в группировке:
>
>     ПОДСТРОКА(КодСкидки, 1, 100) КАК КодСкидки
>
> Длину подбирайте по смыслу поля: 100 — не универсальное число.

## Реквизиты

- `КодСкидки` — Строка (неогр. — только через ПОДСТРОКА) // Код скидки
- `КодМаркировки` — Строка(200) // Код маркировки

Рецепт стоит и в оговорке, и в самой строке поля, и это не избыточность. Первая редакция печатала оговорку последним абзацем карточки. Живой агент 2026-08-18 вызвал get_object с detail=fields, получил её целиком — и всё равно сгруппировал по такому полю. Оговорка стояла на 721 токен позже строки поля, а решение принимается там, где имя копируют. Тот же урок уже был записан на описаниях инструментов: правило работает там, где его читают, а не там, где его аккуратнее положить.

Каждый запрет проверен: агрегатные — цитата из справки, остальные пять — прогоны на живой базе с записанными текстами ошибок. Справка знает об ограничении только в трёх агрегатных функциях из шести и молчит про группировку, упорядочивание, РАЗЛИЧНЫЕ, ОБЪЕДИНИТЬ и сравнение — то есть агент, честно её прочитавший, узнать об этом не мог. Разбивка по происхождению — в docs/data-sources.md, раздел «Оговорки в карточке».

Перед вызовом функции платформы на старой конфигурации — get_syntax. Недоступное помечается, и там же лежит рецепт замены, если он записан.

Источники независимы

Их три, и каждый подключается отдельно:

Источник

Файл

Что даёт

Без него

Метаданные конфигурации

СтруктураКонфигурации_*.zip

объекты, реквизиты, связи, движения

search_objects и get_object не отвечают

Справка платформы

shcntx_ru.hbk

методы, свойства, сигнатуры, доступность, версии

search_syntax говорит «источник не подключён»

Язык запросов

shquery_ru.hbk

ВЫБРАТЬ, ЛЕВОЕ СОЕДИНЕНИЕ, ИТОГИ ПО, РАЗНОСТЬДАТ

конструкции языка запросов не находятся

Что загружено

Что работает

Всё три

всё

Только конфигурация

метаданные; синтаксис отвечает «источник не подключён»

Только справка

синтаксис без фильтрации по версии, config не нужен

Ничего

list_configurations объясняет, что загрузить

Язык запросов — отдельный источник

shquery_ru.hbk из того же каталога установки платформы. 127 страниц: 52 функции, 67 ключевых слов, 8 статей. Загружается как обычный источник и попадает в тот же поисковый индекс, что справка платформы, — искать отдельным инструментом не нужно, search_syntax находит и то и другое.

Версий в самом файле нет — проверено на всех 129 страницах: ноль упоминаний «8.3.x» и «начиная с версии». Но язык запросов меняется: релиз 8.3.20 добавил 25 функций, среди них СтрНайти, Лев, Прав, ВРег, НРег, СтрЗаменить, Окр, Цел и вся тригонометрия.

Взять версию неоткуда: справка платформы функций языка запросов не описывает вовсе (ПОДСТРОКА — ноль совпадений на 25 511 элементов). Поэтому версии задаёт курируемая таблица query_versions.py — по списку 1С «Функции, добавленные в язык запросов начиная с релиза 8.3.20». Остальным 27 функциям версия не приписывается: они были всегда.

Дальше работает обычный фильтр: конфигурация на 8.3.5 этих функций не увидит, на 8.3.23 увидит.

Таблица проверяется данными — сравнением двух справок разных платформ. Чего нет в старой и есть в новой, то появилось между ними, и у этого обязана стоять версия:

python3 tools/lab/compare_query_help.py <старая.hbk> <новая.hbk>

Прогон 2026-08-19, 8.3.5.1570 против текущей: появилось 29, покрыто 29, ложных срабатываний 0. Ложное срабатывание — худшая из ошибок: элемент, который был уже в старой справке, но помечен версией, спрячется от конфигурации, где он есть.

Экземпляр один на сервер: повторная загрузка заменяет прежний.

Таблицы страниц показываются, но не ищутся. В этой справке ячейки таблиц размечены абзацами внутри <TD>, и без отдельного разбора карточка печатала таблицу столбцом значений: «Товар / Количество / Номер / Сантехника / 104 / …» два десятка строк подряд. Теперь таблицы разбираются отдельным полем — 51 таблица на 31 странице из 127 — и печатаются на своих местах в тексте: страница с двумя примерами показывает каждый результат под своим примером. В поисковый индекс содержимое таблиц не попадает.

Таблицы в этой справке двух разных природ, и разбираются они по-разному:

Что

Сколько

Как выглядит в карточке

таблица данных — результат запроса-примера

51 на 31 странице

markdown-таблицей

рисованная синтаксическая диаграмма — грамматика конструкции

21 на 17 страницах

лесенкой с отступом по уровню ветвления

Различаются по разметке, а не по классу CSS: class=SimplyTable стоит не на всех — 7 настоящих таблиц идут без него. Признак — геометрия: у таблицы данных все строки одной ширины, у диаграммы ширины рваные и есть ячейки из одной вертикальной черты (это нарисованная линия, а не значение).

Испорченная разметка называется вслух. Страница с незакрытой <TABLE> разбирается без таблиц, но не теряется, и её имя попадает в предупреждения источника: строкой в выводе загрузки (mcp1c.cli reg-add) и отдельной строкой на странице «Источники» дашборда. Молча отдать карточку беднее обычного нельзя: от справки, в которой этого просто нет, такое неотличимо.

Половина имён совпадает с именами платформы (57 из 127) — ГОД, МЕСЯЦ, ПРЕДСТАВЛЕНИЕ есть и там и там. Чтобы вопрос про запрос не уводил к методу платформы, обороты вроде «в запросе», «в тексте запроса», «в выборке» дают элементам языка запросов мягкий подъём. Мягкий намеренно: при уверенном отрыве платформенный элемент остаётся первым — «как задать параметр в запросе» может быть и про Запрос.УстановитьПараметр.

Параметр config обязателен, если загружено больше одной конфигурации. По умолчанию ничего не подставляется: молчаливый выбор приводит к тому, что агент пишет код по чужой конфигурации, и этого никто не замечает.

Ответ зависит от версии платформы

Один и тот же вызов, две конфигурации:

get_syntax("СтрШаблон", config="Розница")          → 8.3.23
# Метод: Глобальный контекст.СтрШаблон
с версии платформы 8.3.6
Доступность: ТонкийКлиент, ВебКлиент, Сервер, ТолстыйКлиент, …

get_syntax("СтрШаблон", config="Ювелирный")        → 8.3.5
# `Глобальный контекст.СтрШаблон` недоступен в этой конфигурации
Элемент существует, но появился в 8.3.6, а конфигурация работает на 8.3.5.1570.
Использовать нельзя — код не скомпилируется.

Для платформы 8.3.5 из выдачи убрано 6 539 элементов, для 8.3.23 — 874. Не предупреждением, а фильтрацией: предупреждение агент пропустит, отсутствующий в выдаче метод — нет.

Поле Доступность (сервер / тонкий клиент / веб-клиент / мобильные) читать обязательно: вызов серверного метода из клиентского контекста не компилируется.

Справки нескольких версий сливаются в один индекс

Одна свежая справка на старой конфигурации врёт. Замерено на 8.3.5: 199 элементов сервер объявил бы несуществующими, 117 отдал бы с чужой сигнатурой (ЗаписьXML.ОткрытьФайл на 8.3.5 берёт два параметра, в 8.3.27 — три), 410 — с чужой доступностью. Всё это ошибки компиляции, а не неточности.

Поэтому справки разных версий кладутся рядом и сливаются в один индекс с границами since и until, а ответ собирается под версию конкретной конфигурации. Справок нужно столько, сколько платформ у загруженных конфигураций — две крайние промежуточные не заменяют.

Цена измерена и мала: слияние трёх версий даёт 25 691 ключ против 24 777 у одной, то есть меньше процента. Отдельный контейнер на версию тоже работает и остаётся аварийным путём, но как основной проигран по цифрам — 300–450 МБ и свой адрес на каждую версию.

Сервер сам называет, каких справок не хватает и какие лишние, — в выдаче list_configurations.

Замена вместо запрета

Сказать «функции нет» — половина ответа. Вторая половина — чем её заменить, и из справки она не выводится: пометка об устаревании стоит на 15 страницах из 25 тысяч.

Поэтому есть таблица замен (replacements.py), сейчас 6 записей — строковые функции, появившиеся в 8.3.6. Вместо запрета get_syntax отдаёт рецепт:

get_syntax("СтрРазделить", config="Ювелирный")     → 8.3.5
# `СтрРазделить` недоступна: появилась в 8.3.6

Замена: РазложитьСтрокуВМассивПодстрок(<Строка>, <Разделитель>)
Оговорка: разделитель у `СтрРазделить` — набор символов, каждый из которых
самостоятельный разделитель; у замены это одна строка целиком.

Оговорка обязательна. Замена почти никогда не эквивалентна, и молча подсунуть похожую функцию — хуже, чем не подсказать ничего.

Таблица пополняется по живым случаям, а не вслепую: сочинять обходы для функций, которых никто не спрашивал, смысла нет.


4. Управление данными

Добавить источник

# в Docker
docker compose exec mcp1c python -m mcp1c.cli reg-add /data/bootstrap/Выгрузка.zip --data /data
docker compose exec mcp1c python -m mcp1c.cli reg-add /data/bootstrap/shcntx_ru.hbk --data /data

# без Docker
PYTHONPATH=src python3 -m mcp1c.cli reg-add Выгрузка.zip

Проще: положить файл в data/bootstrap/ — он подхватится при следующем старте.

Применить изменения без перезапуска

Работающий сервер держит реестр в памяти, поэтому после reg-add его нужно подтолкнуть. Либо перезапуск (docker compose restart mcp1c, около 2 секунд), либо админ-ручка:

# включается переменной ADMIN_TOKEN; без неё маршрут отключён
ADMIN_TOKEN=секрет docker compose up -d
curl -X POST -H "x-admin-token: секрет" http://localhost:5001/admin/reload

Словарь: как говорят против того, как названо

Главная сложность поиска — разрыв между словами человека и именами в конфигурации. «Заказ клиента» — а объект называется ЗаказПокупателя. Словарь лежит в data/dictionary.json, правится без пересборки образа.

Два механизма, и они разные.

Синонимы слов — общие для всех конфигураций:

python3 -m mcp1c.cli dict-synonyms клиент покупатель заказчик

Псевдонимы объектов — прямое указание «когда я говорю так, я имею в виду вот эти объекты», вес выше любого текстового совпадения. Два десятка типовых фраз («файлы», «товары», «клиенты», «сотрудники», «задачи») встроены и работают сразу; если объекта в конфигурации нет, псевдоним не применяется. Свои добавляются с привязкой к конфигурации:

python3 -m mcp1c.cli dict-alias "справочник физлиц" \
    Справочник.ФизическиеЛица Справочник.Пользователи \
    --config РозницаДляКазахстана
«справочник физлиц»
    Справочник.ФизическиеЛица     псевдоним из словаря
    Справочник.Пользователи       псевдоним из словаря

Существование объектов проверяется при добавлении — псевдоним на опечатку бесполезен. Посмотреть содержимое: dict-show, удалить: dict-alias «фраза» --remove.

Изменения применяются перезапуском контейнера или POST /admin/reload — пересобирать образ не нужно.

Поисковые ключи языка запросов — третий механизм, и правится он только в коде (search_keys.py, в git с ревью). Разрыв тут другой природы: человек не называет конструкцию чужим словом, а описывает задачу. «Количество дней между двумя датами» против РАЗНОСТЬДАТ, «убрать повторы» против РАЗЛИЧНЫЕ — общих слов ноль, и синоним не поможет, заменять нечего.

Поэтому к 116 страницам из 127 приписаны формулировки, которыми их спрашивают, и попадают в поисковый индекс отдельным полем. В рантайме не весят ничего. Результат на живом наборе: 57,9% → 94,7% первым местом, без регресса на 61 тысяче автоматических запросов.

Ключи сочинены нами, а не выгружены, и отсюда три ограничения:

  • живут отдельным слоем в git, а не приписываются разобранному элементу;

  • в ответ агенту не попадают — ответ по-прежнему собирается только из справки, ключи работают исключительно на попадание в нужную статью;

  • привязаны к страницам по идентификатору, и если справка даст другой набор страниц, расхождение называется при загрузке, а не проявляется молча просевшим поиском.

Правило целиком — в docs/data-sources.md, раздел «Сгенерированные слои поверх источников».

Посмотреть, что загружено

docker compose exec mcp1c python -m mcp1c.cli reg-list --data /data
РозницаДляКазахстана  2.3.10.5  платформа 8.3.23.1997
  объектов 5637, связей 44034, загружено 2026-08-18T12:22:16+00:00
  метаданные : да
  синтаксис  : справка 8.3.27, новее конфигурации, скрыто 874
  модули     : не подключены
  язык запросов: подключён, 127 страниц

Конфигураций может не быть вовсе — сервер при этом работает, если загружена хоть одна справка: отвечают search_syntax и get_syntax, config указывать не нужно. reg-list в этом случае перечисляет подключённое и возвращает 0:

Конфигурации не загружены. Подключено:
  язык запросов, 127 страниц
Работают search_syntax и get_syntax, без фильтра по версии.

На полностью пустом реестре — «Ничего не загружено.» и код возврата 1. Любая команда, которой нужна конфигурация, там же скажет, чего именно не хватает и чем каждое берётся.

Отладка без агента — mcp1c.cli

CLI ходит в тот же реестр и те же функции, что и инструменты MCP. Если он отвечает верно — дело в настройке клиента, а не в сервере.

Команды делятся на три группы. По реестру — то же, что видит агент:

PYTHONPATH=src python3 -m mcp1c.cli reg-list  [--data data]
PYTHONPATH=src python3 -m mcp1c.cli reg-add   Выгрузка.zip     [--data data]
PYTHONPATH=src python3 -m mcp1c.cli reg-add   shcntx_ru.hbk    [--data data]
PYTHONPATH=src python3 -m mcp1c.cli reg-search "чек ккм"  --config РозницаДляКазахстана
PYTHONPATH=src python3 -m mcp1c.cli reg-search "разделить строку" --syntax --limit 5

reg-search без --syntax ищет по метаданным, с ним — по справке и языку запросов.

Прямо по файлу, без реестра — посмотреть выгрузку до того, как она поедет в сервер:

PYTHONPATH=src python3 -m mcp1c.cli info    Выгрузка.zip
PYTHONPATH=src python3 -m mcp1c.cli stats   Выгрузка.zip
PYTHONPATH=src python3 -m mcp1c.cli show    Выгрузка.zip Документ.ЧекККМ --detail full
PYTHONPATH=src python3 -m mcp1c.cli related Выгрузка.zip Документ.ЧекККМ --depth 2
PYTHONPATH=src python3 -m mcp1c.cli find    Выгрузка.zip реализация --limit 10

Путь — ZIP или распакованный каталог, формат определяется по манифесту.

Словарь поиска — синонимы общие, псевдонимы привязаны к конфигурации:

PYTHONPATH=src python3 -m mcp1c.cli dict-show                       # правила и их происхождение
PYTHONPATH=src python3 -m mcp1c.cli dict-show --all --config Розница...
PYTHONPATH=src python3 -m mcp1c.cli dict-synonyms чек ккм касса     # группа взаимозаменяемых слов
PYTHONPATH=src python3 -m mcp1c.cli dict-synonyms чек ккм --remove
PYTHONPATH=src python3 -m mcp1c.cli dict-alias "справочник физлиц" Справочник.ФизическиеЛица
PYTHONPATH=src python3 -m mcp1c.cli dict-alias "справочник физлиц" --remove

dict-show показывает происхождение каждого правила — с этого начинается разбор «почему поиск так себя ведёт».

Замер качества поиска — mcp1c.bench

Отдельный стенд, потому что «стало лучше» без цифр — мнение.

PYTHONPATH=src .venv/bin/python -m mcp1c.bench \
    --data data --config РозницаДляКазахстана \
    --auto --sets query-language,roznica-metadata --check-notes

Ключ

Что делает

--sets имя,имя

ручные наборы из tests/queries/*.json, без расширения

--auto

автоматические наборы по справке: точные имена и одноимённые

--config

конфигурация; обязательна, если загружено несколько

--limit

глубина выдачи, по умолчанию 10

--save путь

записать прогон для сравнения; по уговору data/bench/ГГГГ-ММ-ДД.json

--baseline путь

сравнить с прошлым прогоном — назовёт поимённо, кто сменил место

--check-notes

сверить пометки в наборе с тем, какое место запрос занял

Печатает P@1/P@3/P@5/P@10, MRR, долю «чужой домен первым» и медианный отрыв первого результата от второго. Порогов в assert нет намеренно: наборы запросов — не тесты, проценты ломались бы от каждой правки словаря. Ненулевой код возврата бывает только на расхождении пометок — это не качество поиска, а враньё в файле.

Сравнение двух прогонов выглядит так (ухудшения первыми):

=== сравнение с прошлым прогоном ===
  - «как прибавить месяц к дате в запросе»: 1 -> промах
  - «как отсортировать результат запроса»: 1 -> 5
  + «в чем разница между внутренним и левым соединением»: 5 -> 4

Наборы в образ не входят (tests/ в .dockerignore) — запускать из рабочей копии, не из контейнера.

Сервер вручную — mcp1c.server

PYTHONPATH=src python3 -m mcp1c.server --data data          # streamable-http на :8000/mcp
PYTHONPATH=src python3 -m mcp1c.server --transport stdio    # локальному клиенту
PYTHONPATH=src python3 -m mcp1c.server --host 0.0.0.0 --port 5001

--transport sse в коде есть и работает, но наружу не выведен: SDK поднимает один транспорт на процесс, а всё состояние у нас в памяти — второй транспорт стоил бы примерно столько же, сколько первый. Сам SSE в MCP объявлен устаревшим в пользу streamable-http.

Откуда берутся исходные данные

Структура конфигурации — обработкой из exporter-1c/. Четыре варианта модуля под обычную и управляемую форму, XML и JSON; XML-варианты совместимы с 8.3.5. Две обработки лежат уже собранными и открываются как есть: ВыгрузкаСтруктурыКонфигурации_ОбычнаяФорма_XML.epf (8.3.5 и выше) и ВыгрузкаСтруктурыКонфигурации_УправляемаяФорма_XML_JSON.epf (8.3.6 и выше, формат выбирается на форме).

Справка платформы — файл shcntx_ru.hbk из каталога установки 1С:

/opt/1cv8/<версия>/shcntx_ru.hbk
C:\Program Files\1cv8\<версия>\bin\shcntx_ru.hbk

Имя должно совпадать целиком. В том же каталоге лежат сотни файлов .hbk — 38 разных справок, каждая на два десятка языков. Похожие на нужный:

Файл

Что это

Почему не подходит

shcntx_root.hbk

та же справка, языконезависимая часть

25 508 элементов, но ни одного описания: только дерево страниц и английские идентификаторы, без версий появления

shlang_ru.hbk

описание встроенного языка

не контейнер 1С вовсе

shquery_ru.hbk

язык запросов

то же

config_ru.hbk

справка конфигуратора

контейнер, но страниц синтакс-помощника внутри нет

1cv8_ru.hbk

руководство пользователя

не контейнер

По размеру их не отличить: shcntx_root.hbk весит 33 МБ против 39 МБ у нужного. Суффикс _ru — язык, _root — общая часть без текстов.

Файл не тот — сервер объясняет, почему именно, и оставляет прежнюю справку на месте.

Достаточно одной справки от самой свежей доступной платформы: каждый элемент несёт версию появления, и для старых конфигураций лишнее отфильтровывается. Если версии нет в пути, она выводится из самих данных.

Справки от старых платформ тоже принимаются — они размечены иначе (разделы на div вместо p), это учтено. Пригодится, если поднимать отдельный сервер под старые внедрения: справка от 8.3.5 даёт 18 936 элементов и не содержит СтрНайти, СтрРазделить, ЗаписьJSON — их в 8.3.5 и не было. Но версию такая справка о себе не сообщает: пометок «начиная с версии» в ней нет, потому что тогда всё было текущим. Поэтому версию берут из имени файла или каталога — положите её как 8.3.5.1570.hbk или в data/hbk/8.3.5.1570/, иначе сопоставление с конфигурацией работать не будет.


5. Как устроено

src/mcp1c/
  v8container.py     контейнер 1С — общий для .hbk, .cf, .epf
  syntax_parser.py   разбор справки платформы
  syntax_model.py    модель элемента справки, виды, границы версий
  syntax_merge.py    слияние справок разных версий в один индекс
  query_parser.py    разбор справки по языку запросов (shquery_ru.hbk)
  replacements.py    чем заменить функцию, которой нет в старой платформе
  virtual_tables.py  таблицы запроса регистров и имена их полей
  loader.py          чтение выгрузок, XML и JSON в одну модель
  model.py           модель конфигурации
  graph.py           граф связей
  graph_view.py      окрестность объекта для картинки на дашборде
  search.py          лексический поиск
  search_keys.py     формулировки, которыми спрашивают язык запросов
  synonyms.py        встроенный словарь: как говорят против того, как названо
  dictionary.py      локальный словарь поверх встроенного
  index_cache.py     кэш поисковых индексов, расходный
  store.py           чтение и запись разобранных справок
  render.py          markdown-карточки объектов и элементов
  registry.py        реестр источников, сопоставление версий
  tools.py           семь инструментов, без зависимости от MCP
  server.py          протокольный слой (единственная внешняя зависимость)
  dashboard.py       веб-интерфейс: реестр, запросы, словарь
  cli.py             отладочный CLI
  bench.py           стенд замеров качества поиска

Одна модель на два формата. XML и JSON — разные сериализации одной схемы; загрузчик приводит оба к одинаковому словарю. Проверено: обе выгрузки дают одинаковый набор из 30 ключей.

Граф строит загрузчик, а не 1С. Рёбра выводятся из типов реквизитов, движений документов, оснований ввода, владельцев, обработчиков подписок и методов регламентных заданий. Правила можно менять без перевыгрузки.

Слабые рёбра. Реквизиты вроде ЗначениеДоступа перечисляют сотни типов и связывают почти всё со всем. Такие связи помечаются слабыми и по умолчанию скрыты — иначе полезные в них тонут.

Уровни детализации. Полное описание Документ.ЧекККМ (50 реквизитов, 17 табличных частей) съедает контекст целиком. brief — пара строк, fields — состав, full — со связями.

Без внешних баз. Пять конфигураций со справкой держатся в памяти одного процесса — 628 МБ, подъём с диска 9,4 с. Elasticsearch, векторное хранилище и графовая БД рассматривались и отклонены с цифрами: разбор — в docs/TASKBOARD.md, раздел «Отложено». Коротко: полмиллиона документов для ES — мало, а вся цена вектора не в хранилище, а в модели- энкодере на рантайме (+185–620 МБ к образу за torch, кодирование запроса 16–32 мс против нынешних 0,18–1,4 мс на весь поиск).

Измерено на реальных данных — 2026-08-18

Что загружено на рабочем сервере:

Конфигурация

Платформа

Объектов

Рёбер

Бухгалтерия для Казахстана

8.3.27.1936

3 492

84 426

Документооборот КОРП

8.3.27.1936

4 596

50 554

Зарплата и управление персоналом

8.3.27.1936

5 181

100 136

Розница для Казахстана

8.3.23.1997

5 637

58 345

Ювелирный торговый дом

8.3.5.1570

1 616

29 288

Итого

20 522

322 749

Плюс справка платформы — слитый индекс трёх версий (8.3.5, 8.3.23, 8.3.27), 25 691 элемент, и язык запросов — 127 страниц отдельным источником.

Старт из кэша — 9,4 с на всём этом. Первый старт дольше: исходники разбираются, индексы строятся и складываются в data/index/cache/ (12 МБ), разобранные справки — в data/index/syntax/ (11 МБ). Дальше поднимаются оттуда.

Кэш производный и расходный: привязан к версии Python, отпечатку кода пакета и хешу источника. Не сошлось что-нибудь — индексы строятся заново. Каталог можно удалить в любой момент, он восстановится сам.

Память живого контейнера — 628 МБ. Постинги индекса лежат массивами numpy; наполнение остаётся словарным и освобождается сразу после заморозки. Образ — 354 МБ.

Тексты модулей — разведка, провайдера ещё нет

Провайдер modules не сделан, инструментов по коду сервер не отдаёт. Цена измерена заранее, на выгрузке «Розницы» 2.3.10.5 в файлы (2 063 МБ, 33 188 файлов, 7 878 модулей, 136 909 процедур):

Слой

На диске

В памяти

сигнатуры и адреса процедур

18,1 МБ

65 МБ

поиск по всем процедурам

473 МБ

поиск только по экспортным (49 068)

156 МБ

формы: 3 194 файла, 69 769 элементов

5,8 МБ

44 МБ

Латентность поиска — 0,4–1,2 мс. Разбор корпуса — 7–10 с.

Выгрузок в файлы существует две разных, и вторая мерилась отдельно — «Ювелирный торговый дом» 10.5.1.3 на 8.3.5: плоская раскладка, модули в .txt, код обычных форм внутри двоичных контейнеров .Form. 2 603 модуля, 33 555 процедур, разбор 1,1 с, поиск по всем 94 МБ при медиане 0,2 мс. Структуры формы этот формат не содержит, а часть общих модулей поставлена скомпилированными — исходника в них нет вовсе.

Скрипты замеров лежат в tools/lab/, они разведочные и будут выброшены вместе с появлением настоящего провайдера. Пока ими воспроизводится каждая цифра выше:

python3 tools/lab/measure_modules.py <каталог выгрузки в файлы>
python3 tools/lab/measure_resident.py <каталог> <файл индекса> собрать
python3 tools/lab/measure_search.py <файл индекса> [экспортные]
python3 tools/lab/measure_forms.py <каталог>
python3 tools/lab/measure_flat.py <каталог плоской выгрузки>

Полный разбор, включая устройство расширений конфигурации, — docs/modules-and-extensions-2026-08-18.md.

Качество поиска

Снимается стендом, воспроизводится одной командой:

PYTHONPATH=src .venv/bin/python -m mcp1c.bench \
    --data data --config РозницаДляКазахстана \
    --auto --sets query-language,roznica-metadata --check-notes

Набор

Запросов

P@1

P@3

P@5

MRR

Отрыв

Язык запросов

19

94,7%

94,7%

100%

0,958

35,0%

Метаданные Розницы

21

90,5%

95,2%

95,2%

0,934

94,0%

Точные имена справки

50 926

97,1%

98,3%

98,7%

0,978

91,7%

Одноимённые

10 544

98,8%

99,8%

99,9%

0,993

93,8%

Первые два набора — ручные, из живых промахов. Вторые два строятся из самих данных: имя элемента как запрос, он же как ожидаемый ответ.

«Отрыв» — насколько первый результат оторвался от второго, медианой. Отвечает на вопрос «уверенно попали или чудом»: 35% по языку запросов против 91,7% по справке означает, что эти победы держатся втрое слабее и правка ранжирования способна их перевернуть, не сдвинув ни одного процента P@1.

Латентность поиска — 0,18–1,4 мс на запрос в зависимости от набора.

Наборы запросов в образ не входят (tests/ в .dockerignore): мерить надо из рабочей копии, а не из контейнера.

Тесты

.venv/bin/pip install -r requirements-dev.txt
.venv/bin/python -m pytest          # 371 тест, ~2 с

От содержимого data/ не зависят: проприетарных выгрузок в репозитории нет, всё нужное собирается синтетически в tests/conftest.py.

Качество поиска тестами не проверяется — оно меряется стендом (mcp1c.bench, см. «Измерено»). Пороги в процентах ломались бы от каждой правки словаря, поэтому стенд печатает цифры, а решение принимает человек. pytest проверяет наблюдаемое поведение: «индекс не построен заново», «выдача совпала», «старт не упал».


6. Безопасность

Два токена, оба задаются переменными окружения. Пока токен не задан, соответствующий доступ открыт всем, кто дотянется до адреса.

Переменная

Что закрывает

Не задана

API_TOKEN

чтение: инструменты MCP и страницы дашборда

структура конфигураций открыта всем

ADMIN_TOKEN

запись: загрузка и удаление источников, правка словаря, /admin/reload

эти маршруты отключены, отвечают 404

Разница между «открыто» и «отключено» намеренная. Чтение без токена работает — на своей машине это удобно и ничем не грозит. Запись без токена не работает вовсе: одна неудачная правка словаря тихо ломает поиск всем, кто подключён к общему серверу.

Токен передаётся заголовком — либо X-Api-Token, либо Authorization: Bearer <токен>. Административный годится и для чтения: иначе владельцу пришлось бы держать в клиенте два заголовка вместо одного.

Токен должен быть в латинице. Заголовки HTTP кодируются latin-1, и кириллический токен до сервера физически не доходит: через форму входа в браузере он сработает, через заголовок клиента — нет.

Мимо проверки пропускаются два пути: /health (по нему ходит healthcheck контейнера, и сведений сверх права чтения он не отдаёт) и /login — иначе форма входа оказалась бы за той самой авторизацией, которую она выдаёт.

Ещё два правила, не про токены:

  • MCP-эндпоинт отдаёт структуру конфигураций целиком. Задавайте API_TOKEN при любом выносе за пределы своей машины, сетевого доступа недостаточно.

  • Каталог data/ целиком в .gitignore — и .hbk с выгрузками, и разобранные индексы. Индекс справки — тот же контент фирмы «1С», только распакованный. Однажды он туда попал и пролежал 20 коммитов; историю переписывали git filter-repo, а правило переформулировали по каталогу, а не по расширениям: проверять надо не «это .hbk?», а «это лежит в data/?».


7. Документы

Файл

О чём

AGENTS.md

правила работы над проектом

CHANGELOG.md

что сделано и что выяснено про 1С

docs/TASKBOARD.md

планы, приоритеты и отклонённые предложения с причинами

docs/schema-v1.md

контракт формата выгрузки

docs/data-sources.md

что из какого источника берём

docs/query-language-design.md

устройство источника языка запросов

docs/dashboard-design.md

устройство дашборда

docs/market-review-2026-08-17.md

обзор аналогов и что из него взято

exporter-1c/README.md

обработка выгрузки для 1С

Раздел «Отложено» в доске задач — отклонённые предложения с цифрами: внешняя БД, вектора, графовая БД, SSE наружу, ленивая загрузка. Прежде чем предлагать что-то из этого заново, стоит прочитать: отменяют такие решения новые замеры, а не новые соображения.

-
license - not tested
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/AzeevAN/mcp-1c'

If you have feedback or need assistance with the MCP directory API, please join our Discord server