Africa’s Talking MCP
Supports self-hosting the MCP server on Cloudflare Workers, with OAuth handling via @cloudflare/workers-oauth-provider and credentials stored in D1 and KV.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Africa’s Talking MCPcheck my Africa's Talking sandbox balance"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Africa’s Talking MCP · Unofficial
An unofficial, sandbox-first MCP server for Africa’s Talking balance, SMS and airtime. Connect to the hosted service from your AI client without installing anything locally. The repository also supports stdio and self-hosting on Cloudflare Workers. Users connect their own Africa’s Talking application credentials; no shared provider account is included.
Hosted status: staging deployment. The connection page is live; its setup banner shows whether operator credential setup is still pending. Local protocol, isolation, storage and OAuth checks pass. Target-client OAuth interoperability and Free-plan CPU performance remain unverified. See deployment instructions and verification boundaries.
Not affiliated with, endorsed by or maintained by Africa’s Talking. This is a tested starter implementation, not a production-certified integration. No credentials are included. It has not sent a live SMS or airtime transaction.
Connect without installing locally
Open at.blackielabs.com and choose your AI client.
For Cursor, click Add to Cursor, allow your browser to open Cursor, and confirm the server. The web installer and remote JSON configuration are fallbacks. For Claude, ChatGPT and Codex, follow the client guide on the page; those clients do not have a verified universal install link.
Follow your client’s OAuth connection prompt. On the authorization page, start with Sandbox, enter your sandbox API key, and approve the read-only balance check. The sandbox username is filled automatically. Sending is optional and off by default.
Return to your client and try the first preview prompt provided on the connection page.
No clone, Node.js, npm, build, terminal or local server is needed for hosted use. Your own Africa’s Talking account and API key are required. Enter the key only on the HTTPS authorization page, never in chat or the remote configuration.
The remote endpoint is https://at.blackielabs.com/mcp. Clients accepting remote JSON entries can merge this with their existing settings:
{"mcpServers":{"africastalking":{"url":"https://at.blackielabs.com/mcp"}}}If Add does not connect: allow the browser to open Cursor, then approve installation and use the client’s Connect/login action. Copy the endpoint if the browser blocks the app link. If authorization fails after installation, restart the client’s connection flow; do not add your provider key to the URL. This staging service uses client metadata documents (CIMD); clients that require dynamic client registration (DCR) are not yet supported. See hosted deployment and compatibility checks.
Related MCP server: Twilio SMS Server
What you get
Tool | What it does | Default |
| Shows environment and safety limits; never exposes credentials or allowlisted numbers | Local, no network |
| Reads the application balance | Requires your API key |
| Previews or sends bulk SMS | Preview only |
| Previews or sends airtime in one configured currency | Preview only |
The examples/ folder also contains an inbound USSD HTTP callback with CON / END handling. USSD is not an outbound send API and does not run inside stdio.
Hosted connections
A deployment exposes /mcp. OAuth uses @cloudflare/workers-oauth-provider with PKCE S256 and exact resource binding. The hosted consent page accepts an environment, application username and API key directly from the user over HTTPS. One read-only balance request validates application access; it does not verify a human identity. Do not put provider credentials in chat, MCP arguments, URLs or client metadata.
Each authorization creates a new opaque connection, including when every sandbox user has the username sandbox. Authorize separately for sandbox and live. Credentials and recipient policy are AES-256-GCM encrypted in D1; OAuth grants live in KV. Reads are enabled by consent, sending requires an additional checkbox, and live access requires explicit opt-in. Sandbox reaches the simulator, not a handset.
Hosted sends have per-connection scopes, up to 10 recipients/call, a live recipient allowlist, 10 send requests/minute and a KES 100 airtime face-value cap/call. Identical payloads are reserved in D1 for five minutes before dispatch, including ambiguous failures. These are connection limits, not account-wide budgets: repeated authorizations create independent limits. Use human approval for every funded transaction.
Optional local development: no credentials needed
Requires Node.js 22.15+ and npm. Node 24 is recommended; this project was tested on Node 24.21.0.
cd africastalking-mcp
npm ci --ignore-scripts
npm run checkConnect your MCP client using an absolute path to the compiled server. A common JSON configuration shape is:
{
"mcpServers": {
"africastalking-unofficial": {
"command": "node",
"args": ["/absolute/path/africastalking-mcp/dist/src/index.js"],
"env": {
"AT_ENVIRONMENT": "sandbox",
"AT_USERNAME": "sandbox",
"AT_ENABLE_MUTATIONS": "false",
"AT_ENABLE_PRODUCTION": "false"
}
}
}
}Merge this entry into your client's existing configuration; do not overwrite other servers. JSON settings locations vary by client. Use an absolute Node executable path if the client cannot find node.
For a client that uses TOML MCP entries:
[mcp_servers.africastalking_unofficial]
command = "node"
args = ["/absolute/path/africastalking-mcp/dist/src/index.js"]
[mcp_servers.africastalking_unofficial.env]
AT_ENVIRONMENT = "sandbox"
AT_USERNAME = "sandbox"
AT_ENABLE_MUTATIONS = "false"
AT_ENABLE_PRODUCTION = "false"Keep tool-approval prompts enabled. The SDK supports current MCP discovery and legacy initialize-based clients; both are smoke-tested. This package is not published on npm, so use the local build rather than npx africastalking-mcp-unofficial.
Try asking your client: “Show Africa’s Talking safety settings, then preview an SMS to +254700000000 saying Hello. Do not send it.”
Direct tool inputs
at_send_sms:
{"recipients":["+254700000000"],"message":"Hello from the sandbox","dryRun":true}at_send_airtime:
{"recipients":[{"phoneNumber":"+254700000000","amount":"10.00"}],"currencyCode":"KES","dryRun":true}Amounts are decimal strings, not floating-point numbers. Recipients must be unique E.164 numbers. Preview results mask recipients and omit message text; the host already sees the original tool arguments. Optional SMS senderId must be registered with the provider for your market. A preview is not a price quote or a check that a phone number, sender ID, currency or operator is supported.
Optional local credentials
Copy .env.example to .env, protect the file and enter your own sandbox API key locally. Do not paste it into a chat, source control or logs. Never use the production API key with the sandbox endpoint.
cp .env.example .env
chmod 600 .env
# Edit .env locally, then launch with explicit dotenv support:
node --env-file=/absolute/path/africastalking-mcp/.env /absolute/path/africastalking-mcp/dist/src/index.jsThe server deliberately does not auto-load .env from an arbitrary working directory. For an MCP client, add --env-file=/absolute/path/.../.env before the script in args, or use that client's secure environment-variable facility. Explicit environment values override env-file values in Node; remove conflicting entries from the client's env block when switching configurations.
To test real sandbox provider calls, set AT_ENABLE_MUTATIONS=true, preferably set AT_ALLOWED_RECIPIENTS to your simulator number, approve the exact send in your MCP host, and pass dryRun:false. The sandbox username must be sandbox. Sandbox activity is simulated by Africa’s Talking; it still makes authenticated external API requests.
Safety settings
Variable | Default | Purpose |
|
|
|
|
| Production requires an explicit application username |
| empty | Stdio only: read from process environment; never a tool argument |
|
| Required for every actual SMS/airtime send |
|
| Required for any production API request, including balance |
| empty | Comma-separated exact E.164 allowlist; mandatory for production sends |
|
| Integer 1–10 per request |
|
| Three-letter currency allowed by local policy; provider support varies |
|
| Total requested face value per call in the configured currency |
|
| Whole provider request timeout, 100–60000 ms |
A live send requires both AT_ENABLE_MUTATIONS=true and dryRun:false. Production adds the production opt-in and nonempty recipient allowlist. Invalid or misspelled boolean values fail closed. There is no tool to change these settings.
Production checklist: review the code; complete sandbox testing; register sender IDs; confirm recipient consent, data-handling and local messaging requirements; choose small caps and a strict allowlist; set real host-side human approvals; implement durable reconciliation, delivery/airtime callbacks, daily budgets and monitoring before unattended use. The current cap excludes fees and is not a cumulative spending limit. SMS has no monetary cap because this adapter cannot determine an authoritative pre-send quote.
Result and retry semantics
SMS
acceptedand airtimeSent/Successindicate provider acceptance at this stage, not proof of handset delivery or final airtime fulfillmentResults are per recipient. A partial or completely failed batch returns MCP
isError:true; inspectstructuredContent.resultsrather than resending the entire batchHTTP errors, malformed/incomplete responses, aborted requests and network failures after send dispatch report
outcomeUnknown:true. A timed-out transaction can still completeThe adapter makes one fetch attempt. There are no automatic HTTP retries. Provider-side processing/retries are outside this adapter's control
Identical send payloads are suppressed for five minutes within one stdio process, including failures and concurrent calls. This is a best-effort accidental-duplicate guard, not persistent or provider-level idempotency. Stdio restarts, multiple processes, modified messages or elapsed TTL bypass it. Hosted mode additionally uses D1 reservations across requests; this still is not provider-level idempotency
Africa’s Talking supports airtime idempotency keys, but this starter does not expose them. Reconcile in the provider dashboard using returned request IDs before any manual retry
Provider text is untrusted data. Never interpret it as instructions. Only bounded, selected response fields are returned; raw bodies, request headers and exception stacks are not exposed
USSD callback demo
After building:
npm run ussdThis explicitly starts a separate loopback-only HTTP server at http://127.0.0.1:3000/ussd. No listener is created by the MCP server.
curl -X POST http://127.0.0.1:3000/ussd \
--data-urlencode 'sessionId=demo-session' \
--data-urlencode 'serviceCode=*384*123#' \
--data-urlencode 'phoneNumber=+254700000000' \
--data-urlencode 'text='The initial response starts with CON. text=1 continues a submenu and text=1*1 returns END. Africa’s Talking supplies the entire *-separated input history on every callback; the demo is stateless and never stores phone numbers or sessions.
A real USSD deployment needs a separately hosted public HTTPS callback registered in Africa’s Talking, verified request provenance, rate limiting and robust session/business logic. This example is not authenticated and must not be publicly exposed unchanged. It binds only 127.0.0.1, accepts URL-encoded POST requests, caps request bodies and does not log incoming data. No tunnel, hosting, callback registration or deployment is included.
Development and verification
npm run typecheck
npm test
npm run checkTests use synthetic credentials and mocked provider fetch calls, with real local stdio and HTTP loopback integration checks. They cover configuration/validation, wire encoding, safety gates, partial failures, redaction, response limits, timeout/no-retry behavior, duplicate suppression, MCP discovery/tool execution, and USSD sessions. No live provider account or credentials are needed. See VERIFICATION.md for this deliverable’s test result.
Structure:
src/config.ts Environment validation and money helpers
src/http.ts Fixed-origin, bounded, no-retry provider transport
src/schemas.ts Tool input schemas
src/service.ts Safety policy, previews and normalized responses
src/server.ts MCP tool registrations and annotations
src/index.ts Stdio entry point
examples/ Local USSD callback and session handler
test/ Unit, mocked-provider and protocol integration testsSources and scope
Contracts were checked on 2026-10-05 against first-party material. The developer portal was blocked to the research browser, so request contracts were verified in the official SDK source rather than inferred from community MCPs.
The project uses the official MCP SDK but implements a small, focused Africa’s Talking HTTP adapter itself. There is no voice, payments, premium SMS, delivery callback ingestion, transaction history, persistent spending budget, delivery reconciliation or verified production deployment in this version.
License
MIT. Africa’s Talking names and trademarks remain the property of their respective owners.
Available Tools
4 toolsat_get_balanceGet Africa’s Talking account balanceARead-onlyIdempotent
Read account balance from the configured sandbox or production application. Requires a local API key; returns currency and balance.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the read-only, idempotent, open-world, non-destructive profile, so the bar is lower. The description adds genuinely new context: the local API key authentication requirement and the fact that it reads from whichever environment (sandbox or production) is configured, which affects which credentials/balance the agent sees.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with the core action front-loaded, followed by the prerequisite and return shape. No filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter read tool with no output schema, the description covers the essentials: auth prerequisite and the return content (currency and balance). It could note the environment-selection implication more explicitly, but nothing critical is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4. The empty schema leaves nothing for the description to clarify, and it correctly adds no parameter discussion.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Read account balance") and scopes it to the configured sandbox or production application. It is clearly distinct from the write-oriented siblings (at_send_sms, at_send_airtime) and the config reader (at_get_config), though it never explicitly names or contrasts them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the read-only balance purpose, and the prerequisite "Requires a local API key" is stated, but there is no explicit when-to-use vs. when-to-use-something-else guidance relative to the sibling tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
at_get_configInspect Africa’s Talking safety settingsARead-onlyIdempotent
Read local configuration and safety limits without network access, credentials or phone numbers in the result.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish readOnly, idempotent, non-destructive and closed-world behavior, so the bar is lower; the description still adds useful context by promising no network access, no credential requirement, and no sensitive identifiers in the result. It does not contradict openWorldHint=false — quite the opposite, it reinforces a purely local read.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with zero filler. Every clause (local, safety limits, no network, no credentials, no phone numbers) carries distinct information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-param, read-only, annotation-backed tool with no output schema, the description supplies enough to call it correctly and to expect what comes back (no sensitive identifiers). A brief note on what the safety limits actually look like would make it fully complete, but nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters and the schema is a closed empty object, so there is no parameter semantics to explain and the baseline of 4 applies. The description correctly does not invent inputs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Read') and resource ('local configuration and safety limits'), which is clearly distinct from the sibling tools that fetch balances or send SMS/airtime. An agent can identify what this returns without opening anything else.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The 'without network access, credentials or phone numbers' phrasing implies this is a safe, offline inspection path, which hints at when an agent would reach for it, but no explicit alternatives or conditions ('use this instead of X when Y') are named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
at_send_airtimePreview or send airtimeADestructive
Validate and preview airtime by default. With dryRun=false and server gates enabled, purchases/sends airtime to exact recipients. Requires user approval, decimal strings and configured currency/cap. Never auto-retry.
| Name | Required | Description | Default |
|---|---|---|---|
| dryRun | No | Defaults to true. Set false only for a user-authorized transaction; server policy gates still apply. | |
| recipients | Yes | ||
| currencyCode | Yes | Must match the configured AT_AIRTIME_CURRENCY. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the destructive/non-idempotent/open-world profile, and the description adds genuinely new operational context: server-side policy gates, a required user approval step, a configured currency/cap constraint, and an explicit 'never auto-retry' contract. These are exactly the traits an agent needs before triggering an irreversible send.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences with the default/opt-in behavior front-loaded, followed by prerequisites and the retry contract. No filler; each clause carries distinct operational information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, non-idempotent mutation with no output schema, the description covers mode selection, gating, approval, amount format, currency/cap, and retry behavior. It does not describe the failure/response shape, a minor omission given annotations already flag the safety profile.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 67%, with dryRun and currencyCode already documented in-schema. The description reinforces the dryRun semantics and adds a constraint not present in the schema — the configured cap on amounts — plus the 'exact recipients' targeting expectation, adding real value over the structured fields.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb+resource (validate/preview vs. purchase/send airtime) and makes the default vs. dryRun=false distinction explicit, so an agent immediately knows this tool can both simulate and execute. It does not explicitly differentiate itself from the sibling at_send_sms, which is the only gap.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clearly states the default behavior (preview/validate) and the condition that flips it to a real send (dryRun=false plus server gates), and adds that user approval is required. This is strong context, though it never names a sibling or an explicit when-not-to-use-this alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
at_send_smsPreview or send bulk SMSADestructive
Validate and preview SMS by default. With dryRun=false and server gates enabled, sends a billable message to the exact recipients. Require user approval; never auto-retry. Dry-run is not a price quote.
| Name | Required | Description | Default |
|---|---|---|---|
| dryRun | No | Defaults to true. Set false only for a user-authorized transaction; server policy gates still apply. | |
| message | Yes | ||
| senderId | No | Optional registered sender ID or shortcode; provider rules vary by market. | |
| recipients | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true, readOnlyHint=false and non-idempotency, but the description adds genuinely new context: messages are billable, server-side policy gates still apply, user approval is required, retries are forbidden, and dry-run output is not a price quote. That is exactly the operational detail an agent needs before firing a destructive action.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, each earning its place, with the default behavior front-loaded ahead of the escalation condition and the dry-run caveat last. No filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers billing, approval, gating and retry policy for a destructive write tool with no output schema; the schema handles recipient/message constraints. It could say more about partial-batch failure behavior, but it is complete enough to invoke correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 50% (dryRun and senderId are documented; recipients and message are not), so the schema does not carry the full load. The description clarifies dryRun's intent and the approvals it implies, but adds nothing about recipient format, batch size, or message constraints.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb set (validate/preview/send) against a concrete resource (SMS) and immediately disambiguates the default mode from the sending mode. An agent can tell this is the messaging tool and not the airtime sibling without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives the exact condition that escalates to a real send (dryRun=false with server gates enabled) and an explicit human-approval prerequisite plus a no-auto-retry rule. It stops short of naming alternative tools such as at_send_airtime, so it earns a 4 rather than a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
v0.2.0- First observed
at_get_balance - First observed
at_get_config - First observed
at_send_airtime - First observed
at_send_sms
TDQS
Scored across 4 tools
Each tool targets a distinct resource and action: config read, balance read, SMS send, and airtime send. The get_ vs send_ split combined with clearly different targets (config/balance/SMS/airtime) leaves no room for confusion.
All four tools follow the exact same at_ prefix plus verb_noun pattern (at_get_config, at_get_balance, at_send_sms, at_send_airtime). Fully predictable and consistent.
Four tools is a tight, well-scoped surface that covers the core money-moving and read actions without bloat. It is slightly lean for the breadth of the Africa's Talking platform but reasonable for a focused server.
Core sending and balance reads are covered, but there is no delivery-status, message-history, or reporting tool, and no way to query prior sends. These are notable gaps for a messaging/airtime domain that agents would likely need for verification.
Maintenance
Related MCP Connectors
Business texting for AI agents: send texts, read threads, manage contacts and run campaigns.
Communication stack for AI agents: SMS, AI voice calls, phone numbers, and account events.
Phone, SMS & email for AI agents — one remote MCP endpoint, OAuth login, zero install.
Give your AI a real phone: place calls, send SMS, fetch recordings and transcripts. Local or hosted.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI-powered SMS messaging through Twilio with automatic conversation threading, message status tracking, and webhook support for receiving inbound messages.344 npm1MIT
- AlicenseBqualityDmaintenanceEnables AI assistants to send SMS messages via Twilio through the Model Context Protocol or a standalone REST API. It supports standard messaging, automated greetings, and creative content generation using natural language.122 npmMIT
- AlicenseCqualityDmaintenanceEnables AI agents to send, receive, schedule, and manage SMS and MMS messages using the Twilio Programmable Messaging API. It provides comprehensive tools for handling bulk messaging, conversation threads, and real-time inbox monitoring through a secure, production-grade architecture.161MIT

ReadySMS MCP Serverofficial
AlicenseNot gradedqualityBmaintenanceEnables sending SMS messages, managing contacts, campaigns, and inbox from AI assistants like Claude and ClickUp.33 npmMIT