MCP Server
Connect Claude Code and other MCP clients to your BusinessChat business, so an AI agent can read and update your data through the Public API with your API key.
Overview#
BusinessChat runs a remote MCP server (Model Context Protocol) at:
https://api.businesschat.io/mcpAn MCP client, such as Claude Code, connects to it and gets a set of tools. Each tool is one operation of the Public API: listContacts is GET /v1/contacts, createTopic is POST /v1/topics, and so on. When the agent calls a tool, BusinessChat makes that API request with your key, so the agent gets the same data, the same scopes and the same rate limit as any other integration using that key.
POST to /mcp answered with JSON.Authorization: Bearer … on every request. There is no OAuth sign-in, so the client has to let you set that header.Quick start#
You need a Public API key. Create one in the BusinessChat dashboard under Settings → Developer settings → API keys, and give it only the scopes the agent needs. The full key is shown once, at creation.
Claude Code#
Add the server from your terminal, with your key in place of bc_live_<id>_<secret>:
claude mcp add --transport http businesschat https://api.businesschat.io/mcp \
--header "Authorization: Bearer bc_live_<id>_<secret>"By default this is saved for you only, in the current project. Add --scope user to use it in all your projects. Don't use --scope project with the key written into the command: project scope is stored in a file meant to be shared with your repository.
This connects with the default tool groups. To choose groups, add ?groups= to the URL, for example https://api.businesschat.io/mcp?groups=contacts,sessions.
Checking the connection#
Start claude and run /mcp. businesschat should be listed as connected, with its tools. Claude Code names them mcp__businesschat__<tool>, for example mcp__businesschat__listContacts, and those are the names to use in its permission settings.
Then try a first prompt:
Using the businesschat tools, show me which scopes my API key has, then list my 5 most recent open sessions.The first part calls getCapabilities, which every key can call. It's the quickest way to confirm the key works and to see what it can reach.
Other clients#
Any MCP client that supports remote servers over Streamable HTTP and lets you set a request header can connect. Most take a JSON configuration shaped like this one:
{
"mcpServers": {
"businesschat": {
"type": "http",
"url": "https://api.businesschat.io/mcp",
"headers": {
"Authorization": "Bearer bc_live_<id>_<secret>"
}
}
}
}Field names vary between clients. Check yours for where the URL, the transport (HTTP or Streamable HTTP) and custom headers go. A client that can only connect with OAuth sign-in can't use this server.
Authentication#
The MCP server uses the same API keys as the Public API, sent the same way:
Authorization: Bearer bc_live_<id>_<secret>Every request to /mcp is authenticated on its own. A missing or invalid key gets 401 before any MCP handling (see HTTP errors).
A key belongs to one business and always acts as that business. Tools have no business argument: an agent can't pass one, and a tool call that tries is rejected as an unknown argument. Any resource constraints set on the key, such as a limit to certain teams, apply to tool calls exactly as they do to direct API calls.
Scopes#
The key's scopes decide which tools the agent gets:
- Listing tools returns only the tools your key has the scopes for. A key without
topics:writenever seescreateTopic. - Calling a tool checks the scopes again, and the API request it makes is checked again after that. A tool your key can't use is refused with
insufficient_scope.
Grant the narrowest set that does the job. For an agent that should only look things up, grant :read scopes only: no write tools will appear at all.
| Scope | Unlocks tools in |
|---|---|
| none | getCapabilities, available to every key |
contacts:read, contacts:write | contacts and contact-attributes |
products:read | products |
sessions:read, sessions:write | sessions |
teams:read, teams:write | teams (listTeamMembers also needs users:read) |
templates:read | templates |
topics:read, topics:write | topics |
users:read, users:write | users |
work-items:read, work-items:write | work-items and work-items-setup |
Scopes can't be changed after a key is created. To change what an agent can do, create a new key and update the client's configuration.
Keeping the key safe#
Your key grants access to your business's data. Treat it like a password.
- Create a separate key for each agent or person, named after it, so you can revoke one without breaking the others. Revoking takes effect on the next request.
- Keep the key in the client's local or user configuration. Don't commit it to a repository or put it in a shared config file.
- Don't paste the key into a chat with the agent. The client sends it as a header, and the model never needs to see it.
- Review write and destructive tool calls before approving them (see Read-only and destructive tools).
Tool groups#
The client loads every tool's name, description and input schema into the AI model's context. The full catalogue is large, and a long tool list takes up context and makes the right tool harder for the model to pick. Tool groups let you load only the part you need.
Choose groups with the groups query parameter on the server URL, as a comma-separated list:
https://api.businesschat.io/mcp default groups
https://api.businesschat.io/mcp?groups=contacts,sessions just these two
https://api.businesschat.io/mcp?groups=all every group- No
groups: the default set,capabilities,contacts,sessions,templatesandwork-items. groups=all: every group. Useallon its own, not combined with other names.- An unknown name: the request is refused with an error that lists the valid groups.
- Calling a tool outside your groups: refused with an error that names the tool's group, for example Tool 'listProducts' is in the 'products' tool group, which this connection did not select. Add it to the MCP URL, for example ?groups=products.
Groups are not access control. Anyone with the key can connect with ?groups=all. What a key can do is decided only by its scopes. Groups only control how many tools are loaded into the model's context.
Available groups#
Counts are for a key with every scope. Your key sees only the tools its scopes allow. Groups follow the sections of the API reference, and new API operations appear as tools in their group automatically.
| Group | Tools | Covers |
|---|---|---|
capabilities default | 1 | getCapabilities: the scopes, limits and constraints of your key |
contacts default | 28 | Contacts: list, search, get, create, update, batch upsert, block, opt in and out, their sessions, attribute values, tags and tag groups, and imports |
sessions default | 5 | List and search sessions, get a session, assign it, close it |
templates default | 1 | List approved WhatsApp message templates |
work-items default | 17 | Work items themselves: list, get, create, update, assign, transition, promote, reopen, and their tags |
work-items-setup | 46 | Work item configuration: calendars, fields, statuses, tag groups and types |
contact-attributes | 10 | The contact attribute catalogue: define, rename, archive and restore attributes, and manage their options |
products | 2 | List products, get a product from your synced catalogue |
teams | 4 | List teams, get a team, list and add team members |
topics | 10 | List, get, create, update, archive and restore topics; add a topic to a contact or session; list and remove a session's topics |
users | 3 | List users, get a user, update a user's roles |
The default groups hold 52 tools and all holds 127. There is no messages group: see Not available.
Choosing groups#
- Leave
groupsoff for everyday support work: contacts, sessions, templates and work items. - Pick the groups for your task when it's narrower or different, for example
?groups=work-items,work-items-setupto set up a work item type, or?groups=teams,usersto review team membership. - Use
allonly if your client handles many tools well, for example by loading tool definitions on demand.
The groups are part of the server URL, so changing them means changing the URL in your client and reconnecting. In Claude Code, run claude mcp remove businesschat and add it again with the new URL.
How tools work#
Each tool maps one-to-one to a Public API operation and is named after its operation id: listContacts, getSession, transitionWorkItem. The tool's description is the operation's description from the API reference. Parameters, fields and error codes are documented there, under the API tab.
Arguments#
The agent fills in tool arguments from each tool's input schema. They map onto the API request like this:
| Argument | Becomes |
|---|---|
| Path and query parameters | The same parameter, under its API name, for example id, limit, cursor. Values must be a string, number or boolean. |
body | The JSON request body, for operations that take one. |
idempotency_key | The Idempotency-Key header, for write operations that accept one. The same key with the same body replays the original result instead of repeating the write, for 24 hours. |
For example, a call to createTopic looks like this:
{
"idempotency_key": "create-topic-vip-2026-09-14",
"body": { "name": "VIP", "color": "#1d4ed8" }
}An argument the tool doesn't define is rejected, not ignored. The error lists the arguments the tool accepts, so the agent can correct the call. A missing required argument is rejected the same way.
Read-only and destructive tools#
Every tool carries hints that clients can use to decide when to ask you before running it:
- Read-only: every
GEToperation (list and get tools). - Destructive: every
DELETEoperation, and archive actions such asarchiveTopic. - Idempotent:
GET,PUTandDELETEoperations.
Every other tool changes data. How hints are used depends on the client; Claude Code asks for permission before it runs a tool, unless you've allowed it.
Results#
A successful call returns the API response body as JSON text, exactly as the API would return it. Lists use the API's usual envelope, so the agent pages by passing next_cursor back as the cursor argument.
A failed call returns a tool result marked as an error (isError: true) containing HTTP <status> and the API's error body, so the agent can read the error code and react. See Tool errors.
Not available#
Sending WhatsApp messages is not available, over MCP or through the Public API.
The server offers tools only. It has no MCP resources or prompts.
Limits & behaviour#
Rate limits#
Two limits apply, both per minute:
| Limit | Counts | Size |
|---|---|---|
| API limit | Every tool call, as one API request. It is the same per-business limit your other integrations use, so they share it. | Your business's API limit (getCapabilities reports it) |
| MCP message limit | Every request to /mcp: connecting, listing tools and calling tools. Counted per key. | Twice your business's API limit |
The MCP message limit is set higher so that connecting and listing tools never run out before tool calls do. In practice the API limit is the one you'll hit.
- Over the API limit: the tool call returns a tool error such as HTTP 429: rate limit exceeded. Retry after 12 seconds (Retry-After: 12). The agent should wait that long and retry.
- Over the MCP message limit: the
/mcprequest itself gets HTTP429rate_limit_exceededwith aRetry-Afterheader./mcpresponses carryX-RateLimit-Limit,X-RateLimit-RemainingandX-RateLimit-Resetfor this limit.
Timeouts & response size#
- A tool call has 150 seconds in total. A slower one returns the tool error The BusinessChat API did not answer in time. Retry, or narrow the request.
- A tool result can be up to 16 MB. A larger response returns The BusinessChat API response is too large to return. Narrow the request, for example with a smaller limit.
Filters and a smaller limit fix both. List operations clamp limit to their maximum rather than rejecting it.
No sessions#
The server is stateless. Each message is a single POST /mcp answered with one JSON response. There is no session id, no event stream (GET /mcp returns 405) and no notifications from the server, so reconnecting loses nothing. Batched JSON-RPC requests aren't supported: send one message per request.
An Idempotency-Key header on the /mcp request itself is ignored. To make a write safe to retry, use the tool's idempotency_key argument.
Browser clients#
Requests that carry a browser Origin header are refused with 403 Forbidden: Origin not allowed. This protects your key against malicious web pages. Connect from a command-line, desktop or server-side client, which don't send Origin. Your key shouldn't be in a browser anyway.
Errors#
A problem shows up in one of three places, depending on how far the request got.
HTTP errors#
The request was refused before MCP handling. Clients usually report these as a failed connection.
| Status | Body | Meaning |
|---|---|---|
401 | authentication_required | No Authorization header, or it isn't Bearer <key>. |
401 | invalid_api_key | The key is unknown, malformed, revoked or expired. |
429 | rate_limit_exceeded | Over the MCP message limit. Wait for Retry-After. |
403 | JSON-RPC -32600 Forbidden: Origin not allowed | A browser Origin was sent. See Browser clients. |
400 | JSON-RPC -32700 Parse error or -32600 Invalid Request | The body isn't a single JSON-RPC message (including batches). |
415 | JSON-RPC -32600 | The body isn't UTF-8 JSON. |
405 | — | Not a POST, for example a GET from a client expecting an event stream. |
JSON-RPC errors#
The request reached the server, but it refused the tool list or the tool call itself, so no API request was made. These come back with HTTP 200 and a JSON-RPC error:
| Code | Message | What to do |
|---|---|---|
-32602 | Unknown tool: <name> | No such tool. Check the name against the tool list. |
-32602 | Tool '<name>' is in the '<group>' tool group, which this connection did not select… | Add that group to ?groups= and reconnect. |
-32602 | Unknown tool group(s): … Known groups: … | Fix the groups value in the URL. |
-32602 | Invalid params: tools/call requires a non-blank string 'name'… | A malformed call from the client. |
-32003 | insufficient_scope: tool '<name>' requires scope(s) '…' | The key lacks a scope. The error data's required_scopes lists what's needed. Create a key that has it. |
-32601 | Method not found: <method> | The client used an MCP method this server doesn't offer. |
-32603 | Tool catalog temporarily unavailable. Retry shortly. | A temporary problem on our side. Retry. |
-32603 | Internal error | Something went wrong on our side. Retry, and report it if it persists. |
Tool errors#
The tool ran but didn't succeed. The result is a normal tool result with isError: true, and the agent sees the text and can usually correct itself.
| Text | Meaning |
|---|---|
HTTP <status> followed by the API's error body, for example HTTP 404 with the code not_found and the message Contact not found | The API request was made and returned an error. The code is documented in the API reference. |
| HTTP 429: rate limit exceeded. Retry after N seconds… | Over the API limit. Wait and retry. |
| Unknown argument(s): … This tool accepts: … Missing required argument(s): … Argument '…' must be … | The arguments didn't fit the tool. No API request was made. |
| The BusinessChat API did not answer in time… …response is too large to return… | See Timeouts & response size. |
| The BusinessChat API call failed. Retry shortly. The BusinessChat MCP server is still starting. Retry shortly. | Temporary. Retry. |
Reporting a problem#
Every /mcp response carries an X-Request-Id header. Quote it to BusinessChat support, and we can find that request and the API request its tool call made. If your client doesn't show response headers, send the time (with time zone), the tool name and the name of the key you used instead. Never send the key itself.
Troubleshooting#
| Symptom | Where to look |
|---|---|
| The server shows as failed, or the client asks you to sign in | The key isn't reaching the server. Check the header is exactly Authorization: Bearer <key>, with the Bearer prefix and no quotes or spaces inside the key, and that the key hasn't been revoked. The server has no OAuth sign-in, so a client that only offers sign-in can't connect. |
| A tool you expect isn't listed | Either its group isn't selected or your key lacks its scope. Ask the agent to call getCapabilities to see the key's scopes, and check the group table. |
| Almost no tools are listed | The key's scopes don't match the default groups. For example, a key with only products:read sees just getCapabilities until you add ?groups=products. |
Changed ?groups= but the tool list didn't change | The client is still using the old URL. Update it and reconnect: in Claude Code, remove the server and add it again. |
| The agent is slow to choose tools, or picks the wrong one | Too many tools are loaded. Narrow the groups to the task. |
| There's no tool to send a message | Intentional. See Not available. |
403 Origin not allowed | A browser-based client. Use a command-line, desktop or server-side client. See Browser clients. |
| Tool calls return HTTP 429 | Your business's API limit is shared with every integration using its keys. Wait for the stated time, and reduce parallel calls. getCapabilities shows the limit. |
| Tool calls time out or are too large | Ask for less: use filters and a smaller limit, and page with cursor. |
To test the key and URL outside your client, list the tools with curl:
curl -X POST 'https://api.businesschat.io/mcp' \
-H 'Authorization: Bearer bc_live_<id>_<secret>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'A 200 with a tools array means the key and URL work, and the problem is in the client's configuration.