Guides
AI agents (MCP)
Connect Claude, Cursor, or any MCP client to your Sendai account — six tools over hosted HTTP, authenticated with your API key, nothing to install.
Sendai runs a hosted MCP server, so an AI agent can send and track messages from your account: the same API key, the same prepaid balance, the same delivery record and message log as everything else you do. There is nothing to install and nothing to run — you configure a URL and a key, and every message the agent sends shows up in your dashboard exactly as if your own code had sent it.
| Host | Use |
|---|---|
https://mcp.sendai.co.zw | Production |
https://mcp-staging.sendai.co.zw | Staging |
Agents send real messages.
send_smsandsend_bulk_smsdeliver to real handsets and charge your prepaid balance, exactly as if you had called the REST API yourself. Both are marked destructive in the MCP metadata, so well-behaved clients ask before running them — but the enforcement that matters (approved sender, sufficient balance) happens server-side.
How it works
The server speaks MCP over plain HTTP: your client POSTs JSON-RPC to the host and gets the response back in the same request. There is no session and no state — each request carries your API key as a bearer token, the server forwards it to the REST API for the life of that one request, and nothing about you is stored on it.
- The endpoint answers on both the bare host and
/mcp— either URL works. - It accepts
POSTonly; aGETon the endpoint returns405, and any other path is a deliberate404so a mistyped URL fails loudly instead of half-working. - Authentication is a normal API key from Settings → Developer in the dashboard, sent as
Authorization: Bearer …. No OAuth — browser and mobile connector UIs that expect an OAuth flow cannot connect; use a client that reads a config file.
Connect a client
Create an API key in the dashboard under Settings → Developer — ideally one dedicated to the agent (see Security) — then add the server to your client:
claude mcp add --transport http sendai https://mcp.sendai.co.zw \
--header "Authorization: Bearer sk_your_key_here"
The same JSON shape works in any client that reads an mcpServers config file — VS Code
included. The dashboard's Settings → Developer tab shows this exact configuration with a
copy button.
The six tools
The tools are the same operations as the REST reference, so everything an agent does is visible in your dashboard's messages log and reports.
send_smswrite · charges the accountSends one SMS. Real message, real charge. Args:to(recipient MSISDN in international format, e.g.263771000000),message(billed per GSM-7/UCS-2 segment),from(an approved sender ID — an unapproved value is rejected with400). Returns202— accepted, priced and queued, not delivered; pollget_smsto confirm delivery.send_bulk_smswrite · charges the accountSends the same body to many recipients, priced as one send. Real messages, real charges. Args:to(array of MSISDNs),message,from(approved sender ID), optionalwebhook_url(a delivery callback applied to every message in the send). Rejected outright with insufficient balance when the prepaid balance does not cover it — never partially delivered.get_smsread-onlyReads a message back by id. Args:id(from thesend_smsresponse).status: successmeans the carrier accepted or confirmed it —delivered_atnon-null is the confirmed handset delivery. There is no separate delivery-status field.get_balanceread-onlyPrepaid wallet balance, one row per currency. No args. Worth calling before a bulk send — an underfunded send is rejected, not partially delivered.list_sender_idsread-onlySender identities on the account. No args. Rows withusable_as_from: trueare validfromvalues — an SMS identity that is both active and verified; the rest are listed so a rejected sender can be explained rather than guessed at.list_api_keysread-onlyAPI keys on the account —ID,Name,Active,CreatedAt,LastUsedAt. Metadata only, never key material. No args.
One convenience the tools add over raw REST: every charge is decorated with a
charge_display sibling ("0.045 USD"), so an agent reads four cents as four cents rather
than as the API's raw ten-thousandths integer 450.
Deliberately not exposed: creating or revoking API keys. Minting a key returns the secret once, in plaintext — over MCP it would land in the model's context and the client transcript, and it would let an agent create credentials that outlive the session. Listing is safe (only metadata comes back), so only listing is here.
A worked example
A typical first session — you ask the agent to check the balance, then send a verification code and confirm it arrived:
// sample — tool calls an agent makes for:
// "Check my Sendai balance, then text the code 4821 to 263771000000."
→ get_balance
← [{ "currency": "USD", "amount": 184500, "amount_display": "18.45 USD" }]
→ list_sender_ids
← [{ "from": "Sendai SMS", "channel": "sms", "usable_as_from": true }]
→ send_sms { "to": "263771000000", "from": "Sendai SMS",
"message": "Your code is 4821" }
← { "id": "0f9c1b3a-…", "status": "enqueued", "charge": "450",
"charge_display": "0.045 USD", "delivered_at": null } // 202 — queued
→ get_sms { "id": "0f9c1b3a-…" } // a little later
← { "status": "success", "delivered_at": "2026-07-06T09:12:44Z" }
That sequence exercises the whole delivery story, and teaches the agent the same lesson the
Quickstart teaches you: 202 is queued; delivered_at is delivered.
Security
- Give the agent its own key. A key is the only credential the server sees, and it scopes every call to one account — a dedicated key means you can cut the agent off without touching your services. Create and revoke keys under Settings → Developer or with the API tokens endpoints; revocation takes effect on the next request.
- Your key is never stored. Each request's bearer key is forwarded to the REST API for that one request and then gone — the MCP server keeps no key material and no per-tenant state.
- The send tools spend money.
send_smsandsend_bulk_smsare flagged destructive so clients prompt first, but treat any agent holding a key as able to send: fund the account accordingly and watch the messages log. - Agents cannot mint keys. Key creation and revocation are excluded from the tool surface by design (see above).
Troubleshooting
| Symptom | Cause and fix |
|---|---|
401 Missing or malformed Authorization header | The key is absent, not in Authorization: Bearer sk_… form, or revoked. Check the header in your client config, and that the key is still active under Settings → Developer. |
400 unknown or unapproved sender id | The from value is not an approved sender ID on your account. Run list_sender_ids and use a row with usable_as_from: true — see Sender IDs. |
404 No MCP endpoint at that path | The URL has a typo. The server answers on the bare host and /mcp only. |
405 This endpoint accepts POST | The client is probing with GET. Configure it as an HTTP (streamable) MCP server, not SSE. |
| insufficient balance on a bulk send | The prepaid balance does not cover the whole send. Check get_balance, top up in the dashboard, retry — nothing was partially sent. |
Health
GET /health on the MCP host answers unauthenticated and says only that the server is up —
nothing about your account.
Next steps
- The endpoints behind the tools → API overview
- Delivery, confirmed → Retrieve an SMS
- Push instead of poll → Webhooks
- Key hygiene in full → Authentication