MCP server
Give AI assistants and agents WhatsApp, SMS and email through SendKuy, with 17 tools over API v1.
@sendkuy/mcp is a Model Context Protocol server. It lets an AI assistant or agent reach people through your SendKuy account. It can send alerts and summaries, notify customers per order, send and check OTP codes, and run campaigns you prepared in the dashboard.
It runs on your machine through npx, talks to https://app.sendkuy.com/api/v1 with your API key, and lists only the tools that key may use.
Create a key for the agent
Open Developers → Keys and create a key just for the agent. Every key needs account:read, because the server reads the key's scopes when it starts. Then add only what the agent should do:
| The agent should… | Scopes |
|---|---|
| Read messages and webhook deliveries while you debug | account:read, messages:read, webhooks:read |
| Send notifications and alerts | account:read, messages:write, messages:read, groups:read, contacts:read |
| Run OTP | account:read, verifications:write |
| Run campaigns from the dashboard | account:read, campaigns:read, campaigns:write |
A key with read scopes only never lists a tool that sends. When you change a key's scopes, restart the MCP client so the server reads them again.
Install
Cursor reads .cursor/mcp.json in a project, or ~/.cursor/mcp.json for every project. VS Code reads .vscode/mcp.json and asks for the key, so it stays out of the file. Claude Desktop reads claude_desktop_config.json, and Windsurf reads ~/.config/devin/mcp_config.json.
claude mcp add --transport stdio --env SENDKUY_API_KEY=sk_live_YOUR_API_KEY sendkuy -- npx -y @sendkuy/mcpOne click: Install in Cursor · Install in VS Code · Claude Desktop: open sendkuy-mcp.mcpb from the latest release. The Cursor link fills in sk_live_YOUR_API_KEY, so replace it with your key afterwards.
Scenarios
On-call alert
Who builds it: a team running its own monitoring agent. What the agent does: when a health check fails, it messages the on-call group on WhatsApp with the service and the error, once per incident.
When the checkout health check fails, send the on-call group a WhatsApp message with the service name and the error. Use the incident id as dedupe_key.
Tools: sendkuy_list_groups to find the on-call group, then sendkuy_send_message with its grp_ id in to and dedupe_key: "incident-4821". A monitor that fires three times for the same incident still sends one message, as long as the text stays the same: the same key with a different body is refused with idempotency_key_reused.
Scopes: account:read, groups:read, messages:write.
Daily revenue summary
Who builds it: a store owner, or the developer who runs their back office. What the agent does: every evening, it reads the day's sales from the store's database and sends the owner a short summary.
Every day at 21:00, total today's paid orders, compare them with yesterday, and WhatsApp the summary to +6281234567890. Use daily-revenue-YYYY-MM-DD as dedupe_key.
Tools: sendkuy_send_message. Before a long run, sendkuy_get_account shows how much WhatsApp credit is left.
Scopes: account:read, messages:write.
Store operations
Who builds it: a shop with stock and orders in its own system. What the agent does: it watches for low stock and orders that have waited too long, and tells the right person.
Every hour, find products with fewer than 5 units and orders paid more than 2 hours ago that are not packed. Message the warehouse lead about stock and the shop admin about orders.
Tools: sendkuy_find_contacts to look up staff by external_id, then sendkuy_send_message to their con_ ids.
Scopes: account:read, contacts:read, messages:write.
A notification per order
Who builds it: a developer adding customer updates to a store. What the agent does: it collects every order shipped in the last hour and sends each customer their own tracking number.
For every order shipped since the last run, send the customer a WhatsApp message with their name, order number and tracking link. Email customers who have no phone number.
Tools: one sendkuy_send_batch call with a different body per row, mixing WhatsApp and email. A row without credit fails on its own; the rest still go out. sendkuy_get_messages confirms delivery afterwards.
Scopes: account:read, messages:write, messages:read.
OTP
Who builds it: a developer adding phone verification to sign-up. What the agent does: it sends a code and checks what the user typed.
Send a verification code to +6281234567890 by WhatsApp, falling back to SMS. Then check the code 482913.
Tools: sendkuy_send_verification, then sendkuy_check_verification.
Scopes: account:read, verifications:write.
A promotion to a customer group
Who builds it: a shop that writes its campaign in the SendKuy dashboard and lets an agent decide when it goes out. What the agent does: it finds the campaign and reports its audience. Then it starts the campaign, watches delivery, and pauses if something looks wrong.
Find the draft campaign "Promo Payday", tell me how many contacts it reaches, start it, and pause it if more than 10% of the first 200 fail.
Tools: sendkuy_list_campaigns, sendkuy_start_campaign, sendkuy_get_campaign, sendkuy_control_campaign. For a quick one-off with the same text to everyone, sendkuy_send_message with the group's grp_ id is enough.
Scopes: account:read, campaigns:read, campaigns:write.
Debugging an integration
Who builds it: you, while wiring SendKuy into your app. What the agent does: it answers questions about what happened, without you opening the dashboard.
Which WhatsApp messages failed in the last hour, and why? What is the status of msg_9cBe3A1H…? Why is my webhook failing?
Tools: sendkuy_list_messages, sendkuy_get_messages, sendkuy_list_webhook_deliveries.
Scopes: account:read, messages:read, webhooks:read.
Tools
| Tool | What it does | Scopes |
|---|---|---|
sendkuy_get_account | Plan, credits per channel, usage this period, the key's scopes | account:read |
sendkuy_send_message | One body to 1–100 recipients, contacts or a group, on one channel | messages:write |
sendkuy_send_batch | Up to 500 messages with different content, answered row by row | messages:write |
sendkuy_get_messages | Status of up to 20 messages by id | messages:read |
sendkuy_list_messages | Recent messages by channel, status and time | messages:read |
sendkuy_cancel_message | Cancel a message not sent yet | messages:write |
sendkuy_send_verification | Send an OTP code | verifications:write |
sendkuy_check_verification | Check the code a user typed | verifications:write |
sendkuy_check_whatsapp_numbers | Which numbers are on WhatsApp | numbers:read |
sendkuy_find_contacts | A contact by phone or external_id | contacts:read |
sendkuy_list_templates | Saved message templates | templates:read |
sendkuy_list_groups | Contact groups and their size | groups:read |
sendkuy_list_campaigns | Campaigns prepared in the dashboard | campaigns:read |
sendkuy_start_campaign | Start a campaign | campaigns:write |
sendkuy_get_campaign | Progress and delivery stats | campaigns:read |
sendkuy_control_campaign | Pause, resume or cancel | campaigns:write |
sendkuy_list_webhook_deliveries | Webhooks and their latest delivery attempts | webhooks:read |
Good to know
- Tools that send really send, and spend credit. Give the agent a key with only the scopes it needs.
dedupe_keystops a repeated step from sending twice. Derive it from the event, such asorder-1234-shipped, and keep changing values such as the time out of the message. The same key with different content is refused withidempotency_key_reused. A refusal is remembered under the key as well: after fixing a bad number or topping up, retry with a new key. Keys last about 24 hours. See Idempotency.- A suppressed recipient still gets a message id. Someone who unsubscribed or is on your suppression list is checked when the message goes out, so the message fails later. Read the final status with
sendkuy_get_messages. - Without a key the server still starts. It lists every tool and answers each call with an error until
SENDKUY_API_KEYis set. - Errors carry the API's own code and a link to Errors, so the agent can fix the call itself, for example a phone number without the leading
+. - A send to a large group answers with counts.
sendkuy_send_messagereturns the number of messages per status and the first 20; read the rest withsendkuy_list_messages.