bitrix24-mcp-server
A secure-by-default, self-hosted Model Context Protocol server for Bitrix24 CRM. It discovers portal-specific schemas and smart-process automations (SPAs), reads CRM data, and optionally performs confirmation-gated writes.
This is an independent open-source project and is not an official Bitrix24 product. Test it against a non-production portal before using it in production. Effective access always depends on the Bitrix24 OAuth user's permissions and the OAuth application's scopes.
What is included
- Bring-your-own Bitrix24 OAuth application with an automatic MCP-to-Bitrix24 authorization-code flow and refresh tokens.
- AES-256-GCM token encryption in PostgreSQL and concurrency-safe automatic refresh.
- Read-only tools for connections, entity types, fields, funnels, stages, users, and CRM items.
- Dynamic discovery for SPAs through
crm.type.listand universalcrm.item.*methods. - Schema metadata cache with explicit invalidation.
- Prepared create/update/stage-move operations that require a separate confirmation call.
- Audit records for prepared, completed, failed, and cancelled writes.
- Stateless Streamable HTTP MCP transport with OAuth 2.1, PKCE, dynamic client registration, refresh tokens, and legacy static-bearer compatibility.
- Docker Compose and Coolify-ready deployment.
Raw REST calls, deletion, schema administration, robots, Bizproc, and event binding are deliberately not exposed in this release.
Quick start
Requirements: Node.js 20.11+, PostgreSQL 14+ (16 recommended), and a local/public Bitrix24 OAuth application with CRM scope.
Version 0.3.1 accepts hosted *.bitrix24.* cloud portal domains and the exact custom portal configured through BITRIX_PORTAL_DOMAIN. Other custom and on-premise domains remain rejected.
cp .env.example .env
npm ci
npm run build
npm start
Create the two secrets shown in .env.example; keep TOKEN_ENCRYPTION_KEY stable for the lifetime of the database. Configure the Bitrix24 local application handler as:
https://your-server.example.com/oauth/bitrix/callback
Set BITRIX_PORTAL_DOMAIN to the hosted or custom portal URL, such as your-portal.bitrix24.com or https://crm.example.com/. A custom domain is accepted only when it matches this operator-managed value exactly. The variable can be omitted when the installation callback has already stored exactly one active hosted portal in the database.
The server applies its database migration automatically at startup. Start authorization in a browser while sending the MCP bearer token:
curl -i \
-H "Authorization: Bearer $MCP_AUTH_TOKEN" \
"https://your-server.example.com/oauth/bitrix/start?domain=your-portal.bitrix24.com"
Follow the Location redirect. The callback returns a safe connection object containing the id used by MCP tools; it never returns OAuth tokens.
API-only local application installation
For a Bitrix24 local server-side application with Uses API only enabled, configure:
Handler path: https://your-server.example.com/oauth/bitrix/callback
Initial installation path: https://your-server.example.com/oauth/bitrix/install
Bitrix24 sends the initial token pair as a form-encoded auth object. The installation endpoint validates that token against the portal's app.info method before encrypting and storing it. A deployment may initially use a pending-* client ID while Bitrix24 creates the local app; replace the placeholder client ID and secret immediately after Bitrix24 displays them so refresh-token renewal can work.
Connect an MCP client
The recommended remote flow is federated OAuth. The server publishes OAuth 2.1 protected-resource and authorization-server metadata, supports dynamic client registration (DCR), and requires S256 PKCE. Its /authorize endpoint redirects directly to the configured Bitrix24 portal. After the user logs in and grants access, Bitrix24 returns to the server, the server stores the encrypted Bitrix24 token pair, and the browser returns automatically to the MCP client's callback. No MCP token is typed into a browser.
Every OAuth access token issued to an MCP client is bound to the Bitrix24 connection and user profile that completed authorization. That client can list and operate only on its bound connection. The static MCP_AUTH_TOKEN remains an operator-only compatibility and recovery mechanism.
Use this Streamable HTTP URL:
https://your-server.example.com/mcp
Claude custom connector
Add the MCP URL and leave the advanced OAuth Client ID and Client Secret fields empty. Claude registers itself through DCR. Select Connect; the browser goes to Bitrix24 for login/consent and then returns automatically to Claude.
Claude Code
Claude Code can use OAuth:
claude mcp add --transport http bitrix24 https://your-server.example.com/mcp
Open /mcp inside Claude Code and complete the Bitrix24 login/consent. For an operator-only static-token setup, add --header "Authorization: Bearer <MCP_AUTH_TOKEN>" to the command.
Codex
Add the remote server, then start the OAuth login:
codex mcp add bitrix24 --url https://your-server.example.com/mcp
codex mcp login bitrix24
Codex can also retain static-bearer compatibility through ~/.codex/config.toml:
[mcp_servers.bitrix24]
url = "https://your-server.example.com/mcp"
bearer_token_env_var = "BITRIX24_MCP_TOKEN"
Generic static-bearer clients
Clients that can set arbitrary headers may continue to send:
Authorization: Bearer <MCP_AUTH_TOKEN>
Example client configuration (exact keys vary by MCP client):
{
"mcpServers": {
"bitrix24": {
"url": "https://your-server.example.com/mcp",
"headers": {
"Authorization": "Bearer replace-with-your-token"
}
}
}
}
For local stdio use, set MCP_TRANSPORT=stdio and run node dist/index.js. OAuth still needs the HTTP transport temporarily or an existing connection in the same database. Diagnostic logs go to stderr so they do not corrupt MCP stdio messages.
Tools
Read-only:
bitrix_list_connectionsbitrix_discover_portalbitrix_list_crm_entitiesbitrix_describe_entitybitrix_list_fieldsbitrix_list_categoriesbitrix_list_stagesbitrix_refresh_schema_cachebitrix_search_itemsbitrix_get_itembitrix_list_users
Confirmation-gated writes:
bitrix_prepare_create_itembitrix_prepare_update_itembitrix_prepare_move_item_stagebitrix_confirm_operationbitrix_cancel_operationbitrix_list_pending_operations
The write workflow is intentionally two-step:
prepare request -> pending operation and human summary -> explicit confirm -> Bitrix24 call -> audit record
To allow preparation for a portal, initiate OAuth with ?mode=write_with_confirmation. The default read_only mode denies preparation as well as execution. Confirmation is atomic: concurrent confirmation requests cannot execute one operation twice. Pending operations expire after ten minutes by default.
Configuration
| Variable | Required | Default | Purpose |
|---|---|---|---|
APP_URL |
yes | — | Public server URL; HTTPS except localhost |
DATABASE_URL |
yes | — | PostgreSQL connection string |
DATABASE_SSL |
no | false |
Require a verified TLS PostgreSQL connection |
BITRIX_CLIENT_ID |
yes | — | Deployment-owned Bitrix24 OAuth app ID |
BITRIX_CLIENT_SECRET |
yes | — | Deployment-owned Bitrix24 OAuth app secret |
BITRIX_PORTAL_DOMAIN |
conditional | stored portal | Portal used for the automatic OAuth redirect and exact allowlist entry for a custom domain |
MCP_AUTH_TOKEN |
yes | — | Operator-only static bearer fallback, minimum 32 characters |
TOKEN_ENCRYPTION_KEY |
yes | — | Stable 32-byte base64 or 64-character hex key |
BITRIX_MCP_DEFAULT_MODE |
no | read_only |
Mode assigned during OAuth unless overridden |
BITRIX_MCP_ADMIN_TOOLS |
no | false |
Stored policy flag; no admin tools are exposed yet |
SCHEMA_CACHE_TTL_SECONDS |
no | 900 |
Metadata cache lifetime |
PENDING_OPERATION_TTL_SECONDS |
no | 600 |
Confirmation window |
MCP_OAUTH_ACCESS_TOKEN_TTL_SECONDS |
no | 3600 |
MCP OAuth access-token lifetime |
MCP_OAUTH_REFRESH_TOKEN_TTL_SECONDS |
no | 2592000 |
MCP OAuth refresh-token lifetime |
BITRIX_MAX_PAGES |
no | 20 |
Pagination safety cap per tool call |
See .env.example for all runtime and retry settings.
Docker and Coolify
For local Compose, set DATABASE_URL to use hostname postgres and make it agree with the PostgreSQL variables:
DATABASE_URL=postgresql://bitrix_mcp:<POSTGRES_PASSWORD>@postgres:5432/bitrix_mcp
Then run docker compose up --build; Compose automatically loads docker-compose.override.yml to publish port 3000 for local use. In Coolify, deploy only docker-compose.yml, attach a public HTTPS domain to the app service on port 3000, and set every variable marked required by Compose. The production stack exposes the app only to Coolify's proxy network. Persistent storage is the postgres_data volume, and PostgreSQL is never published on the host.
Architecture
MCP client
-> OAuth 2.1 / PKCE authorization request
-> Bitrix24 login and consent
-> Bitrix24 callback and encrypted profile token storage
-> MCP token bound to that Bitrix24 connection
-> MCP tools
-> policy guard / confirmation workflow
-> CRM and schema services
-> token manager and encrypted PostgreSQL store
-> Bitrix24 OAuth / REST API
All REST calls pass through one client for token refresh, timeouts, bounded retries, pagination at the service layer, and sanitized logging. Metadata resolution never guesses when an exact entity name is unavailable.
See SECURITY.md before production deployment and CONTRIBUTING.md before adding new tools.