Skip to main content

odata1c-gate

Локальный MCP-шлюз между Claude Code и стандартным OData-интерфейсом 1С:Предприятие 8.3. Модель получает доступ к данным базы — справочникам, документам, регистрам, — но между ней и 1С стоит гейт псевдонимизации: реквизиты (ИНН, счета, паспорта, телефоны) и, на выбранном уровне, названия организаций и ФИО заменяются токенами вида [[type:tail]] до того, как данные увидит модель. Обратная подмена происходит только внутри шлюза, перед отправкой запроса в 1С.

Один пользователь, одна машина, несколько сессий агентов одновременно, несколько баз 1С. Клиент — Claude Code (другие клиенты MCP работают, но подтверждение записи у них устроено иначе, см. docs/install.md).

Статус: выпуск 0.1.0 (чтение M1, запись M2 и поставка M3 закрыты 2026-09-14). Работают демон, лаунчер, индекс метаданных, гейт всех уровней, девять тулов чтения и семь тулов записи; приёмка на живой базе 1С пройдена для чтения, записи и установки из PyPI и маркетплейса (docs/probes/M1d-live-check.md, docs/probes/M2-live-check.md, docs/probes/M3-clean-install.md); перечень изменений — CHANGELOG.md.

Зачем это

Дать модели читать рабочую базу 1С — значит отдать ей персональные данные и коммерческую тайну: ИНН контрагентов, расчётные счета, телефоны и адреса физических лиц, названия клиентов. Обезличивать выгрузку заранее неудобно (модель должна видеть свежие данные и уметь дозапрашивать), а инструктировать модель «не показывай ИНН» бессмысленно — инструкция не механизм.

Шлюз решает это подменой на границе: модель работает с живой базой, но защищаемые значения заменяются токенами до того, как попадут в её контекст. Токен детерминирован (одно значение — один токен), поэтому по нему можно отбирать, связывать записи и вести разговор, не зная исходного значения. Разработчик, который читает ответы модели, видит [[inn:M4T2Q9XZ7K]], а не ИНН — и при необходимости раскрывает его сам, командой в терминале, мимо модели.

Что видит модель, а что нет

Что уходит модели. Структура базы (сущности, поля, ключи, навигация) и данные, прошедшие гейт. Номера и даты документов, суммы, количества, коды, GUID, значения перечислений не защищаются ни на одном уровне — без них работа с базой теряет смысл. Названия организаций и ФИО (классы org и person) и защищаемые реквизиты — ИНН, КПП, ОГРН, счета, БИК, карты, СНИЛС, документы, телефоны, почта, даты рождения, адреса — приходят токенами [[type:tail]] по правилам политики базы. Уровень задаётся на базу: off — гейт выключен, identifiers — реквизиты, identifiers+names — реквизиты плюс названия и ФИО.

Что не уходит никогда. Реальные значения защищаемых классов не выходят через MCP ни в одном ответе: ни в данных, ни в текстах ошибок 1С, ни в превью записи, ни в журнале, ни в odata1c_raw_get, ни в вопросах подтверждения. Это инвариант, а не тест: последний проход по готовому ответу делает страж утечек — он ищет в сериализованном ответе известные словарю значения и заменяет их токенами, если что-то прошло мимо гейта. Учётные данные 1С модель не получает: пароль не покидает домашнего каталога вовсе, имя пользователя 1С не попадает ни в один ответ, а адрес публикации базы не возвращает ни один тул. О самой базе модель узнаёт ровно то, что перечисляет odata1c_bases: имя, подпись, роль, уровень гейта, разрешена ли запись, состояние индекса (собран ли, когда, сколько сущностей) и конфигурацию 1С, к которой база отнесена. Единственное исключение по адресу — текст сетевого сбоя, в который его может вписать HTTP-клиент. Хук плагина вдобавок запрещает модели читать файлы домашнего каталога шлюза. Раскрыть токен может только владелец машины, командой odata1c reveal в своём терминале.

Кто подтверждает запись. Тулы записи ничего не пишут в 1С: они готовят операцию, показывают превью в токенах и возвращают pending_id. Выполняет её отдельный вызов odata1c_commit, и только после подтверждения человека механизмом клиента — в Claude Code это диалог разрешения, у клиентов с elicitation — вопрос шлюза. Реплика «да» в чате подтверждением не считается: модель не может подтвердить запись сама себе. Каждая выполненная запись попадает в локальный журнал и откатывается тулом odata1c_undo. Записи в базах с ролью prod по умолчанию нет вовсе, а состав разрешённого сужается флагами разрешений в настройках базы.

Установка

Нужен uv — он сам поставит подходящий Python, отдельно ставить интерпретатор не нужно. Дальше две команды в терминале ставят плагин Claude Code вместе со шлюзом:

claude plugin marketplace add Romandredan/odata1c-gate
claude plugin install odata1c@odata1c-gate

Плагин приносит MCP-сервер шлюза, три навыка, хук подтверждения записи и агента-следователя. Версия пакета закреплена в plugin/.mcp.json, поэтому claude plugin update odata1c обновляет и плагин, и шлюз.

Две оговорки. Первая: обе команды заработают начиная с выпуска 0.1.0 — пока тег не опубликован, пакета odata1c-gate на PyPI нет, и uvx при первом запуске шлюза ответит отказом (.mcp.json плагина закреплён на версии из репозитория). Вторая: репозиторий пока приватный, claude plugin marketplace add клонирует его через git, поэтому на машине нужны учётные данные git с доступом к нему. Открытие репозитория — отдельное решение владельца.

Отдельно ставится командная строка — она нужна владельцу базы, а не модели (описать базу, собрать индекс, раскрыть токен, править политику гейта):

uv tool install odata1c-gate

После этого команда odata1c доступна в терминале. Без установки то же самое запускается как uvx --from odata1c-gate odata1c <команда>. Подробности, Linux, обновление и разбор типовых сбоев — docs/install.md.

Первые пять минут

odata1c init                          # ~/.claude/odata1c/ с шаблонами настроек, права владельца
odata1c base add ut_test --role test --recipes ut   # спросит адрес, подпись, пользователя, пароль
odata1c base test ut_test             # проверить соединение с 1С
odata1c reindex ut_test               # разобрать $metadata и построить индекс метаданных
odata1c doctor                        # проверить окружение: uv, дом, базы, демон, Claude Code

Начинать с init обязательно: плагин домашнего каталога не создаёт — его делают либо эта команда, либо лаунчер при первой сессии Claude Code. doctor на пустом месте честно ответит FAIL в строке домашнего каталога, поэтому он и стоит последним; запускать его можно в любой момент.

Адрес базы — это адрес публикации OData 1С, он оканчивается на /odata/standard.odata/ (например https://1c.example.local/ut/odata/standard.odata/). Пользователь 1С заводится отдельный, с правами только на то, что нужно читать, — например odata_claude. Пароль вводится в терминале и на экране не отображается; он ложится в bases.yaml домашнего каталога открытым текстом, файл закрывается правами владельца (SPEC §3.4, ADR-0014) — осознанное решение: файл не покидает диск владельца, это не сетевой секрет. Роль базы задаёт умолчания: prod — уровень гейта identifiers+names и только чтение, test — уровень identifiers, dev — гейт выключен и запись разрешена; любое поле переопределяется правкой файла вручную — готовая запись выглядит так (адрес и пароль — плейсхолдеры; шаблон со всеми полями — src/odata1c/templates/bases.example.yaml):

bases:
  ut_test:
    label: УТ 11, тестовая
    url: https://server/base/odata/standard.odata/
    user: odata_claude
    password: "…"
    role: test
    config: ut

Чаще всего руками правят label, role, write (разрешить запись), gate.mode (уровень гейта), permissions (что именно разрешено писать) и config (библиотека рецептов); демон перечитывает bases.yaml по изменению файла без перезапуска. Другой домашний каталог — переменная ODATA1C_HOME или ключ --home <путь> у любой команды.

Файл правит владелец, не модель: модель его штатно не читает и не правит — хук плагина PreToolUse перехватывает такие обращения к домашнему каталогу шлюза и требует решения человека; это защита в глубину, а не абсолютный барьер (что он не отсекает и почему главная защита в другом — раздел «Безопасность» в AGENTS.md). Реальные значения не выходят через MCP ни при каком обращении, а пароль 1С модели попросту не нужен — этого достаточно, даже если бы хука не было. Базу заводит владелец сам, в своём терминале — просить модель «пропиши базу» бессмысленно, у неё нет для этого инструмента. Подробнее — docs/install.md.

Первый реиндекс долгий: у типовой УТ $metadata — это около 17 МБ описания и больше семи тысяч сущностей. Дальше индекс пересобирается, только если у публикации изменилась контрольная сумма $metadata.

Теперь можно спрашивать в Claude Code:

  • «какие базы 1С мне доступны?» — модель вызовет odata1c_bases;
  • «найди справочник контрагентов и покажи состав его полей» — odata1c_find_entity, затем odata1c_describe_entity с классами гейта у каждого поля;
  • «возьми любого контрагента и покажи его пять последних заказов клиента» — odata1c_query; название контрагента придёт токеном, номера и суммы документов — как есть.

Что модель видит и в каком порядке ходит — навык odata1c из плагина; справочные темы об устройстве OData 1С, токенах, политике и протоколе записи — тул odata1c_info.

Что внутри

Два процесса из одного пакета: демон (odata1c daemon) — единственный на машину, держит соединения с базами, индекс, словарь и журнал, отвечает по MCP Streamable HTTP на 127.0.0.1:7171; лаунчер (odata1c mcp) — тонкий stdio-процесс на сессию, который поднимает демон при необходимости и проксирует ему вызовы. Собственной логики у лаунчера нет.

Тулы чтения: odata1c_bases, odata1c_find_entity, odata1c_describe_entity, odata1c_query, odata1c_get, odata1c_info, odata1c_reindex, odata1c_raw_get, odata1c_recipe. Тулы записи: odata1c_create, odata1c_update, odata1c_mark_for_deletion, odata1c_action (проведение и отмена), odata1c_undo, odata1c_commit, odata1c_journal.

Рецепт — именованный параметризованный запрос к одной сущности («остатки на складе на дату», «задолженность контрагента»): модель подставляет параметры, шлюз строит запрос сам. Рецепты копятся по конфигурации 1С, а не по отдельной базе.

Ограничения

  • Физического удаления объектов нет. «Удаление» для объектов и подчинённых регистров — только пометка удаления (DeletionMark = true). PUT не используется.
  • Сокращённое название в свободном тексте проходит открытым. Словарь знает полные написания названия; если в комментарии документа человек написал узнаваемое сокращение, которого нет в справочнике, гейт его не заменит. Ловить «ядро» названия отвергнуто: ядра — обычные слова, их замена портила бы данные ложными срабатываниями.
  • Аутентификации у демона нет. Он слушает только 127.0.0.1; модель угроз — диск и машина владельца. Публикация по сети с TLS и токенами — этап M4.
  • Записи в регистры, подчинённые регистратору, нет ни при каком флаге разрешений: их пишет проведение документа, а не прямая запись.
  • Шаблоны рецептов заполнены только для УТ. Для БП и ЗУП шаблоны пока пустые: базы для сверки имён нет, а невыверенный рецепт хуже пустого.
  • Клиент — Claude Code. Claude Desktop и Cowork не поддерживаются (ADR-0012).

Документы

Файл Что внутри
docs/install.md установка на Windows и Linux, обновление, типовые сбои, раздел сопровождающего
CHANGELOG.md что вошло в выпуск
SPEC.md спецификация v0.2, 16 разделов — главный артефакт проекта
CONTEXT.md глоссарий: термины и запрещённые синонимы
docs/adr/ 15 архитектурных решений (0001–0015), статус — во frontmatter
AGENTS.md вводная для AI-агентов: архитектура, стек, инварианты, процесс
CLAUDE.md указатель для Claude Code поверх AGENTS.md

Структура репозитория

src/odata1c/          пакет PyPI odata1c-gate: демон, лаунчер, CLI (SPEC §2.2, §11.1)
  config/             bases.yaml и daemon.yaml, роли, валидация, права файлов
  registry/           реестр баз, статус индекса, видимость по сессии
  client1c/           httpx-пул на базу, IBSession, семафор, маппинг ошибок 1С
  index/              парсер EDMX → metadata.sqlite, реиндекс, нечёткий поиск
  gate/               детекторы реквизитов, словарь, подмена в обе стороны, страж
  write/              разрешения, pending-операции, commit, журнал, undo
  recipes/            загрузка рецептов и рендеринг параметров в OData-литералы
  tools/              регистрация тулов, ресурсов, промптов, server instructions
  templates/          файлы-шаблоны в поставке: конфигурация и рецепты УТ/БП/ЗУП
  cli.py              команды odata1c: init, base, reindex, policy, recipe, doctor, reveal, daemon, mcp
  daemon.py           демон: тулы, ресурсы, промпт, MCP Streamable HTTP на 127.0.0.1
  launcher.py         лаунчер: stdio-прокси демону, подъём демона, проброс elicitation
plugin/               плагин Claude Code: манифест, .mcp.json, навыки, хук, агент, evals (SPEC §11.2)
.claude-plugin/       маркетплейс плагина для claude plugin marketplace add
tests/                unit / property / integration + образцы EDMX (SPEC §12)
tools/                bump_version.py, plugin_dev_copy.py, probes/ — скрипты проверок и приёмки
docs/adr/             архитектурные решения
docs/plans/           планы реализации по этапам
docs/probes/          отчёты технических проверок P1–P8 и приёмок на живой базе

Что не попадает в репозиторий

bases.yaml хранит пароли 1С открытым текстом (SPEC §3.4), поэтому в git не коммитятся конфигурация рабочей машины, env-файлы, базы SQLite (словарь, индекс, журнал), выгрузки $metadata и логи — см. .gitignore. В поставке живут только файлы-шаблоны в src/odata1c/templates/, в тестах — урезанные образцы $metadata, не полные дампы.

Лицензия

MIT.

Release files for odata1c-gate 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for odata1c-gate 0.1.1
File Size Uploaded
odata1c_gate-0.1.1.tar.gz 512.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for odata1c-gate 0.1.1
File Interpreter ABI Platform
odata1c_gate-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 1.1 MB

Release files / odata1c_gate-0.1.1.tar.gz

Download URL odata1c_gate-0.1.1.tar.gz
Size 512.5 kB
Tags Source
SHA-256 checksum
How to use checksums
5fb8035e4c607ae83c6f9d12fdc47bb2b9b4beaceedff3ac2f2c5ee96d658c02
BLAKE2b-256 checksum
How to use checksums
e1a0fba62adfdc47761d058441cc37d589da9e52e74d21c8ef1769892a89d814
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 20, 2026.

Transparency log

Release files / odata1c_gate-0.1.1-py3-none-any.whl

Download URL odata1c_gate-0.1.1-py3-none-any.whl
Size 565.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
34280e2639b673d9a445dd1991c59c36d2e3dc80b34655b35167b224f1472e9e
BLAKE2b-256 checksum
How to use checksums
48aa3f7f8c301ae3ecb1324cb555407ab60f4fca5e96d7b056a6a94f40d0363c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 20, 2026.

Transparency log

Release history Release notifications | RSS feed

0.3.0

2 release files

0.2.0

2 release files

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page