bitrix24-mcp-bridge 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,8 +1,9 @@
1
1
  # Bitrix24 MCP Bridge
2
2
 
3
- Локальный MCP-сервер, дающий ИИ-агенту **read-only** доступ к задачам, проектам и чатам
4
- Bitrix24 — в объёме прав пользователя, через браузерное расширение, переиспользующее
5
- живую сессию. Без прав администратора и без официального REST-вебхука.
3
+ Локальный MCP-сервер, дающий ИИ-агенту доступ к задачам, проектам и чатам Bitrix24 (чтение
4
+ и — для вызовов из каталога — выполнение действий) — в объёме прав пользователя, через
5
+ браузерное расширение, переиспользующее живую сессию. Без прав администратора и без
6
+ официального REST-вебхука.
6
7
 
7
8
  ```
8
9
  ИИ-агент ─stdio─► MCP-клиент ─UDS(bridge.sock)─► daemon ─WS(127.0.0.1:39917, токен+Origin)─► Расширение (вкладка портала)
@@ -14,16 +15,21 @@ Bitrix24 — в объёме прав пользователя, через бр
14
15
  ## Быстрый старт
15
16
 
16
17
  ```bash
17
- # 1. Установить CLI глобально (prepare соберёт dist/cli.js + статичные бандлы расширения)
18
- npm i -g github:DarWiM/bitrix24-mcp-bridge
18
+ # 1. Настроить портал через npx — без глобальной установки (интерактивно): токен +
19
+ # первый портал + config.json + actions.json + расширение
20
+ npx -y bitrix24-mcp-bridge setup
19
21
 
20
- # 2. Настроить портал (интерактивно): токен + первый портал + config.json + actions.json + расширение
21
- bitrix24-bridge setup
22
-
23
- # 3. Зарегистрировать сервер у MCP-клиента (пример — Claude Code)
24
- claude mcp add bitrix24-bridge -s user -- bitrix24-bridge
22
+ # 2. Зарегистрировать сервер у MCP-клиента (пример — Claude Code); каждый запуск идёт через npx
23
+ claude mcp add bitrix24-bridge -s user -- npx -y bitrix24-mcp-bridge
25
24
  ```
26
25
 
26
+ Пакет опубликован в npm registry как [`bitrix24-mcp-bridge`](https://www.npmjs.com/package/bitrix24-mcp-bridge)
27
+ (бинарь внутри называется `bitrix24-bridge`, но `npx bitrix24-mcp-bridge` резолвит его напрямую,
28
+ т.к. в `package.json` он объявлен под обоими именами). Глобальная установка (`npm i -g
29
+ bitrix24-mcp-bridge`) тоже работает и чуть быстрее стартует (без резолва npx при каждом
30
+ запуске MCP-клиента) — тогда в шаге 2 подставь `-- bitrix24-bridge` вместо `-- npx -y
31
+ bitrix24-mcp-bridge`.
32
+
27
33
  Затем — два ручных шага, которые нельзя автоматизировать:
28
34
 
29
35
  1. **Загрузить расширение.** `chrome://extensions` → включить **Developer mode** →
@@ -59,8 +65,9 @@ daemon после любой правки, затрагивающей конфи
59
65
 
60
66
  ## Инструменты
61
67
 
62
- Все — read-only, каждый принимает необязательный параметр `portal` (alias; по умолчанию —
63
- портал по умолчанию из `config.json`):
68
+ Типизированные инструменты — read-only; `bitrix_call` выполняет любой разрешённый каталогом
69
+ вызов, включая мутирующие. Каждый принимает необязательный параметр `portal` (alias; по
70
+ умолчанию — портал по умолчанию из `config.json`):
64
71
 
65
72
  | Инструмент | Назначение |
66
73
  |---|---|
@@ -119,9 +126,13 @@ Runtime-домашняя папка — `~/.bitrix24-mcp-bridge/` (или `$BITR
119
126
  привилегия — живая аутентифицированная сессия Bitrix24 — физически в расширении, а не в
120
127
  сервере. Отсюда:
121
128
 
122
- - **Read-only — гарантия «доброй воли», а не защита.** Ограничение на чтение — это
123
- denylist мутирующих глаголов (`…add`/`…update`/`…delete`/…) в каталоге; каталог с
124
- мутирующим вызовом просто не загрузится. Значения `params` при этом не инспектируются.
129
+ - **Граница — это allowlist каталога, не режим чтения.** Мост выполняет только именованные
130
+ вызовы из `actions.json` — теперь среди них могут быть мутирующие. Общий локальный токен
131
+ (риск G7) в write-режиме означает: процесс, знающий токен и порт демона, может выполнять
132
+ эти действия в объёме прав пользователя. Внутри разрешённого действия значения `params`
133
+ не инспектируются — для мутирующего вызова это означает полный контроль агента над телом
134
+ запроса в рамках этого действия. Держи `actions.json` под контролем — это и есть
135
+ граница возможностей агента.
125
136
  - **Токен — единственная защита loopback-WS.** Генерируйте длинный и случайный —
126
137
  `setup` использует `crypto.randomBytes(32)`. Токен отсекает случайные подключения, но
127
138
  не является границей против локального атакующего: любой локальный процесс, знающий
@@ -1,33 +1,29 @@
1
1
  {
2
- "tasks.list": {
3
- "action": "tasks.task.list",
4
- "method": "POST"
5
- },
6
- "task.get": {
7
- "action": "tasks.task.get",
8
- "method": "POST"
9
- },
10
- "projects.list": {
11
- "action": "socialnetwork.api.workgroup.list",
12
- "method": "POST"
13
- },
14
- "projects.get": {
15
- "action": "socialnetwork.api.workgroup.get",
16
- "method": "POST"
17
- },
18
- "chats.recent": {
19
- "endpoint": "/rest/im.recent.list.json",
20
- "method": "POST",
21
- "params": {
22
- "LIMIT": 50,
23
- "SKIP_OPENLINES": "Y",
24
- "GET_ORIGINAL_TEXT": "Y",
25
- "PARSE_TEXT": "Y",
26
- "WITH_COUNTERS": "N"
27
- }
28
- },
29
- "chat.messages": {
30
- "action": "im.v2.Chat.Message.list",
31
- "method": "POST"
32
- }
2
+ "tasks.list": { "action": "tasks.task.list", "method": "POST" },
3
+ "task.get": { "action": "tasks.task.get", "method": "POST" },
4
+ "task.v2.get": { "action": "tasks.v2.Task.get", "method": "POST", "bodyType": "json" },
5
+ "task.scrum.info": { "action": "tasks.v2.Scrum.getTaskInfo", "method": "POST", "bodyType": "json" },
6
+ "task.files": { "action": "tasks.v2.File.listObjects", "method": "POST", "bodyType": "json" },
7
+ "task.views.count": { "action": "tasks.v2.Task.View.User.count", "method": "POST", "bodyType": "json" },
8
+
9
+ "projects.list": { "action": "socialnetwork.api.workgroup.list", "method": "POST" },
10
+ "projects.get": { "action": "socialnetwork.api.workgroup.get", "method": "POST" },
11
+
12
+ "chats.recent": { "endpoint": "/rest/im.recent.list.json", "method": "POST", "params": { "LIMIT": 50, "SKIP_OPENLINES": "Y", "GET_ORIGINAL_TEXT": "Y", "PARSE_TEXT": "Y", "WITH_COUNTERS": "N" } },
13
+ "chat.load": { "action": "im.v2.Chat.load", "method": "POST", "params": { "messageLimit": 25 } },
14
+ "chat.messages": { "action": "im.v2.Chat.Message.list", "method": "POST" },
15
+ "chat.messages.tail": { "action": "im.v2.Chat.Message.tail", "method": "POST", "params": { "order[id]": "DESC", "limit": 25 } },
16
+ "chat.message.read": { "action": "im.v2.Chat.Message.read", "method": "POST" },
17
+
18
+ "entityselector.load": { "action": "ui.entityselector.load", "method": "POST", "bodyType": "json" },
19
+ "entityselector.search": { "action": "ui.entityselector.doSearch", "method": "POST", "bodyType": "json" },
20
+
21
+ "recent.load": { "action": "im.v2.Recent.load", "method": "POST" },
22
+ "recent.tail": { "action": "im.v2.Recent.tail", "method": "POST" },
23
+ "chat.dialogId": { "action": "im.v2.Chat.getDialogId", "method": "POST" },
24
+ "chat.read.all": { "action": "im.v2.Chat.readAll", "method": "POST" },
25
+ "im.user.get": { "endpoint": "/rest/im.user.get.json", "method": "POST" },
26
+
27
+ "task.subtasks": { "action": "tasks.v2.Task.Relation.Child.list", "method": "POST", "bodyType": "json" },
28
+ "task.related": { "action": "tasks.v2.Task.Relation.Related.list", "method": "POST", "bodyType": "json" }
33
29
  }