Skip to main content
Glama
kopyshok

rules-mcp

by kopyshok

rules-mcp — правила обмена 1С в чате

MCP-сервер, который разбирает боевые правила обмена 1С (Конвертация данных 2.0) и отвечает на вопросы о них прямо в чате Open WebUI: как работает конкретный обмен, что создаётся у приёмника, где расхождение с конфигурацией.

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

Разбор — обычная программа, языковая модель в нём не участвует и токены на него не тратятся. Токены уходят только на то, что инструмент вернул в чат.

  • Поддерживается КД 2.0 (ExchangeRules.xml + RegistrationRules.xml). Конвертация данных 3 (EnterpriseData) — другой формат, здесь не поддерживается.

  • Только стандартная библиотека Python для разбора, одна зависимость для MCP.

  • Индекс живёт в памяти, базы данных нет. 36 МБ правил разбираются за секунду.


Что умеет

Инструмент

Отвечает на вопрос

exchange_overview

Какие есть направления, документы, процессы

trace_document

Что происходит с документом при обмене — от регистрации до приёмника; где стоит каждый вызов правила

get_conversion_rule

Одно правило конвертации целиком: реквизиты, табличные части, каскады

search_rules

Где вообще упоминается реквизит, алгоритм или фрагмент логики

get_rule_handler

Полный текст обработчика правила или отдельного реквизита — постранично, с номерами строк

get_rule_queries

Запросы обработчика: пакет, параметры, временные таблицы

receiver_fields

Что правила ждут от конфигурации приёмника — для сверки

refresh_rules

Перечитать правила из репозитория сейчас (под паролем)

Инструменты намеренно общие, а не готовые отчёты: пользователь спрашивает как угодно, а ответ складывает модель.

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

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

Отбор по правилу в search_rules понимает код, наименование и имя объекта — как get_rule_handler. Коды правил регистрации числовые, поэтому их удобнее называть именем документа; если правил у документа несколько, ищется по всем.

get_rule_queries делает механическую часть, в которой легко ошибиться руками: делит пакет на отдельные запросы, сопоставляет Результат[n] с номером запроса в пакете, показывает, где создаётся каждая временная таблица и от каких она зависит. Текст, собранный не из строкового литерала, а выражением, полным не выдаётся — такой запрос помечается неполным. Вычисляемый номер элемента пакета не угадывается, а выносится отдельно как неопределённый.

Инструменты видят не только правила, но и общие алгоритмы с именованными запросами: ветка выгрузки часто зовёт Выполнить(Алгоритмы.Имя), а сам вызов правила конвертации стоит внутри алгоритма. В правилах УПП → ЕРП так спрятаны 34 вызова, и без обхода алгоритмов часть документов приёмника просто не видна.

И ещё обработчики отдельных реквизитов правил конвертации. Там лежит условие заполнения реквизита — не то же самое, что условие выбора правила: признак может влиять на то, чем заполнится склад, и никак не влиять на то, какое правило сработает. Таких обработчиков по корпусу 2115, они есть у 489 правил конвертации. Карточка правила (get_conversion_rule) показывает у реквизита с обработчиком его код, перечень обработчиков в get_rule_handler перечисляет такие реквизиты, а прочитать обработчик можно тем же get_rule_handler с параметром prop — кодом реквизита или именем приёмника. Имя приёмника внутри правила бывает не единственным (в шапке и в табличной части), тогда в ответе перечень — выберите код. search_rules ищет и по ним; у такого попадания есть поля «реквизит» и «код реквизита».

Ради чего всё затевалось

Правила целиком состоят из ссылок на реквизиты и типы двух конфигураций. Проверить их в одиночку нельзя. Но если рядом подключён сервер, читающий конфигурации 1С (например rlm-tools-bsl), появляется проверка, которую иначе делают руками:

1. rules-mcp        → «правила пишут вот в эти реквизиты приёмника, вот их типы»
2. сервер конфигураций → «а вот что реально есть у этого объекта»
3. модель           → сравнивает и показывает расхождения

Реквизита нет, он переименован или сменил тип — обмен на этом не падает, он молча не переносит данные. Это самая дорогая и самая незаметная поломка обмена.

Серверы друг друга не знают и ничего друг о друге не предполагают — разворачиваются и чинятся независимо. Связывает их модель: когда и как идти во второй сервер, написано в PROMPT.md и в разделе «Сверка с конфигурацией» KNOWLEDGE.md.


Related MCP server: bsl-context

Как должны лежать правила

Папка на направление обмена, внутри выгрузка из Конвертации данных:

<корень или подкаталог репозитория>/
├── УПП_ERP/
│   ├── ExchangeRules.xml              правила выгрузки (ПВД) и конвертации (ПКО)
│   ├── RegistrationRules.xml          правила регистрации (ПРО)
│   └── CorrespondentExchangeRules.xml не читается
├── ERP_УПП/
│   └── …
└── Розница_ERP/
    └── …

Направление определяется по файлу ExchangeRules.xml; папка без него молча пропускается. Имена папок могут быть на кириллице или латиницей — стороны обмена берутся из самих правил, а не из имени папки, поэтому «УПП → ЕРП», «упп erp», «из розницы в ерп» и «УПП_ERP» распознаются одинаково.

Порядок сторон значим: УПП_ERP и ERP_УПП — разные направления с разными правилами, и сервер их не путает.


Установка

Вариант 1. Docker рядом с Open WebUI (рекомендуется)

Добавьте в ваш docker-compose.yml (или возьмите готовый фрагмент из docker-compose.yml):

services:
  rules-mcp:
    build: ./rules-mcp                     # или image: ghcr.io/…, если соберёте свой
    environment:
      GITLAB_REPO: https://gitlab.example.ru/exchange/rules.git
      GITLAB_TOKEN: ${GITLAB_TOKEN}
      GITLAB_BRANCH: main
      RULES_SUBDIR: ""
      REFRESH_INTERVAL: "3600"
      REFRESH_PASSWORD: ${RULES_REFRESH_PASSWORD}
    volumes:
      - rules-clone:/data                  # клон переживает перезапуск контейнера
    restart: unless-stopped
    networks: [ai]

  open-webui:
    # ваш существующий сервис; нужно добавить только это
    environment:
      WEBUI_SECRET_KEY: ${WEBUI_SECRET_KEY}
    networks: [ai]

volumes:
  rules-clone:

networks:
  ai:
git clone https://github.com/kopyshok/rules-mcp.git
cp rules-mcp/.env.example .env      # заполнить токен и пароль
docker compose up -d --build rules-mcp
docker compose logs -f rules-mcp

Секции ports намеренно нет: наружу сервис публиковать не надо, Open WebUI дотянется до него по внутренней сети. Это же снимает вопрос доступа извне.

Вариант 2. Без Docker

git clone https://github.com/kopyshok/rules-mcp.git && cd rules-mcp
python -m venv .venv && . .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install -r requirements.txt

export RULES_DIR=/путь/к/каталогу/с/направлениями
export REFRESH_INTERVAL=0                      # работать с тем, что уже на диске
python server.py

Нужен Python 3.10+ и установленный git, если правила берутся из репозитория.


Настройки

Все настройки — через переменные окружения. Образец: .env.example.

Переменная

По умолчанию

Смысл

GITLAB_REPO

пусто

Адрес репозитория с правилами по HTTPS. Пусто — работать с тем, что уже лежит в RULES_DIR

GITLAB_TOKEN

пусто

Токен на чтение репозитория

GITLAB_BRANCH

пусто

Ветка с правилами. Пусто — ветка по умолчанию

RULES_SUBDIR

пусто

Подкаталог внутри репозитория, если папки направлений лежат не в корне

REFRESH_INTERVAL

3600

Период опроса, секунды. 0 — не опрашивать

REFRESH_PASSWORD

пусто

Пароль для refresh_rules. Не задан — команда недоступна

RULES_DIR

/data/rules

Каталог с направлениями. При работе из репозитория клон кладётся в /data/checkout

HOST / PORT

0.0.0.0 / 8000

Адрес прослушивания

Несмотря на имена, GITLAB_* работают с любым git-сервером — GitHub, Gitea, Bitbucket. Имена оставлены такими, потому что писалось под GitLab.


Подключение к GitLab

1. Токен на чтение

Лучше deploy-токен: он привязан к репозиторию, а не к человеку, и не отвалится, когда сотрудник уйдёт.

Settings → Repository → Deploy tokens → Add token

  • Name: rules-mcp

  • Expires: можно оставить пустым

  • Scopes: только read_repository

GitLab покажет имя пользователя и сам токен один раз. Сервису нужен только токен — имя пользователя он подставляет сам.

Личный токен (Settings → Access Tokens, область read_repository) тоже подойдёт, если deploy-токены запрещены политикой.

2. Адрес репозитория

Только HTTPS. SSH не поддерживается — в контейнере нет ключей и известных хостов, и заводить их ради чтения одного репозитория не стоит.

GITLAB_REPO=https://gitlab.example.ru/exchange/rules.git
GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx

Токен не надо вписывать в адрес — сервис подставит его сам при обращении. Так он не попадает ни в логи, ни в вывод команд.

Если GitLab на нестандартном порту, укажите его в адресе как обычно: https://gitlab.example.ru:8443/exchange/rules.git.

3. Ветка с правилами

GITLAB_BRANCH=main

Указывайте ветку явно. Если оставить пусто, берётся ветка по умолчанию — а она в репозиториях с правилами часто оказывается черновой. Аналитики будут читать не то, что стоит на продуктиве, и не узнают об этом.

Заведите отдельную ветку под боевые правила (prod, production, release) и укажите её. Сервис работает ровно с ней: git fetch и git reset идут по указанной ветке, изменения в других ветках его не трогают.

Ветка видна в ответе каждого инструмента — поле «версия правил»:

ветка prod, коммит d54877b от 08.09.2026

Так человек в чате всегда видит, на какой версии правил построен ответ.

4. Правила лежат не в корне

RULES_SUBDIR=exchange/rules

Клонируется репозиторий целиком, но папки направлений ищутся в этом подкаталоге. Путь указывается от корня репозитория, через /.

5. Проверка

docker compose logs rules-mcp        # клонирование и старт

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


Подключение к Open WebUI

Родная поддержка MCP появилась в Open WebUI 0.6.31. На версиях старее понадобится обновление либо прослойка mcpo.

Настройки → Админ → Интеграции → Внешние серверы инструментов → Добавить:

Поле

Значение

Тип

MCP (Streamable HTTP)

Адрес

http://rules-mcp:8000/mcp

Авторизация

None

Три места, где спотыкаются:

  1. Тип должен быть MCP, не OpenAPI. Если вписать MCP-настройки в подключение типа OpenAPI, интерфейс уходит в бесконечную загрузку. Лечится удалением подключения и повторным добавлением.

  2. Адрес — имя контейнера, а не localhost. Глобальные подключения выполняются самим Open WebUI, и localhost внутри его контейнера означает его же, а не сервер.

  3. Авторизация именно None. Выбранный «Bearer» с пустым ключом шлёт пустой заголовок, и соединение рвётся.

В Open WebUI должен быть задан WEBUI_SECRET_KEY, иначе подключения слетают при каждом пересоздании контейнера.

Чтобы люди не включали инструмент вручную

Глобальный инструмент в чате сам не появляется — каждому пришлось бы включать его в меню интеграций. Вместо этого соберите модель:

Рабочая область → Модели → Создать

  • базовая модель — ваша обычная;

  • системная подсказка — готовый текст в PROMPT.md;

  • знания — KNOWLEDGE.md (инструменты, порядок вызова, разобранный пример), плюс методичка и карта процессов, если они у вас есть;

  • инструменты — rules-mcp и сервер конфигураций, включены принудительно;

  • доступ — нужной группе.

Пользователь выбирает модель из списка, и у него уже всё настроено.


Обновление правил

Три пути, все работают вместе:

  • Автоматически раз в REFRESH_INTERVAL секунд. Если коммит не сменился, индекс не пересобирается — проверка стоит несколько килобайт трафика.

  • Из чата — инструмент refresh_rules с паролем. Нужен, когда только что выложили релиз и ждать час не хочется. Пароль спрашивается у человека, чтобы модель не запускала обновление сама.

  • Перезапуском контейнера — индекс собирается заново при старте.

Индекс подменяется целиком и только после того, как новый успешно собран. Пока он строится, сервер продолжает отвечать на старом. Если забрать правила не удалось, старый индекс остаётся в работе.


Если что-то не работает

Симптом

Причина

Open WebUI не видит сервер

Адрес localhost вместо имени контейнера; контейнеры в разных сетях

Интерфейс виснет при добавлении

Выбран тип OpenAPI вместо MCP

Соединение сразу рвётся

Авторизация «Bearer» с пустым ключом; нужна None

Подключения слетают после пересоздания

Не задан WEBUI_SECRET_KEY в Open WebUI

«направлений: 0»

Не тот RULES_SUBDIR, не та ветка, или в папках нет ExchangeRules.xml

В ответах поле «внимание»

Не проходит обновление: протух токен, нет ветки, недоступна сеть. Текст ошибки там же

Модель не зовёт инструменты

Вопрос к модели, а не к серверу. Проверьте на модели с надёжным вызовом инструментов

Посмотреть, что сервер вообще отдаёт:

docker compose exec rules-mcp python -c "
import asyncio
from fastmcp import Client
async def m():
    async with Client('http://127.0.0.1:8000/mcp') as c:
        for t in await c.list_tools(): print(t.name)
        print((await c.call_tool('exchange_overview', {})).data)
asyncio.run(m())"

Как устроено внутри

  • rules_index.py — разбор XML и индекс. Только стандартная библиотека. Правила регистрации, ветки выгрузки, правила конвертации со всеми свойствами и табличными частями, каскады в подчинённые правила, функциональные блоки (процессы), которыми разработчики помечают ветки, общие алгоритмы и именованные запросы.

  • query_extract.py — разбор запросов в коде обработчиков: многострочные литералы 1С, деление пакета, параметры, временные таблицы и их зависимости. Тоже только стандартная библиотека, от индекса не зависит.

  • server.py — инструменты, работа с git, фоновое обновление. Тонкая обёртка: разрешить направление, вызвать функцию индекса, добавить версию правил. Вся логика лежит в rules_index.py, чтобы её можно было проверять тестами без установленного fastmcp.

Отбор регистрации разворачивается в читаемое дерево условий вместо XML:

(ИЛИ:
  (И:
    ВидОперации = ПокупкаКомиссия
    ВидПоступления = ПоОрдеру
    Контрагент.НеЯвляетсяРезидентом = Истина
  )
  …
)

Ответы по умолчанию сжатые: тексты обработчиков отдаются только по запросу (get_conversion_rule с verbose=true), состав справочников приёмника — отдельным вызовом. Иначе один ответ съедает контекст чата.

Исключение — get_rule_handler: он для того и сделан, чтобы отдавать текст целиком. Половина обработчиков короче 170 знаков и приходит одним куском; крупных, больше 20 000 знаков, во всём корпусе четыре десятка, и только им нужны страницы. Самый большой — около 100 000 знаков.

Проверка

python test_rules_index.py /путь/к/каталогу/с/направлениями
python test_reading.py
python test_query_extract.py

test_rules_index.py проверяет на настоящих правилах: направления распознаются с учётом порядка сторон, ветки выгрузки не зовут несуществующих правил конвертации, отбор регистрации разбирается, каскады не зацикливаются, справочники без своей ветки выгрузки находятся через подчинённые правила.

test_reading.py — чтение и поиск: все крупные обработчики читаются страницами и собираются знак в знак, номер строки из поиска годится для чтения, закомментированный вызов правила в выдачу не попадает, многозначное имя правила даёт ошибку с перечнем, а не молчаливый выбор. То же для обработчиков реквизитов: все читаются и собираются, находятся по коду и по имени приёмника, повторяющееся имя приёмника даёт ошибку с перечнем, поиск по ним отсеивает закомментированные строки. Места вызовов правил в trace_document по всему корпусу указывают на живую строку с вызовом и не теряют ни одного вызова; метки процессов ветки делятся на свои и пришедшие без потерь; отбор поиска по имени объекта даёт то же, что по кодам его правил.

test_query_extract.py — разбор запросов по всему корпусу без исключений, номера элементов пакета совпадают с присваиваниями Результат[n], вычисляемые номера не угадываются, у неполного запроса текста нет.

Версии

Номер версии — три числа через точку: основная.дополнительная.исправление.

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

  • дополнительная — новый инструмент или параметр, старое работает как раньше;

  • исправление — ошибка исправлена, поведение по описанию не менялось.

Текущая версия записана в server.py и видна в каждом ответе сервиса («версия сервиса») — так из чата видно, что именно развёрнуто. История — в CHANGELOG.md.

Лицензия

MIT — см. LICENSE.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    MCP server providing tools for interacting with 1С:Напарник AI, including asking questions, syntax explanation, code review, and documentation search. Also serves as a web chat interface and OpenAI-compatible API gateway.
    102
    AGPL 3.0
  • F
    license
    Not graded
    quality
    A
    maintenance
    MCP server that validates AI-generated 1C:Enterprise (BSL) code against the real platform API. Catches unknown enum values, wrong argument counts, and missing type members by parsing the platform syntax-helper (shcntx_ru.hbk) — independent Rust implementation with built-in expression validator.
    24
    -
  • F
    license
    Not graded
    quality
    B
    maintenance
    MCP server for searching and analyzing 1C enterprise metadata and BSL code using a SQLite backend. Enables querying configuration structure, code routines, and performing compliance checks via natural language.
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    MCP server for RAG-based search over 1C Enterprise configuration documentation, enabling natural language queries to find objects like справочники, документы, and отчеты.
    MIT