MCP server
The chatbox-ai MCP server lets an AI agent work with your Chatbox AI workspace: look up templates and contacts, send WhatsApp messages, manage orders and webhooks. It speaks the Model Context Protocol, so it works with Claude, Cursor, VS Code, Codex and any other MCP client.
Endpoint and auth
| Setting | Value |
|---|---|
| Server name | chatbox-ai |
| Transport | Streamable HTTP |
| Endpoint | https://api.chatboxai.dev/mcp |
| Auth header | Authorization: Bearer cbk_live_... (X-Api-Key is also accepted) |
Authenticate with a normal Chatbox AI API key, created in the dashboard under Settings → API & Webhooks (see Authentication). The key's scopes decide which tools work. A tool whose scope the key lacks answers insufficient_scope, so an agent connected with a read-only key cannot send anything.
Keep the key out of files you commit. Where a client supports it, put the key in an environment variable or a password prompt (shown below) rather than pasting it into a config file. The examples use the placeholder cbk_live_YOUR_KEY.
Client setup
Claude Code
claude mcp add --transport http chatbox-ai https://api.chatboxai.dev/mcp --header "Authorization: Bearer cbk_live_YOUR_KEY"Or read the key from an environment variable so it never lands in your shell history as text:
export CHATBOX_API_KEY="cbk_live_YOUR_KEY"
claude mcp add --transport http chatbox-ai https://api.chatboxai.dev/mcp --header "Authorization: Bearer $CHATBOX_API_KEY"Claude Desktop
Add this to claude_desktop_config.json. It runs the server through the mcp-remote bridge:
{
"mcpServers": {
"chatbox-ai": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://api.chatboxai.dev/mcp",
"--header",
"Authorization:${CHATBOX_AUTH}"
],
"env": {
"CHATBOX_AUTH": "Bearer cbk_live_YOUR_KEY"
}
}
}
}Note there is no space after the colon in Authorization:${CHATBOX_AUTH}: some clients split arguments on spaces. The CHATBOX_AUTH environment value carries the full Bearer cbk_live_... string instead. Restart Claude Desktop after saving.
Codex CLI
In ~/.codex/config.toml, point Codex at the HTTP endpoint and tell it which environment variable holds the key:
[mcp_servers.chatbox-ai]
url = "https://api.chatboxai.dev/mcp"
bearer_token_env_var = "CHATBOX_API_KEY"export CHATBOX_API_KEY=cbk_live_YOUR_KEYAlternatively, use the mcp-remote stdio bridge:
[mcp_servers.chatbox-ai]
command = "npx"
args = ["-y", "mcp-remote", "https://api.chatboxai.dev/mcp", "--header", "Authorization:${CHATBOX_AUTH}"]
env = { CHATBOX_AUTH = "Bearer cbk_live_YOUR_KEY" }Cursor
{
"mcpServers": {
"chatbox-ai": {
"url": "https://api.chatboxai.dev/mcp",
"headers": {
"Authorization": "Bearer cbk_live_YOUR_KEY"
}
}
}
}VS Code
In .vscode/mcp.json, VS Code prompts for the key the first time the server starts and stores it securely, so the file itself is safe to commit:
{
"servers": {
"chatbox-ai": {
"type": "http",
"url": "https://api.chatboxai.dev/mcp",
"headers": {
"Authorization": "Bearer ${input:chatbox-api-key}"
}
}
},
"inputs": [
{
"type": "promptString",
"id": "chatbox-api-key",
"description": "Chatbox AI API key",
"password": true
}
]
}Windsurf and any other MCP client
Any client that supports Streamable HTTP needs just the URL and the header:
Transport: Streamable HTTP
URL: https://api.chatboxai.dev/mcp
Header: Authorization: Bearer cbk_live_YOUR_KEYA client that only runs local (stdio) servers can use the mcp-remote bridge, with CHATBOX_AUTH set to Bearer cbk_live_YOUR_KEY in its environment:
npx -y mcp-remote https://api.chatboxai.dev/mcp --header "Authorization:${CHATBOX_AUTH}"Tools
Each tool maps onto the matching API endpoint and follows the same rules (24-hour window, opt-out, idempotency, pagination).
| Tool | What it does | Scope | Access |
|---|---|---|---|
list_templates | Lists the workspace's templates and their approval status. | templates:read | Read-only |
send_template_message | Sends an approved template. Arguments: to or contactId, template, language?, bodyParameters? (array of strings filling {{1}}, {{2}}, and so on), components? (raw Meta components), reference?, idempotencyKey?. | messages:send | Sends |
send_text_message | Sends a plain text message. Only works within 24 hours of the customer's last message. | messages:send | Sends |
get_message_status | Looks up what happened to a message. | messages:read | Read-only |
list_contacts | Lists contacts. Filters: search, tag, optIn, page, pageSize. | contacts:read | Read-only |
get_contact | Gets one contact by id. | contacts:read | Read-only |
find_contact_by_phone | Exact lookup of a contact by phone number. | contacts:read | Read-only |
upsert_contact | Creates a contact, or updates whoever already has the phone number. | contacts:write | Writes |
update_contact | Updates a contact's name, tags, attributes or opt-in. | contacts:write | Writes |
add_contact_tags | Adds tags without touching the others. | contacts:write | Writes |
remove_contact_tags | Removes tags without touching the others. | contacts:write | Writes |
set_contact_opt_in | Opts a contact in or out (optIn true or false). | contacts:write | Writes |
list_orders | Lists orders. | orders:read | Read-only |
get_order | Gets one order. | orders:read | Read-only |
create_order | Creates an order. Status changes message the customer. | orders:write | Writes |
update_order_status | Moves an order to a new status (and messages the customer). | orders:write | Writes |
list_webhook_events | Lists the webhook event catalogue. | webhooks:manage | Read-only |
list_webhooks | Lists the workspace's webhook subscriptions. | webhooks:manage | Read-only |
list_webhook_deliveries | Lists delivery attempts for a subscription. | webhooks:manage | Read-only |
create_webhook | Creates a webhook subscription. | webhooks:manage | Writes |
update_webhook | Changes a subscription's URL, events or isActive. | webhooks:manage | Writes |
delete_webhook | Removes a webhook subscription. | webhooks:manage | Writes |
Example prompts
- "Send the order_shipped template to +919999900000 with Asha, #1234 and Friday."
- "List contacts tagged vip."
- "Which of my templates are approved, and how many parameters does each one need?"
- "Did the last message to +919999900000 get delivered?"
- "Mark order clx9q7r4v0005 as shipped."
- "Show me the failed webhook deliveries for my WooCommerce subscription."
Safety
messages:sendspends your allowance. Every send counts against the workspace's monthly message allowance, and Meta's charges apply as usual.- Create a key with only the scopes you need. For an agent that answers questions about your contacts and templates, give it
contacts:readandtemplates:readand nothing else. Make a separate key for the agent so you can revoke it on its own. - Your agent should ask before sending. Most MCP clients show each tool call for approval before it runs. Keep approval on for
send_template_messageandsend_text_messagerather than auto-approving them, and read the recipient and template before you accept. - Opted-out contacts cannot be messaged through the MCP server any more than through the API.
Troubleshooting
| Error | What it means | Fix |
|---|---|---|
401 invalid_api_key | The key in the header does not match any key. | Check the header is Authorization: Bearer cbk_live_... with the whole key, and that the key has not been revoked or expired. |
403 insufficient_scope | The key is real but lacks the scope this tool needs. | details.required lists the missing scope. Create a key that includes it (see the tools table). |
422 session_window_closed | send_text_message was used more than 24 hours after the customer last wrote. | Use send_template_message with an approved template instead. See the 24-hour window. |
Every other error has the same shape and codes as the REST API: see the errors table.