Skip to content

About

Локальное зеркало истории чатов Bitrix24 с быстрым полнотекстовым поиском для AI-ассистентов (MCP). В Bitrix ничего не пишет.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

bitrix-chat-mcp

Локальное зеркало истории чатов Bitrix24 с точным поиском, доступное AI-ассистентам через MCP.

A local mirror of your Bitrix24 chat history with fast full-text search, exposed to AI assistants over MCP. Read-only against Bitrix: it never posts anything back.

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

Всё держится на машине: SQLite рядом с кодом, никакого облака, никаких эмбеддингов. Node 22+, две зависимости (@modelcontextprotocol/sdk, zod).

В Bitrix этот сервер не пишет никогда. Единственная запись — локальные закладки в своей же базе.

Как это соотносится с bitrix24-local-mcp

Инструменты дополняют друг друга, у них разные задачи:

bitrix24-local-mcp bitrix-chat-mcp (этот)
Про что живое состояние: задачи, свежие сообщения, пользователи память: накопленная история чатов
Пишет в Bitrix да (создать задачу, отправить сообщение) никогда
Поиск по истории тяжело: постранично через API быстро, SQLite FTS5
Без сети не работает работает

Связаны они тремя вещами, без общего кода:

  1. Общий креденшл. Читаем BITRIX24_WEBHOOK_URL из своего .env, а если его нет — из ../bitrix24-local-mcp/.env (сосед опционален, без него всё работает). Один секрет на две тулзы, но процессы независимы: обновление или падение одного не ломает другой.
  2. Общий словарь идентификаторов. Зеркало возвращает dialog_id и message_id — те же, что понимает живой MCP. Это и есть точка стыковки:
    chat_search("ai-rules-check")  →  msg 322265, chat10833
      ↓ те же идентификаторы
    im_chat_messages(chat10833)    →  свежий контекст
    im_send_message(chat10833, …)  →  ответить
    
  3. Подсказки в описаниях инструментов — в них прямо сказано, когда переходить в живой MCP.

Установка

Нужен входящий вебхук Bitrix24 (Приложения → Разработчикам → Входящий вебхук) с правом Мессенджер (im) и Пользователи (user). URL выглядит так: https://ВАШ-ПОРТАЛ.bitrix24.ru/rest/USER_ID/СЕКРЕТНЫЙ_КОД/.

make install
cp .env.example .env     # вписать BITRIX24_WEBHOOK_URL
make ui                  # выбрать чаты -> http://127.0.0.1:7625
make sync                # выкачать историю
make status              # что получилось

⚠️ Вебхук — это полный доступ к порталу под правами его владельца. Храните его как пароль: он лежит в .env, который под .gitignore.

config.json (какие чаты зеркалим) в репозитории не хранится — по одному этому списку видно, с кем человек переписывается. В git лежит только config.example.json; свой создаётся через make ui.

Подключение в ~/.mcp.json (или в конфиге вашего MCP-клиента):

{
  "mcpServers": {
    "bitrix-chat": { "command": "node", "args": ["/путь/к/bitrix-chat-mcp/src/server.mjs"] }
  }
}

После правки конфига Claude Code нужно перезапустить.

Настройка через UI

make ui поднимает страницу выбора чатов: командные каналы и личные переписки разделены, видно объём и глубину уже зеркалируемого. Отметили → «Сохранить» → make sync.

Ограничения страницы намеренные:

  • слушает только 127.0.0.1 — это не сетевой сервис;
  • не показывает и не принимает вебхук — секрет остаётся в .env;
  • ничего не пишет в Bitrix, только правит локальный config.json.

Про личные переписки. Зеркалирование складывает сообщения на диск в открытом виде. В личках нередко передают доступы и ключи — отмечайте их осознанно. По умолчанию в конфиге только командные каналы, вложения не выкачиваются вообще.

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

Инструмент Зачем
chat_search найти, где обсуждали решение или замечание; отдаёт dialog_id + message_id
chat_context сообщение с соседними — понять, чем закончилось обсуждение
chat_list какие чаты в зеркале, объём и глубина
chat_pin отметить сообщение как договорённость с пояснением (локально)
chat_pins все отмеченные договорённости
answer_pending вопросы ко мне, после которых я в том же чате ничего не написал
my_promises мои же «сделаю / отпишу / пришлю» — и писал ли я в чате после

Закладки (chat_pin) — это ответ на «помнить важные замечания»: помеченное не растворяется в истории и достаётся одним вызовом.

Что просело между чатами

answer_pending и my_promises отвечают на два вопроса, которые теряются одинаково — сообщение прочитано, ответ отложен «на потом», и «потом» не наступает.

Что считать «моей темой», задаётся в config.json полем topics (например ["биллинг", "касса", "отчёты"]): по этим словам вопрос считается адресованным вам даже без прямого упоминания. Пустой список — только прямые упоминания и личные диалоги.

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

Что выяснилось на живых данных (две недели переписки, 372 сообщения):

  • Тему надо искать по началу слова, а не подстрокой. «бот» внутри «работал» и «чек» внутри «человек» затаскивали в выдачу чужие ежедневные отчёты: 24 «вопроса» вместо 9.
  • Знак вопроса из ссылки — не вопрос. …/compare/a...b?from_project_id=26 держал в списке сообщение, где вопроса нет вообще.
  • «Сделаю» и «сделал» отличаются одной буквой и противоположны по смыслу, поэтому шаблоны обещаний перечислены точно, без основ слов.

my_promises не решает, выполнено обещание или нет: «сделаю» закрывается коммитом, а не сообщением. Он помечает silent_since — после этого обещания я в чате молчу.

Свой user_id берётся из самого вебхука (/rest/45/секрет/) — без обращения к сети и без вывода секрета наружу.

Синхронизация

make sync   # инкрементально: тянет только то, что появилось после прошлого раза

Первый прогон по чату забирает историю вглубь (ограничение — maxPagesPerChat в config.json), дальше докачиваются только новые сообщения.

Вместе с чатами забираются треды — комментарии к сообщению. В Bitrix тред это отдельный скрытый чат, связь с родительским сообщением лежит в commentInfo. Ветка перекачивается, только если выросла: счётчик из commentInfo сравнивается с сохранённым. В поиске такое сообщение показывается как «Родительский чат · тред», а не голым chat11115.

Про API: у im.dialog.messages.get неочевидная семантика, проверенная экспериментально — FIRST_ID отсутствует → последняя страница; FIRST_ID: 0 → самые старые; FIRST_ID: <id> → сообщения новее указанного. Поэтому курсор двигается по максимальному id, и один код работает и для первой закачки, и для докачки.

Что не индексируется

Системные события и сообщения без текста (звонки, «X вступил в чат», голые вложения) — они только зашумляют поиск. Файлы не выкачиваются.

Из-за этого число сохранённых сообщений ветки меньше, чем messageCount в ответе Bitrix. Признак «ветка выросла» строится на самом messageCount, а не на подсчёте своих строк — иначе каждый прогон перекачивает ветки заново.

Структура

src/
  server.mjs      MCP-сервер (stdio)
  sync.mjs        инкрементальная синхронизация
  ui.mjs          локальная страница настройки
  status.mjs      состояние зеркала
  lib/bitrix.mjs  клиент REST + чтение креденшла
  lib/db.mjs      схема, FTS5, помощники
  lib/attention.mjs  вопросы без ответа и мои обещания (чистые функции)
test/             node --test, запуск: npm test
config.json       какие чаты зеркалим (правится через UI)
data/             БД зеркала (в git не хранится)

Тесты

npm test

Чистые функции разбора (src/lib/attention.mjs) покрыты тестами без обращения к базе и к сети.

Лицензия

MIT — см. LICENSE.

About

Локальное зеркало истории чатов Bitrix24 с быстрым полнотекстовым поиском для AI-ассистентов (MCP). В Bitrix ничего не пишет.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages