Skip to main content
Glama
KarpovPartnersCom

Bitrix24 MCP Bridge

Bitrix24 MCP Bridge

A bridge between Claude (MCP) and Bitrix24 CRM/Tasks. Deployed on Beget hosting at mcp-bitrix.karpovpartners-it.ru.

1. Why this was needed

Initially, we tried to connect Claude to Bitrix24 through the built-in "MCP connections" connector in Bitrix24 (the aiassistant.bitrix_mcp app / the "B24" button in the marketplace). It turned out that this feature does not work: the /authorize, /.well-known/oauth-authorization-server, /.well-known/oauth-protected-resource endpoints return a bare nginx 404, even though all settings and the subscription are in order. This is a bug/unfinished feature on the Bitrix24 side, not a configuration error.

As a workaround, a custom MCP server (a "bridge") was written, which:

  • accepts MCP requests from Claude over the Streamable HTTP protocol;

  • translates them into calls to the regular Bitrix24 REST API via an inbound webhook (created in Bitrix24 with rights only to CRM + Tasks);

  • returns the result back to Claude in the form of MCP tool responses.

Related MCP server: fast-bitrix24-mcp

2. Architecture and files

File

Purpose

server.mjs

Main bridge code (ES module). Starts an Express server, parses MCP requests via @modelcontextprotocol/sdk, calls the Bitrix24 REST API.

app.js

Thin CommonJS wrapper for launching server.mjs. Needed due to a Passenger quirk on Beget (see below).

package.json

Dependencies: @modelcontextprotocol/sdk, express, zod, undici.

.htaccess.example

Phusion Passenger configuration template plus environment variables. The real .htaccess with production secrets is not stored in the repository (see .gitignore) — it is deployed directly on the server and kept separately by the project owner.

What tools are available in Claude

  • bitrix24_call — call any crm.*, task.*, tasks.*, user.current, profile method directly (escape hatch).

  • bitrix24_list_crm / bitrix24_get_crm / bitrix24_add_crm / bitrix24_update_crm — list/read/create/update CRM records (lead, deal, contact, company).

  • bitrix24_list_tasks / bitrix24_add_task / bitrix24_update_task / bitrix24_complete_task — work with tasks.

The server strictly restricts the Bitrix24 methods it can call to the crm., task., tasks., user.current, profile prefixes (see ALLOWED_METHOD_PREFIXES in server.mjs) — this is protection in case the webhook ever gets broader rights.

3. Authentication / security

Custom MCP connectors in the Claude interface have no field for arbitrary HTTP headers — only a URL (plus optional OAuth Client ID/Secret). Therefore, instead of an Authorization header, the secret is embedded in the URL path:

https://mcp-bitrix.karpovpartners-it.ru/mcp/<секрет>

The secret and the Bitrix24 webhook address are stored only in the production .htaccess on the server and in a private copy held by the project owner — they are deliberately not committed to this repository (see .gitignore). Anyone who learns the secret from the URL will get access to the Bitrix24 CRM and tasks within the webhook's rights.

4. How it works step by step

  1. Claude opens the MCP connector → POST to /mcp/<secret> with the body {"method":"initialize", ...}.

  2. The Express route in server.mjs creates a new McpServer (StreamableHTTPServerTransport, sessionIdGenerator: undefined — a server without session persistence, each request is independent).

  3. Claude calls tools/list, then tools/call with a specific tool (for example bitrix24_list_crm).

  4. server.mjs calls bitrixCall(method, params), which makes a fetch() to https://<portal>.bitrix24.ru/rest/<id>/<webhook>/<method>.json.

  5. The Bitrix24 response is wrapped in MCP format and sent back to Claude.

5. Deployment from scratch

  1. Create an inbound webhook in Bitrix24: Settings → Developers → Other → Inbound webhook. Rights — minimum CRM + Tasks.

  2. Clone the repository to the server, into the site directory (public_html of your domain/subdomain).

  3. npm install in that directory (installs express, zod, @modelcontextprotocol/sdk, undici).

  4. Copy .htaccess.example to .htaccess and set the real BITRIX_WEBHOOK_URL and MCP_PATH_SECRET.

  5. On Beget: mkdir tmp && touch tmp/restart.txt — the Passenger command to restart the app after any code changes.

  6. In the Beget panel: "Sites" → for the desired site → "⋮" → "Attach domain" — without this step Apache won't even try to reach your code (see section 6.2 — easy to forget, the error is non-obvious).

6. Problems encountered during deployment on Beget and how they were solved

A debugging log — useful for redeployment on Beget or another shared hosting with an old Node.js.

6.1. Node.js on Beget — version 16.20.2, too old

On the Beget side (Ubuntu 18.04, glibc 2.27), official Node 18+ builds do not run (GLIBC_2.28' not found). We had to stay on Node 16.20.2 and manually provide the global objects missing in Node 16 that modern dependencies need (@modelcontextprotocol/sdk, Express 5):

  • fetch, Headers, Request, Response — via the undici package.

  • crypto (Web Crypto API, crypto.randomUUID()) — via the built-in node:crypto (webcrypto).

  • ReadableStream, WritableStream, TransformStream — via the built-in node:stream/web.

  • structuredClone, MessageChannel/MessagePort — just in case, via node:v8 and node:worker_threads.

All of this is at the very beginning of server.mjs, before importing Express and the MCP SDK (done via await import(...), not a regular import at the top of the file — see the next point for why).

6.2. The domain was not "attached" to the site folder

After uploading the code to the server, the site served the signature Beget page "Domain is not attached to a directory on the server" instead of the application. Simply creating a site folder and uploading files there is not enough — the domain must be separately "attached" via the panel: Sites → the desired site → ⋮ → "Attach domain". A non-obvious step that is easy to miss.

6.3. ERR_REQUIRE_ESM: Passenger cannot load ES modules

Passenger on Beget (old version, passenger40) launches the entry file via require(), and require() in Node fundamentally cannot load ES modules (import/export, type: module in package.json). server.mjs uses await at the top level of the file — which is only possible in an ES module.

Solution: package.json has no "type": "module" (by default .js is CommonJS), the code itself lives in a file with the .mjs extension (the .mjs extension is always an ES module, regardless of package.json), and the entry point for Passenger is app.js — a tiny CommonJS file:

// app.js
import('./server.mjs').catch((err) => {
  console.error('Failed to start server:', err);
  process.exit(1);
});

require() loads app.js fine (it's plain CommonJS), and inside it a dynamic import() (a function, not a declaration) can asynchronously load the ES module server.mjs.

6.4. Secret in the URL path

MCP_PATH_SECRET — a random string (e.g., secrets.token_urlsafe(32) in Python, or crypto.randomUUID() + crypto.randomUUID() in the browser console). If the secret needs to be reissued — generate a new one and update it in .htaccess on the server and in the connector settings in Claude.

7. How to connect in Claude

  1. claude.ai → Settings → Connectors → Add custom connector.

  2. Name: Bitrix24 (any).

  3. Remote MCP server URL: https://mcp-bitrix.karpovpartners-it.ru/mcp/<secret>

  4. OAuth Client ID / Secret — leave empty, they are not needed (authorization is already embedded in the URL).

  5. Save, enable the connector in the chat.

8. Open question — native Bitrix24 MCP connector

It is worth writing to Bitrix24 support about the broken native MCP connector ("B24" in the marketplace): /authorize and the standard OAuth-discovery endpoints return a bare nginx 404 with settings enabled and an active subscription. When/if Bitrix24 fixes this, we can switch to the official connector — or keep this bridge, it also works and gives more control (for example, restricting methods to CRM+Tasks right in the code).

F
license - not found
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Provides a REST API and MCP server to interact with Bitrix24 CRM, enabling CRUD operations on entities like deals, leads, contacts, and tasks via natural language.
    10
    13
  • F
    license
    Not graded
    quality
    C
    maintenance
    MCP server for interacting with Bitrix24 REST API, enabling CRUD operations on deals, contacts, companies, users, leads, and tasks, plus analytics and risk assessment.
    2
  • F
    license
    Not graded
    quality
    D
    maintenance
    Production-grade MCP server for Bitrix24 Cloud with 45 tools, safe by default. Connects Claude Desktop to your Bitrix24 tenant for AI-driven CRM, tasks, messaging, and calendar operations.

View all related MCP servers

Related MCP Connectors

  • Hosted MCP server connecting claude.ai, ChatGPT and other AI apps to your own computer

  • Uptime, SSL, DNS and domain monitoring you can talk to from Claude or any MCP client.

  • MCP server for LeadDelta — manage LinkedIn connections and CRM data via AI assistants.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/KarpovPartnersCom/bitrix24-mcp-bridge-claude'

If you have feedback or need assistance with the MCP directory API, please join our Discord server