Ariadna
by amorozov1310
README.md
# Ариадна
Docker-контейнер с MCP-сервером для быстрого поиска по метаданным конфигураций 1С и анализа кода BSL.
AI-агенты (Claude Code, Cursor, Codex) находят нужный объект, реквизит или процедуру за один MCP-вызов вместо сканирования всей кодовой базы — экономя контекст и токены. Есть и Web UI — искать и индексировать можно и без агента, прямо в браузере.
## Возможности
- **Поиск по метаданным** — объекты, реквизиты (и реквизиты форм), типы,
формы; по имени или своими словами («где лежат долги по аренде земельных
долей»), формы слов совпадают — годится и для помощника по данным базы.
Поиск процедур по описанию — `semantic_search_code`. Типичный вызов
инструмента — доли секунды (замер: `search_procedures` на крупной типовой конфигурации, около
550 тыс. процедур, — 0,1–0,15 с). Дольше — `diagnose_index` (читает все
файлы выгрузки) и первый запрос к проекту после перезапуска Docker
Desktop, пока индекс читается с диска (несколько секунд)
- **Граф вызовов BSL** — кто вызывает / что вызывает процедура, с резолвингом
рёбер по факту (включая перехваты `&Вместо`/`&Around` из расширений)
- **Полнотекстовый поиск по коду** — FTS5 по всему тексту модулей, а не только по вызовам
- **RU + EN конфигурации** — русские и английские ключевые слова, директивы,
менеджеры; регистронезависимый поиск, EN-алиасы видов (`Catalog` = `Справочник`)
- **Несколько проектов**, **конфигурация + расширения** (несколько source в одном проекте)
- **Инкрементальная фоновая индексация** — reindex не блокирует, повторный проход
перечитывает только изменённые файлы (по хэшу); при изменении кода
самого парсера индекс сам делает полный переразбор, вручную удалять
`index.db` не нужно
- **Web UI** — управление проектами, поиск, playground для MCP tools;
светлая и тёмная тема, шрифты и иконки локальные — интерфейс полностью
работает без интернета
- **MCP Server** — streamable HTTP, project-scoped tools
- **Эксплуатация** — `/ready` (готовность проектов), манифест индекса,
резервная копия и перенос — [docs/operations.md](docs/operations.md)
## Быстрый старт
Поддерживаемый способ запуска сервера — Docker. Запуск без Docker
(`python -m src.main`) — только для разработки и тестов, см.
«Разработка» и SETUP.md.
### 1. Запуск
```bash
git clone https://github.com/amorozov1310/ariadna-mcp.git
cd ariadna-mcp
docker compose up -d
```
Если образ ещё не собран, а в `docker-wheels/` нет .whl-файлов — сборка
упадёт: зависимости ставятся в образ офлайн из этого каталога (обход
нестабильной сети в docker build). Один раз скачайте колёса (нужен только
Docker, сеть используется из runtime-контейнера):
```bash
docker run --rm -v "$PWD:/repo" -w /repo python:3.12-slim sh docker-wheels/fetch.sh
```
Команда запускается из корня репозитория: список зависимостей берётся из
`pyproject.toml`. На Windows — только из PowerShell с полным путём
(`-v D:\путь\до\ariadna:/repo`): Git Bash искажает пути монтирования.
Повторять при изменении зависимостей в `pyproject.toml` — старые колёса
заменяются новыми, при сбое сети прежний набор остаётся.
Web UI: http://127.0.0.1:19878
MCP (streamable HTTP): http://127.0.0.1:19879/mcp
Адреса — именно `127.0.0.1`, а не `localhost`: на Docker Desktop под
Windows каждое новое HTTP-соединение к `localhost` стоит около 0,26 с
(против ~4 мс к `127.0.0.1`), а streamable HTTP открывает соединение на
каждый вызов инструмента.
### 2. Создание проекта
Откройте Web UI → "Создать проект":
- ID: `demo`
- Название: `Демо-конфигурация`
### 3. Добавление данных
Источник — это XML-выгрузка конфигурации (Конфигуратор → «Выгрузить
конфигурацию в файлы»). Отчёт по конфигурации выгружать **не нужно**:
метаданные (объекты, реквизиты, типы, формы, подсистемы) индексатор
читает прямо из этой же XML.
**Вариант A — Upload через Web UI:**
На странице проекта нажмите «+ Добавить источник» и загрузите
XML-выгрузку (.zip или .tar.gz). Архив проверяется до распаковки:
пути только внутри выгрузки, без ссылок, не больше 1 млн файлов и
64 ГБ в распакованном виде (`ARIADNA_ARCHIVE_MAX_FILES`,
`ARIADNA_ARCHIVE_MAX_BYTES`). Отклонённый архив не трогает прежнюю
выгрузку источника.
**Вариант B — Монтирование volume:**
```bash
# Положить выгрузку на хосте:
mkdir -p data/projects/demo/sources/main/xml
cp -r ВыгрузкаКонфигурации/* data/projects/demo/sources/main/xml/
# Для расширения:
mkdir -p data/projects/demo/sources/ext1/xml
cp -r ВыгрузкаРасширения/* data/projects/demo/sources/ext1/xml/
# Затем в Web UI добавить source и переиндексировать
```
### 4. Индексация
На странице проекта нажмите «Переиндексировать». Прогресс (процент, фаза,
оценка оставшегося времени) виден на дашборде, в том числе если открыть
страницу заново или запустить индексацию из другой вкладки или из MCP.
По завершении страница обновляется сама.
Индексация — фоновый поток внутри процесса и перезапуск не переживает.
Если сервер остановили посреди прогона, при следующем старте статус
`indexing` снимается автоматически (в лог пишется предупреждение), а
прежний индекс остаётся пригодным — прогон достаточно повторить.
Без сервера — командой `ariadna-index <проект> [--source <источник>]`
(ставится с пакетом, `pip install .`); без установки пакета из корня
репозитория — `python -m src.core.indexer <проект>`. Не запускайте её
параллельно с работающим сервером на тех же `data/`: реестр `projects.json`
у них общий.
### 5. Подключение MCP к агенту (по желанию)
Шаги 1–4 уже дают рабочий сервер: искать по метаданным, коду и графу
вызовов можно прямо в Web UI, без какого-либо агента (см. «Web UI» ниже).
Этот шаг — только если нужен доступ из Claude Code, Cursor, Codex и т.п.
Сервер должен быть запущен (`docker compose up -d`), проверка —
`curl http://127.0.0.1:19878/health`.
**Claude Code** — одной командой, для всех проектов на машине:
```bash
claude mcp add --transport http --scope user ariadna http://127.0.0.1:19879/mcp
```
Без `--scope user` сервер подключится только в текущем каталоге. Чтобы
подключение ехало вместе с репозиторием (у всей команды), положите в
корень проекта `.mcp.json` — Claude Code спросит подтверждение при первом
запуске:
```json
{
"mcpServers": {
"ariadna": {
"type": "http",
"url": "http://127.0.0.1:19879/mcp"
}
}
}
```
`"type": "http"` обязателен. `.claude/settings.json` MCP-серверы **не
читает** — конфигурация, положенная туда, молча игнорируется.
Проверка: в Claude Code команда `/mcp` показывает `ariadna` со статусом
connected и 17 инструментами.
**Cursor** — `.cursor/mcp.json` в проекте или `~/.cursor/mcp.json`:
```json
{
"mcpServers": {
"ariadna": { "url": "http://127.0.0.1:19879/mcp" }
}
}
```
Если Cursor запустился раньше сервера (например, сразу после входа в
систему, пока поднимается Docker Desktop), он помечает `ariadna` ошибкой
подключения и **сам не переподключается** — инструментов Ариадны у агента не
будет, хотя Web UI уже работает. Переподключить: Settings → MCP → выключить и
включить `ariadna` (или Ctrl+Shift+P → Reload Window). Ариадну достаточно
прописать в одном месте — либо в `~/.cursor/mcp.json`, либо в
`.cursor/mcp.json` проекта: с одинаковым именем в обоих Cursor использует
одну запись, и вторая только путает.
**Codex CLI** — одной командой:
```bash
codex mcp add ariadna --url http://127.0.0.1:19879/mcp
```
Или вручную в `~/.codex/config.toml` (либо `.codex/config.toml` в
проекте — только для доверенных проектов):
```toml
[mcp_servers.ariadna]
url = "http://127.0.0.1:19879/mcp"
```
Проверка: в composer Codex команда `/mcp` показывает `ariadna` со
статусом connected.
**Сервер на другой машине.** По умолчанию порты публикуются только на
`127.0.0.1` — с других машин сервер недоступен. Чтобы открыть доступ,
задайте адрес публикации явно:
```bash
BIND_ADDR=0.0.0.0 MCP_ALLOWED_HOSTS=192.168.1.10,ariadna.lan docker compose up -d
```
и в клиенте замените `127.0.0.1` на адрес машины. `MCP_ALLOWED_HOSTS` —
имена и адреса, под которыми к серверу обращаются (через запятую; `host` —
любой порт, `host:port` — только этот). MCP и Web UI отклоняют запросы с
другим заголовком `Host` — это защита от DNS rebinding: без неё страница в
браузере могла бы обращаться к серверу на `127.0.0.1` от имени своего
домена. Без `MCP_ALLOWED_HOSTS` пускаются только `127.0.0.1`, `localhost`
и `[::1]`. **Авторизации нет:**
любой, кто достаёт до этих портов, может искать по конфигурации,
запускать переиндексацию и удалять источники. Открывайте порты только в
доверенной сети.
При подключении сервер сам передаёт агенту инструкцию: какой инструмент
для какого вопроса и в каком порядке их вызывать. Типовой диалог:
```python
> list_projects() # если проектов несколько — узнать project_id
> search_metadata(project_id="demo", query="Номенклатура")
> get_object_details(project_id="demo", full_name="Справочник.Номенклатура")
> search_procedures(project_id="demo", query="ЗначениеРеквизитаОбъекта", export_only=true)
> get_procedure_code(project_id="demo", module_name="ОбщегоНазначения",
procedure_name="ЗначениеРеквизитаОбъекта")
> get_call_tree(project_id="demo", procedure_name="ЗначениеРеквизитаОбъекта",
module_name="ОбщегоНазначения", direction="up", depth=2)
> search_code(project_id="demo", query="ВЫБРАТЬ ПЕРВЫЕ 1")
> semantic_search_code(project_id="demo", query="где рассчитывается себестоимость")
```
Без своих правил ничего настраивать не нужно: инструкция сервера уже
объясняет агенту и поиск по описанию (`semantic_search_code`).
**Правила для агента в проекте 1С.** Если в проекте уже есть свои правила
(Cursor rules, `CLAUDE.md`, `AGENTS.md`) и другие MCP-серверы для 1С, агенту
нужно явно сказать, когда звать Ариадну. Готовые шаблоны — в
[docs/agent-rules](docs/agent-rules/README.md): Ариадна как основной индекс,
как вспомогательный рядом с другим сервером или блок для встраивания в уже
существующую цепочку серверов.
## Web UI
http://127.0.0.1:19878 — работает сразу после `docker compose up -d`,
агент не нужен. Здесь же выполняются шаги 2–4 быстрого старта:
- **Проекты** — создание, добавление источников (upload .zip или volume),
запуск переиндексации, прогресс и статистика по каждому.
- **Поиск** — по метаданным (объекты, реквизиты, типы, формы) и по коду
(FTS5 полнотекстовый).
- **Playground** — вызвать любой из 16 MCP-инструментов вручную с формой
параметров и увидеть тот же ответ, что получит агент, — удобно для
проверки сервера и данных без настройки Claude Code/Cursor/Codex.
Инструменты, параметры, их описания и умолчания берутся из схемы
MCP-сервера, ответ строит тот же код, что отвечает агенту; `project_id`
подставляется из проекта страницы. Ошибка инструмента (у агента —
`isError`) выделена. `remove_source` без флажка `confirm` только
показывает, что будет удалено.
- Светлая/тёмная тема, шрифты и иконки — локальные файлы, работает без
интернета.
## Порты
| Сервис | Контейнер | Хост (по умолчанию) | Настройка |
|-------------------|-----------|---------------------|------------------------------|
| MCP streamable HTTP | 9879 | 19879 | `MCP_HTTP_HOST_PORT=33002` |
| Web UI | 9878 | 19878 | `WEB_HOST_PORT=33001` |
```bash
# Свои порты:
MCP_HTTP_HOST_PORT=33002 WEB_HOST_PORT=33001 docker compose up -d
```
## MCP Tools
17 инструментов. Все, кроме `reindex` и `remove_source`, только читают
(помечены `readOnlyHint`), `remove_source` помечен `destructiveHint`.
| Tool | Для какого вопроса |
|---------------------|---------------------------------------------------|
| `list_projects` | Какие проекты есть, их id и статус |
| `list_sources` | Из чего состоит проект: конфигурация, расширения, версии |
| `search_metadata` | Найти объект по имени, синониму или своими словами; фильтр `kind` (RU/EN) |
| `get_object_details`| Карточка объекта: реквизиты с типами, ТЧ, формы; `detail="full"` — целиком |
| `search_attributes` | Найти реквизит (объекта или формы) по имени, синониму или типу |
| `find_references` | Где объект используется как тип реквизита других объектов |
| `list_objects` | Перечень объектов вида (`kind`) |
| `search_procedures` | Найти процедуру/функцию по имени; точные совпадения первыми |
| `get_procedure_code`| Код процедуры с номерами строк |
| `get_module_outline`| Оглавление модуля без чтения кода |
| `get_call_tree` | Кто вызывает (`direction="up"`) / что вызывает (`"down"`) |
| `search_code` | Строка внутри кода: запросы, присваивания, комментарии |
| `semantic_search_code` | Процедура по описанию своими словами; ответ — текст и `structuredContent` с режимом поиска, строками и отпечатками |
| `get_index_status` | Статистика индекса и прогресс переиндексации |
| `reindex` | Переиндексировать (в фоне, инкрементально) |
| `diagnose_index` | Полнота индекса и качество графа вызовов (медленно на крупных конфигурациях) |
| `remove_source` | Удалить источник — без `confirm=true` только показывает, что будет удалено |
Соглашения, общие для всех инструментов:
- **`project_id`** — необязателен, только если в реестре один проект;
иначе ошибка перечисляет доступные id.
- **Имена** — как в конфигураторе, русские или английские, регистр не
важен: `kind="Catalog"` равно `kind="Справочник"`.
- **Имя модуля** (`module_name` — в `get_procedure_code`,
`get_module_outline`, `get_call_tree`) — полное
(`ОбщийМодуль.ОбщегоНазначения.Модуль`,
`Документ.РеализацияТоваровУслуг.МодульОбъекта`), короткое имя общего
модуля (`ОбщегоНазначения`) или часть имени. Точное совпадение
выигрывает у частичного; самый надёжный вариант — скопировать имя из
вывода `search_procedures`.
- **`source_id`** — сужает выдачу до конфигурации или одного расширения.
- **Пагинация** — `limit`/`offset`; строка `use offset=N for more` в конце
выдачи значит, что есть продолжение. `limit` больше 500 урезается до 500
(об этом сказано в конце ответа).
- **Ошибки** приходят клиенту как ошибка инструмента (`isError`) с
понятным текстом: какой проект или источник не найден и какие есть.
- **`search_code`** ищет подстроку без учёта регистра, не регулярное
выражение.
## Структура данных
```
data/
├── projects.json # Реестр проектов
└── projects/
└── demo/
├── index.db # SQLite индекс (FTS5) — при запуске без Docker
└── sources/
├── main/
│ ├── xml/ # XML-выгрузка конфигурации — единственный вход
│ └── report.txt # отчёт по конфигурации, только если нет xml/
└── ext1/
└── xml/
```
В Docker индексы лежат не в `data/`, а на именованном томе
`ariadna-index` (в контейнере — `/index/{проект}/index.db`, переменная
`INDEX_DIR`). В `./data` остаются выгрузки и `projects.json`.
### Индексы в Docker: том `ariadna-index`
Зачем отдельный том. На Docker Desktop под Windows `./data` виден
контейнеру через файловую систему 9p. Поиск процедур делает полный проход
по индексу, и через 9p файл перечитывается при каждом вызове: 3,5–4,5 с на
вызов против 0,1 с на томе. Кроме того, через 9p не работают WAL и
блокировки SQLite.
**Первый старт после обновления.** Сервер один раз переносит существующие
`data/projects/*/index.db` на том: копирует через SQLite backup API (с
данными из WAL) до запуска MCP и Web UI. Каждый перенос с размером и
временем пишется в лог (`docker compose logs`). Время — однократное
чтение файла с `./data` через 9p и запись на том: на Docker Desktop под
Windows индекс крупной конфигурации (~1,2 ГБ) переносится за 25–30 с. Если
копирование проекта не удалось, это тоже будет в логе, а проект просто
переиндексируется.
**Старые файлы.** После переноса `data/projects/*/index.db` (и `-wal`,
`-shm` рядом) контейнером больше не используются — их можно удалить
вручную, когда убедитесь, что поиск работает. Сервер их не удаляет.
**Пересобрать индекс с нуля:** `reindex` в Web UI или через MCP
(переиндексация одного проекта), либо целиком:
`docker compose down && docker volume rm ariadna-index && docker compose up -d`
— затем reindex каждого проекта. Если старые `data/projects/*/index.db`
ещё не удалены, при следующем старте они снова будут перенесены.
**Доступ к индексу с хоста.** В Docker-режиме `index.db` лежит на томе и
с хоста напрямую не виден — открыть его `sqlite3` или DB Browser можно
только внутри контейнера (`docker compose exec ariadna bash`). Поэтому
прежнее правило «не открывать `data/projects/*/index.db`, пока контейнер
запущен» для Docker больше не актуально: контейнер эти файлы не читает.
Оно остаётся в силе, только если запускать контейнер без `INDEX_DIR`
(индексы снова в `./data` через 9p): тогда процесс на хосте, закрывая
соединение, удаляет WAL-файлы из-под сервера, и MCP с Web UI отвечают
`unable to open database file` (лечится `docker restart ariadna`).
**Не запускайте сервер без Docker одновременно с контейнером на одном
`data/`** (`docker compose stop` перед `python -m src.main`): у них общие
`projects.json` и выгрузки. Slow-тесты (`pytest -m slow`) в `data/` не
пишут — для них контейнер останавливать не нужно.
### Эксплуатация
Готовность проектов для оркестратора и скриптов — `GET /ready` (`200` /
`503`, `?project=ID` — один проект), отдельно от `/health` (процесс жив).
Из чего и чем построен индекс — `GET /api/projects/{id}/manifest`: версии
конфигураций, время индексации, версия парсера, покрытие поисковыми
карточками и что требует переиндексации. Резервная копия, перенос на другую
машину и восстановление — [docs/operations.md](docs/operations.md).
## Разработка
Для работы сервер запускается в Docker (см. «Быстрый старт»). Запуск без
Docker — для правки кода и тестов; подробно — SETUP.md, «Разработка без
Docker». Серверы слушают только `127.0.0.1` (`LISTEN_ADDR`).
```bash
# Окружение по pyproject.toml — без него тесты сразу остановятся
# со списком неподходящих пакетов
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
# Переменные (необязательно — ниже значения по умолчанию)
export DATA_DIR=./data
export INDEX_DIR=./index # индексы отдельно от data/ (без неё — data/projects/{id}/index.db)
export WEB_PORT=9878
export MCP_HTTP_PORT=9879 # streamable HTTP
# Сервер без Docker — режим разработки (контейнер на том же data/ остановить)
python -m src.main
# Тесты (быстрые)
python -m pytest tests -q
# Полная переиндексация своих проектов из data/ (id через запятую)
ARIADNA_CORPUS=demo,myconf python -m pytest tests -q -m slow
# Проверка работающего сервера по сети (Docker или без него)
python scripts/live_check.py --project demo
```
### Проверка работающего сервера: `scripts/live_check.py`
Быстрые тесты гоняют код в одном процессе; часть ошибок видна только против
запущенного сервера. `live_check.py` проверяет сервер по сети — так, как его
видят агент (MCP, streamable HTTP) и браузер (Web UI):
- регрессия: версия, 17 инструментов, ошибки, проверка `Host`/`Origin`;
- индексация: сразу после `reindex` статус `indexing`, затем `ready`;
- playground против MCP: для всех 17 инструментов ответы совпадают;
- пересоздание и удаление проекта под нагрузкой MCP и Web UI (ни одного 500,
только «not found»/«проект удалён»);
- стресс: создание и удаление проектов рядом с чтением реестра;
- с `--docker-container ariadna` — нет `/index/<id>` удалённого проекта и
ни одной трассировки или строки ERROR в логе контейнера;
- с `--project ID` — несколько инструментов на вашем проекте (только чтение)
и время `search_procedures`.
Работает на своём временном проекте `zz_live_<суффикс>` из
`tests/fixtures/xml_ru` и удаляет его сам в конце, даже при падении
проверок; существующие проекты не трогает. После обновления сервера:
```bash
python scripts/live_check.py --project demo # Docker, адреса по умолчанию
python scripts/live_check.py --quick --web http://127.0.0.1:9878 --mcp http://127.0.0.1:9879/mcp # без Docker
```
`--quick` — один прогон удаления под нагрузкой и 5 с стресса вместо 5 и
30 с. Код выхода 1 при любом FAIL, в конце — сводка. В CI то же самое идёт на
каждый PR: Docker-образ целиком на Linux и запуск без Docker на Windows.
## Статус
Текущая версия — 1.2.0, история изменений — [CHANGELOG.md](CHANGELOG.md).
Проверено вживую на реальных конфигурациях: две крупные типовые (одна с
расширением), конфигурация с одиннадцатью расширениями и собственная
конфигурация в работе — через Cursor и Claude Code.
Контракт стабилен: в пределах 1.x имена инструментов MCP, их параметры и
смысл ответов не меняются ломающе (подробно — CHANGELOG, «Что гарантирует
1.0»). Новые инструменты и необязательные параметры могут появляться в
минорных версиях; ломающие изменения — только в 2.0.
Замечания из работы (неверный или неполный ответ, лишние вызовы агента,
непонятное описание инструмента) — в GitHub Issues по шаблону «Замечание
из работы» (метка `dogfood`).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues