Skip to main content
Glama
DarWiM

Bitrix24 MCP Bridge

by DarWiM
README.md
# Bitrix24 MCP Bridge

Локальный MCP-сервер, дающий ИИ-агенту доступ к задачам, проектам и чатам Bitrix24 (чтение
и — для вызовов из каталога — выполнение действий) — в объёме прав пользователя, через
браузерное расширение, переиспользующее живую сессию. Без прав администратора и без
официального REST-вебхука.

```
ИИ-агент ─stdio─► MCP-клиент ─UDS(bridge.sock)─► daemon ─WS(127.0.0.1:39917, токен+Origin)─► Расширение (вкладка портала)
                                                                                               │ fetch + свежий sessid + cookie
                                                                                               ▼
                                                                                   Bitrix24 (задачи / группы / чаты)
```

## Быстрый старт

```bash
# 1. Настроить портал через npx — без глобальной установки (интерактивно): токен +
#    первый портал + config.json + actions.json + расширение
npx -y bitrix24-mcp-bridge setup

# 2. Зарегистрировать сервер у MCP-клиента (пример — Claude Code); каждый запуск идёт через npx
claude mcp add bitrix24-bridge -s user -- npx -y bitrix24-mcp-bridge
```

Пакет опубликован в npm registry как [`bitrix24-mcp-bridge`](https://www.npmjs.com/package/bitrix24-mcp-bridge)
(бинарь внутри называется `bitrix24-bridge`, но `npx bitrix24-mcp-bridge` резолвит его напрямую,
т.к. в `package.json` он объявлен под обоими именами). Глобальная установка (`npm i -g
bitrix24-mcp-bridge`) тоже работает и чуть быстрее стартует (без резолва npx при каждом
запуске MCP-клиента) — тогда в шаге 2 подставь `-- bitrix24-bridge` вместо `-- npx -y
bitrix24-mcp-bridge`.

Затем — два ручных шага, которые нельзя автоматизировать:

1. **Загрузить расширение.** `chrome://extensions` → включить **Developer mode** →
   **Load unpacked** → выбрать `~/.bitrix24-mcp-bridge/extension/`.
2. **Открыть залогиненную вкладку** нужного портала и держать её открытой.

Готово. Агент видит инструменты `bitrix_*`; `bitrix_status` покажет, какие порталы
подключены. Bun нужен только мейнтейнерам — конечному пользователю он не требуется.

### Что делает `setup`

- **Первый запуск** (нет `config.json`): спрашивает origin портала и его alias,
  генерирует общий токен (`crypto.randomBytes(32)`), пишет
  `~/.bitrix24-mcp-bridge/config.json`, кладёт стартовый `actions.json`
  (каталог методов) и **материализует расширение** в
  `~/.bitrix24-mcp-bridge/extension/` (статичные JS-бандлы + `config.json` +
  `manifest.json`, собранный под ваши порталы).
- **Повторный запуск** (config уже есть): открывает меню правки —
  `[a]` добавить портал, `[r]` удалить, `[e]` изменить origin, `[d]` сменить
  портал по умолчанию, `[p]` порт, `[t]` ротировать токен, `[u]` обновить
  расширение из установленного пакета, `[q]` выход.

**Обновление пакета** почти полностью автоматическое:

- **Каталог** — новые записи дописываются в ваш `~/.bitrix24-mcp-bridge/actions.json` при следующем
  старте (в stderr — `[catalog] added N new entries…`). Ваши записи и правки не трогаются, а запись,
  которую вы удалили сами, назад не возвращается: доставленные ключи помечаются в
  `catalog-state.json`, поэтому удаление считается решением, а не пробелом.
- **Файлы расширения** в `~/.bitrix24-mcp-bridge/extension/` обновляются там же автоматически, если
  версия пакета изменилась (`[extension] refreshed …`), — запускать `setup` → `[u]` вручную больше не нужно.
- **Один ручной шаг остаётся:** нажать «Обновить» на расширении в `chrome://extensions` и перезагрузить
  вкладку портала. Программно это сделать нельзя — Chrome перечитывает файлы unpacked-расширения только
  сам. Пока этого не сделано, `bitrix_status` возвращает `warning` с версиями моста и расширения, так
  что рассинхрон виден сразу, а не всплывает необъяснимой ошибкой.

**Мультипортальность** поддержана: каждый портал — отдельная запись, а в манифесте
расширения `matches`/`host_permissions` перечисляют ровно сконфигурированные origin'ы
(least-privilege на origin).

daemon читает `config.json` только при старте, поэтому `setup` сам останавливает работающий
daemon после любой правки, затрагивающей конфиг — следующий вызов агента поднимет новый daemon с
актуальным конфигом. Если daemon почему-то не остановился (не было соединения), останови его
вручную (`pkill -f -- --daemon`). Дополнительно:
- сменили набор порталов (add/remove/edit) → **перезагрузить расширение** в `chrome://extensions`;
- сменили порт или токен → **переоткрыть вкладку** портала.

## Инструменты

Помимо `bitrix_help` / `bitrix_status` / `bitrix_call`, мост регистрирует типизированные обёртки
над каталогом (разумные дефолты + схема параметров). Регистрируются только те, чьё имя есть в
`actions.json`. Точная выборка — через необязательный `params` (мержится последним, перекрывает
дефолты). Каждый принимает необязательный `portal` (alias; по умолчанию — из `config.json`).
Обёртки в основном read-only; мутирующие помечены ⚠. `bitrix_call` выполняет любой разрешённый
каталогом вызов, включая мутирующие.

| Инструмент | Назначение |
|---|---|
| `bitrix_help` | справка по API/params (= `docs/api-notes.md`) |
| `bitrix_status` | какие порталы сконфигурированы и подключены |
| `bitrix_call` | любой разрешённый вызов из каталога по имени (в т.ч. мутирующий) |
| *Задачи* | |
| `bitrix_tasks_list` / `bitrix_task_get` | список задач / карточка |
| `bitrix_task_get_v2` | карточка через v2-подсистему (JSON) |
| `bitrix_task_scrum_info` | scrum-инфо (спринт / эпик / story points) |
| `bitrix_task_files` | файлы задачи |
| `bitrix_task_views_count` | счётчик просмотров |
| `bitrix_task_subtasks` / `bitrix_task_related` | подзадачи / связанные задачи |
| *Проекты* | |
| `bitrix_projects_list` / `bitrix_project_get` | рабочие группы / проекты |
| *Чаты* | |
| `bitrix_chats_recent` | недавние чаты (REST) |
| `bitrix_recent_load` / `bitrix_recent_tail` | недавние по секции (в т.ч. `tasksTask` — чаты задач) + листание |
| `bitrix_chat_load` | открыть чат по `dialogId`/`chatId` |
| `bitrix_chat_messages` | последние сообщения чата |
| `bitrix_chat_history` | листать историю вглубь |
| `bitrix_chat_get_dialog_id` | резолв dialogId по externalId |
| `bitrix_chat_mark_read` ⚠ / `bitrix_chat_read_all` ⚠ | пометить сообщения / все чаты прочитанными |
| *Люди / поиск* | |
| `bitrix_user_get` | карточка пользователя |
| `bitrix_entity_selector` / `bitrix_entity_search` | загрузка селектора / текстовый поиск сущностей |
| `bitrix_entity_chat` | chatId чата связанного объекта (задача/группа/CRM) через `im.chat.get` |

`bitrix_help` — единственный источник конвенций params (select/filter/order/пагинация,
имена полей). Он отдаёт `docs/api-notes.md`, так что любому агенту не нужен доступ к репозиторию.

## Архитектура

Модель — **один долгоживущий daemon + N тонких клиентов**:

- **daemon** (`bitrix24-bridge --daemon`) владеет тремя ресурсами: WS-портом
  `127.0.0.1:39917`, подключениями расширений (маршрутизация запросов по `Origin`
  вкладки к нужному порталу) и Unix-domain-сокетом
  `~/.bitrix24-mcp-bridge/bridge.sock` (права `0600`).
- **MCP-клиент** (`bitrix24-bridge`, без флагов) — то, что запускает ваш MCP-хост по
  stdio. Это тонкий UDS-клиент: он **сам поднимает daemon**, если сокета ещё нет, и
  подключается к нему.

Зачем так: раньше каждый MCP-клиент пытался открыть WS-порт сам, и второй экземпляр
(или health-probe хоста) падал с конфликтом порта. Теперь порт держит только daemon, а
любое число клиентов и проб сосуществуют через сокет. Daemon **сам завершается по
простою** (~5 минут без клиентов).

### Состояния (что видит агент)

- **unconfigured** — `config.json` ещё нет. Сервер всё равно стартует по stdio и
  регистрирует только `bitrix_help` + `bitrix_status`, которые направляют выполнить
  `bitrix24-bridge setup`. Настройка **никогда** не происходит в чате.
- **configured, вкладка закрыта** — портал сконфигурирован, но нет открытой залогиненной
  вкладки → `bitrix_status` покажет портал как не подключённый; откройте вкладку.
- **live** — вкладка открыта, расширение подключено, вызовы проходят.

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

Runtime-домашняя папка — `~/.bitrix24-mcp-bridge/` (или `$BITRIX24_MCP_BRIDGE_HOME`).
В ней: `config.json`, `actions.json`, `bridge.sock`, `extension/`.

Разрешение настроек слоями (побеждает верхний): **env → `.env` (только для разработки)
→ `~/.bitrix24-mcp-bridge/config.json`**. Каталог методов по умолчанию берётся из
`~/.bitrix24-mcp-bridge/actions.json`; явный `BITRIX_CATALOG` (или `catalog` в config)
по-прежнему поддержан.

## Безопасность и модель доверия

Это research/PoC-инструмент в публичном репозитории. Прочтите перед использованием.

**Граница доверия — локальная машина.** daemon слушает только `127.0.0.1`, требует токен
первым сообщением и проверяет `Origin` (защита от cross-site WebSocket hijacking). Но сама
привилегия — живая аутентифицированная сессия Bitrix24 — физически в расширении, а не в
сервере. Отсюда:

- **Граница — это allowlist каталога, не режим чтения.** Мост выполняет только именованные
  вызовы из `actions.json` — теперь среди них могут быть мутирующие. Общий локальный токен
  (риск G7) в write-режиме означает: процесс, знающий токен и порт демона, может выполнять
  эти действия в объёме прав пользователя. Внутри разрешённого действия значения `params`
  не инспектируются — для мутирующего вызова это означает полный контроль агента над телом
  запроса в рамках этого действия. Держи `actions.json` под контролем — это и есть
  граница возможностей агента.
- **Токен — единственная защита loopback-WS.** Генерируйте длинный и случайный —
  `setup` использует `crypto.randomBytes(32)`. Токен отсекает случайные подключения, но
  не является границей против локального атакующего: любой локальный процесс, знающий
  токен, может управлять мостом в объёме сессии.
- **Токен и WS живут только в ISOLATED-мире расширения.** Страница портала (MAIN world)
  не может прочитать `config.json` расширения, потому что запись помечена
  `use_dynamic_url: true` — URL ресурса непредсказуем со страницы. Подробности — в
  [`extension/README.md`](extension/README.md).
- **UDS-граница — права ФС.** Сокет `bridge.sock` создаётся с режимом `0600`.
- **Origin-allowlist.** daemon отклоняет WS-подключения, чей `Origin` не входит в
  сконфигурированный набор порталов.

**Вывод:** запускайте только на доверенной машине, где вы контролируете локальные процессы;
не используйте на общих или недоверенных хостах.

Полный операционный гайд и диагностика — **[docs/RUNBOOK.md](docs/RUNBOOK.md)**.

## Разработка

Bun — инструмент разработчика/мейнтейнера (конечному пользователю не нужен).

```bash
bun install
bun run src/index.ts            # MCP-клиент (default); сам поднимет daemon
bun run src/index.ts --daemon   # daemon вручную
bun run src/index.ts setup      # интерактивная настройка
bun test                        # юнит-тесты (bun:test)
bun run typecheck               # tsc --noEmit (сервер + extension)
bun run build:dist              # бандл сервера → dist/cli.js
bun run build:ext               # dev-сборка расширения → extension/dev/ (загружаемое)
bun run sync:runtime            # применить репо-изменения к живому daemon (см. ниже)
```

`.env` — **только dev-оверрайды** (gitignored). Токен / origin / порт берутся из общего
`~/.bitrix24-mcp-bridge/config.json` (через `loadConfig`) — дублировать их в `.env` не нужно, иначе
dev-токен разойдётся с daemon. Осмысленно держать там лишь `BITRIX_CATALOG` (указывает
dev-сборку/daemon на репозиторный `actions.json`). В проде весь конфиг — в
`~/.bitrix24-mcp-bridge/config.json`, который пишет `setup`.

**Репо ≠ живой daemon.** Daemon, к которому ходят агенты, читает **runtime-папку**
(`~/.bitrix24-mcp-bridge/actions.json` + запущенный `dist/cli.js`), а не файлы репозитория. После
правки каталога или кода сервера выполни **`bun run sync:runtime`**: она пересоберёт бандл, скопирует
репо-`actions.json` в runtime-папку и погасит daemon (следующий вызов агента поднимет свежий). Без
этого новые инструменты/методы агенту не видны.

Дистрибуция: `bin` `bitrix24-bridge` → `dist/cli.js`; npm-хук `prepare` при установке
собирает и `dist/cli.js`, и статичные бандлы расширения (`extension/dist/`), которые
`setup` затем копирует в runtime-домашнюю папку. Публикуемые файлы перечислены в `files`
(`dist`, `extension/dist`, `docs/api-notes.md`, `actions.example.json`).

### Релизы

Версионирование и публикация автоматизированы (conventional commits →
[release-please](.github/workflows/release-please.yml)): бот ведёт release-PR с bump'ом версии и
`CHANGELOG.md`; при его мерже создаётся GitHub Release/тег и пакет публикуется в npm через **OIDC
Trusted Publisher** (с provenance, без токенов). CI ([`.github/workflows/ci.yml`](.github/workflows/ci.yml))
гоняет `typecheck` + тесты на push/PR. Ручная до-публикация застрявшего релиза — `workflow_dispatch`
на `release-please`.

## Документация

- [docs/RUNBOOK.md](docs/RUNBOOK.md) — установка, настройка, повседневная работа, диагностика
- [docs/api-notes.md](docs/api-notes.md) — карта API Bitrix24 для агента (единый источник для `bitrix_help`)
- [docs/reconnaissance.md](docs/reconnaissance.md) — capture, транспорт записи каталога, расширение `actions.json`
- [extension/README.md](extension/README.md) — устройство расширения и модель доверия