Connect your AI (MCP)
BottleCRM ships a Model Context Protocol (MCP) server, bcrm-mcp, that lets an AI assistant — Claude Desktop, Cursor, or any MCP-capable agent — work directly inside your CRM. Ask it to "show my open leads this week", "create a contact for Acme Corp", or "convert that lead to an opportunity", and it does the work through your CRM's API.
The agent acts as you: it authenticates with a personal access token and inherits exactly your role and your organization's data — never more. Every request is checked by the same permissions, validation, and tenant isolation that guard the web app.
Availability. The MCP server is part of the open-source community edition. There are two ways to connect: the hosted HTTP endpoint at
https://api.bottlecrm.io/mcp(nothing to install — just a URL and your token; recommended), or the local stdio server you run yourself withuvx bcrm-mcp. Both authenticate with the same personal access token and expose the same tools.
How it works
The MCP server is a thin layer over the BottleCRM REST API. It holds no database of its own and stores no data — it forwards each tool call to the API and returns the result.
You, in your AI client MCP server Your BottleCRM
────────────────────── ────────── ──────────────
"Show my open leads" ─▶ https://api.bottlecrm.io/mcp ─▶ REST API (auth +
(or local `uvx bcrm-mcp`) permissions + RLS +
"Here are 12 leads…" ◀─ formats the response ◀─ validation)
With the hosted endpoint, each request carries your token in its Authorization header, so the server acts strictly as you for that call — it never holds a shared identity. Because every action goes through the API, the AI cannot bypass any security rule. The backend is the only trust boundary.
Step 1 — Create a personal access token
- Open the BottleCRM app (
https://app.bottlecrm.io, or your own app domain) and go to Settings → API Tokens. - Click Create token, give it a recognizable name (e.g. "My Claude Desktop"), and optionally set an expiry.
- Copy the token (it starts with
bcrm_pat_) immediately — it is shown only once and can never be retrieved again.
A token carries your identity. Anyone who has it can do what you can do in your org, so treat it like a password. You can revoke it from the same page at any time, and the next request from that token will fail.
Step 2 — Add the server to your AI client
Pick one of the two methods. The hosted endpoint needs nothing installed; the local server runs on your machine. The Settings → API Tokens page in the app shows both, pre-filled with your token.
Option A — Hosted endpoint (recommended, no install)
Point your client at the remote URL and send your token in the Authorization header. Nothing to install — no Python, no uv.
{
"mcpServers": {
"bottlecrm": {
"type": "http",
"url": "https://api.bottlecrm.io/mcp",
"headers": {
"Authorization": "Bearer bcrm_pat_…"
}
}
}
}
Use your own API domain in place of https://api.bottlecrm.io if you self-host (the path is always /mcp). Most MCP clients that support remote servers use this url + headers shape; a few name the field serverUrl or omit "type" — check your client's docs if it doesn't connect.
Option B — Local server with uvx (stdio)
Run the server locally; the client launches it and passes your CRM URL and token as environment variables. Claude Desktop, Cursor, and Gemini CLI use the same mcpServers JSON — only the config file differs. Codex CLI uses TOML.
| Client | Config file |
|---|---|
| Claude Desktop | claude_desktop_config.json (Settings → Developer → Edit Config) |
| Cursor | ~/.cursor/mcp.json, or .cursor/mcp.json per project |
| Gemini CLI | ~/.gemini/settings.json |
| Codex CLI | ~/.codex/config.toml |
For the JSON clients (Claude Desktop, Cursor, Gemini CLI):
{
"mcpServers": {
"bottlecrm": {
"command": "uvx",
"args": ["bcrm-mcp"],
"env": {
"BCRM_BASE_URL": "https://api.bottlecrm.io",
"BCRM_TOKEN": "bcrm_pat_…"
}
}
}
}
For Codex CLI (TOML):
[mcp_servers.bottlecrm]
command = "uvx"
args = ["bcrm-mcp"]
[mcp_servers.bottlecrm.env]
BCRM_BASE_URL = "https://api.bottlecrm.io"
BCRM_TOKEN = "bcrm_pat_…"
| Variable | Description |
|---|---|
BCRM_BASE_URL |
The API host — https://api.bottlecrm.io for hosted BottleCRM, or your own API domain if self-hosting. |
BCRM_TOKEN |
The bcrm_pat_… token you created in Step 1. |
Step 3 — Restart and start asking
Restart your AI client so it picks up the new server. With the hosted endpoint it connects straight to the URL; with the local option it launches bcrm-mcp automatically. Either way it discovers the available tools — just talk to it in plain language and it chooses the right tool for each request.
What the AI can do
The server exposes a small set of generic tools that work across your main CRM records: leads, contacts, accounts, opportunities, tasks, cases, invoices, and solutions.
| Tool | Purpose |
|---|---|
crm_search |
List and search records, with filters. Results are capped per call to stay efficient. |
crm_get |
Fetch the full detail of one record. |
crm_create |
Create a record (validated by the API). |
crm_update |
Update fields on a record. |
crm_delete |
Delete a record — requires explicit confirmation. |
crm_action |
Run non-CRUD actions, e.g. convert a lead, add a comment, send an invoice. Outward-facing actions like sending an invoice require explicit confirmation. |
crm_describe |
Discover an entity's fields and valid values from the live schema. |
list_actions |
List the non-CRUD actions available per entity. |
Security & safety
- Acts as you, never more. The agent inherits your role and org. A sales rep's agent is limited to what the rep can do; it cannot see another team's or another company's data.
- Tenant isolation is enforced server-side. PostgreSQL row-level security scopes every query to your organization.
- Destructive and outward-facing actions need confirmation. The agent must explicitly confirm a delete — and outward-facing actions like sending an invoice (which emails a customer) — so nothing irreversible happens by accident.
- Bounded reads. Searches are limited per call, preventing bulk data dumps.
- Revocable and expirable. Cut off an agent instantly by revoking its token, or set an expiry up front.
- Tokens stay secret. Only a hash is stored — the raw token is shown once and never logged. Keep
BCRM_TOKENout of source control and shared configs.
Troubleshooting
- The agent says it isn't authorized / sees no data. On the hosted endpoint, check the
Authorizationheader readsBearer bcrm_pat_…and the URL ends in/mcp. On the local option, check thatBCRM_TOKENis current (not revoked or expired) and thatBCRM_BASE_URLpoints at the CRM host with no trailing/api. In both cases a missing or malformed token is rejected before any data is touched. - The token was lost. Tokens can't be recovered — create a new one and revoke the old.
- A tool can't find a field. Ask the agent to describe the entity first;
crm_describereads the live field list and valid values.