MCP server: connect an AI agent to Sozuri
Give ChatGPT, Claude, Cursor or an agent you build your Sozuri project as tools. It can send SMS and WhatsApp, place calls, deliver one-time codes and request M-Pesa payments, within the permissions you tick and your spending limits. You add one URL and approve the connection. There is no integration code to write.
- What it is
- Before you start
- Connect your assistant: ChatGPT, Claude, Claude Code, Cursor, VS Code, OpenAI API, Anthropic API, others
- MCP keys
- Permissions
- Tools
- What to ask
- Safety and limits
- Billing
- What your assistant sees
- Troubleshooting
- Versions
What it is
MCP (Model Context Protocol) is the open standard AI assistants use to find and call tools.
Sozuri runs an MCP server at https://mcp.sozuri.net/v1. Any assistant that speaks MCP over HTTP can connect to
it and use your Sozuri project, without anyone writing integration code.
- One address for everyone. Every customer uses the same URL. The connection you approve decides which project the agent works on.
- Each tool is one Sozuri API call. It has the same validation, prices, sender ID rules and Do-Not-Disturb list as the API. An agent can do nothing your own code could not do with the API.
- The agent never holds your API key. It signs in with OAuth or uses an MCP key made for it alone. The MCP server refuses project API keys.
- You choose what it may do. Each connection has its own permissions, and you can revoke it at any time.
- Transport: Streamable HTTP. Sign-in: OAuth 2.1 with PKCE, or an MCP key sent as
Authorization: Bearer. Times are East Africa Time.
Before you start
- Who can connect: the project owner or a project admin. A manager or member cannot.
- A project set up for what the agent will do. The agent uses what the project already has:
| To let the agent | The project needs |
|---|---|
| Send SMS | A balance, and a sender ID registered on the project. The agent must name it exactly as registered. See Send SMS. |
| Send WhatsApp | A WhatsApp number connected by QR code, an official WhatsApp number, or both. See Choose a channel. |
| Place calls | An active voice number on the project. See Voice calls. |
| Send one-time codes | What each channel needs, as on the OTP page. |
| Request M-Pesa payments | Your paybill set up for payment requests. See Payments. |
| Premium SMS | A live premium offer on the project. See Premium: Subscription. |
Connect your assistant
ChatGPT and Claude sign in with OAuth. You approve the connection on a Sozuri page and never paste a key. Tools that take a header (Claude Code, Cursor, VS Code, the OpenAI and Anthropic APIs) can use OAuth where they support it, or an MCP key.
What the Sozuri approval page asks. When an assistant connects with OAuth, Sozuri opens a page where you:
- Log in to Sozuri, with your one-time code if your account has one.
- Check the app's name and the address you will be returned to. ChatGPT and Claude show as Verified.
- Choose the project the agent works for. Only projects you own or administer are listed.
- Tick what it may do. The app's request is ticked to start, and you can change it.
- Choose how long the connection lasts, then Approve.
ChatGPT
- In ChatGPT on the web, add a custom MCP server. ChatGPT calls these plugins (earlier, apps or connectors): open the plugins page and choose Create as a plugin. If your ChatGPT still shows Settings → Apps & Connectors, turn on Developer mode under Advanced settings and choose Create. Your plan and workspace decide whether custom servers are allowed.
- Name it Sozuri, set the MCP server URL to
https://mcp.sozuri.net/v1and authentication to OAuth, then confirm. If the form offers an icon, you can use this one. - ChatGPT opens the Sozuri approval page. Approve, and you are returned to ChatGPT.
- In a chat, turn Sozuri on from the tools menu and ask.
ChatGPT asks you to confirm every tool that sends, changes or deletes something. Read the details before you confirm. A server you add yourself shows no website or category in ChatGPT: those appear only for apps listed in ChatGPT's directory.
Claude (claude.ai and Claude Desktop)
- Open Settings → Connectors and choose Add custom connector.
- Name it Sozuri and give the URL
https://mcp.sozuri.net/v1. Leave the advanced OAuth fields empty: Claude registers itself. - Choose Connect, approve on the Sozuri page, and you are returned to Claude.
- In a chat, check that Sozuri is on in the tools menu, then ask.
On a team or enterprise plan, an owner may have to add the connector for the organisation first.
Claude Code
With OAuth, add the server and then run /mcp in Claude Code to sign in:
claude mcp add --transport http sozuri https://mcp.sozuri.net/v1
Or with an MCP key:
claude mcp add --transport http sozuri https://mcp.sozuri.net/v1 \
--header "Authorization: Bearer $SOZURI_MCP_KEY"
Cursor
In ~/.cursor/mcp.json (every project) or .cursor/mcp.json (one project):
{
"mcpServers": {
"sozuri": {
"url": "https://mcp.sozuri.net/v1",
"headers": { "Authorization": "Bearer smcp_k_..." }
}
}
}
VS Code
In .vscode/mcp.json. VS Code asks for the key the first time and stores it for you:
{
"inputs": [
{ "type": "promptString", "id": "sozuri-key", "description": "Sozuri MCP key", "password": true }
],
"servers": {
"sozuri": {
"type": "http",
"url": "https://mcp.sozuri.net/v1",
"headers": { "Authorization": "Bearer ${input:sozuri-key}" }
}
}
}
OpenAI API (Responses API and Agents SDK)
Pass an MCP key as authorization. OpenAI does not store it, so send it with every request. Keep
require_approval on "always" for anything that sends: it makes your code approve each
tool call before it runs.
import os
from openai import OpenAI
client = OpenAI()
response = client.responses.create(
model="gpt-5",
tools=[{
"type": "mcp",
"server_label": "sozuri",
"server_url": "https://mcp.sozuri.net/v1",
"authorization": os.environ["SOZURI_MCP_KEY"],
"require_approval": "always",
}],
input="Text the on-call engineer from ALERTS: the nightly backup finished.",
)
Anthropic API (MCP connector)
Pass an MCP key as the server's authorization_token, and name the server in an mcp_toolset:
import os
import anthropic
client = anthropic.Anthropic()
response = client.beta.messages.create(
model="claude-opus-5-5",
max_tokens=16000,
betas=["mcp-client-2025-11-20"],
mcp_servers=[{
"type": "url",
"url": "https://mcp.sozuri.net/v1",
"name": "sozuri",
"authorization_token": os.environ["SOZURI_MCP_KEY"],
}],
tools=[{"type": "mcp_toolset", "mcp_server_name": "sozuri"}],
messages=[{"role": "user", "content": "Which WhatsApp numbers does my project have connected?"}],
)
An agent you build has no confirmation step unless you add one. Start it with read permissions only, or check each tool call in your code before it runs.
Other assistants
- Grok: add a custom connector with the URL
https://mcp.sozuri.net/v1, then approve on the Sozuri page. - Meta AI (Muse): ask it to set up a custom connector for
https://mcp.sozuri.net/v1. When it asks for a credential, give it an MCP key asAuthorization: Bearer smcp_k_.... - Any other MCP client that supports Streamable HTTP works, with OAuth (Sozuri supports dynamic client registration and client metadata documents) or an MCP key in the
Authorizationheader. - To try the tools yourself, run
npx @modelcontextprotocol/inspectorand connect it to the URL.
MCP keys
For an assistant that sends a header instead of signing in with OAuth.
- In the dashboard, open your project, then Manage API → AI agent (MCP) connections.
- Choose Create an MCP key. Give it a name you will recognise (for example Cursor, Amina's laptop), tick its permissions and choose how long it lasts. The default is 90 days.
- Copy the key, which starts with
smcp_k_. It is shown once. The page also shows it ready to paste for Claude Code, Cursor, VS Code and the OpenAI API.
- The key is the only credential the agent needs. It belongs to one project, so the agent never sends a project name.
- It is not your project's API key, and the MCP server never accepts that key. Your API key keeps working for your own systems, untouched.
- Make one key per agent, or per person. Then revoking one leaves the others working, and your project's activity shows which one acted.
- Keep it secret. Store it in an environment variable or a secrets manager, never in a repository.
Every connection is listed on the same page, OAuth and key alike: who made it, its permissions, when it was last used and when it expires. Revoke one, or Revoke all. A revoked connection stops within a minute. It also stops on its own when it expires, when the person who made it is no longer an admin of the project, or when the project is archived.
Permissions
Each connection has its own permissions, chosen when it is made. Sozuri checks them on every request, on its own servers, so an agent cannot use a tool you left unticked. To change a connection's permissions, connect it again with the new ones and revoke the old one.
| Permission | What it allows | Ticked to start |
|---|---|---|
| account:read | See this project. Channels, templates, numbers, call history (with call transcripts and recordings) and the status of codes. Always on. | Always on |
| contacts:read | Read contacts. List and look up contacts and groups. | Yes |
| contacts:write | Change contacts. Add, update and delete contacts. An update replaces every field. | Yes |
| sms:send | Send SMS. Send and schedule SMS from your sender IDs. | Yes |
| whatsapp:send | Send WhatsApp. Messages and reactions on your QR-code and official numbers. | Yes |
| whatsapp:templates | Manage WhatsApp templates. Submit, edit and delete templates. Each one is a Meta review. | Yes |
| voice:call | Place and end calls. Calls from your voice numbers that read a message aloud, and hanging up a call in progress. | Yes |
| otp:send | Send one-time codes. Deliver codes on WhatsApp, SMS and voice. Use codes your own system made. | Yes |
| premium:send | Premium SMS. Subscribe, unsubscribe and message premium SMS customers. Each message charges the subscriber. | Yes |
| payments:request | Request M-Pesa payments. Send payment prompts to people's phones, for money paid into your paybill. Tick it only on purpose. | No: tick it on purpose |
Tools
Version 1 has 34 tools. An assistant sees only the tools its connection's permissions allow. Reads cost nothing. Writes send, change or delete something; most assistants ask you before each one. The assistant reads each tool's full description, its inputs and what it costs. This list is for you.
Account and status
| Tool | What it does | Permission | Inputs (required in bold) |
|---|---|---|---|
| account_get Read |
Which project this connection works for, what it may do, and when it expires. A good first call. | account:read |
None |
| platform_status Read |
Whether Sozuri and each mobile network are working normally right now. | account:read |
None |
SMS
| Tool | What it does | Permission | Inputs (required in bold) |
|---|---|---|---|
| sms_send Write |
Send or schedule one SMS to up to 1,000 numbers from a sender ID registered on the project. Says which recipients were accepted and which were refused, and why. | sms:send |
from to message type sendAt campaign idempotencyKey |
| Tool | What it does | Permission | Inputs (required in bold) |
|---|---|---|---|
| whatsapp_delete_template Write, permanent |
Delete one language of a template, permanently. | whatsapp:templates |
id |
| whatsapp_edit_template Write, permanent |
Change a template's content. Meta reviews it again. | whatsapp:templates |
id body header footer buttons category security_recommendation code_expiration_minutes otp_button_text message_send_ttl_seconds |
| whatsapp_list_channels Read |
Your WhatsApp numbers (QR code and official), whether each is connected, and whether a person's 24-hour window is open. | account:read |
to |
| whatsapp_list_templates Read |
Your official WhatsApp templates, their review status, and their placeholders. | account:read |
status |
| whatsapp_react Write |
React to a message in a chat with an emoji, or remove the reaction. | whatsapp:send |
to messageId emoji channel from idempotencyKey |
| whatsapp_send_contact Write |
A contact card: a name and a phone number. | whatsapp:send |
to fullName phone organization channel from idempotencyKey |
| whatsapp_send_interactive Write |
Reply buttons, a list, or a link button, on your official number, within 24 hours of the person's last message. | whatsapp:send |
to interactive from idempotencyKey |
| whatsapp_send_location Write |
A map pin, with an optional name and address. | whatsapp:send |
to latitude longitude name address channel from idempotencyKey |
| whatsapp_send_media Write |
An image, video, audio file, document or sticker from a public https link. | whatsapp:send |
to type link caption filename voice replyTo channel from idempotencyKey |
| whatsapp_send_template Write |
An approved template on your official number, with its values filled in: the way to message someone who has not written in the last 24 hours. | whatsapp:send |
to name language params from idempotencyKey |
| whatsapp_send_text Write |
A text message, optionally quoting an earlier one. On the official channel, only within 24 hours of the person's last message. | whatsapp:send |
to text replyTo channel from idempotencyKey |
| whatsapp_submit_template Write |
Create a template and send it to Meta for review. It can be sent once Meta approves it. | whatsapp:templates |
name language category body header footer buttons waba_id security_recommendation code_expiration_minutes otp_button_text message_send_ttl_seconds |
Voice calls
| Tool | What it does | Permission | Inputs (required in bold) |
|---|---|---|---|
| voice_end_call Write, permanent |
Hang up a call that is still going. | voice:call |
callSid |
| voice_get_call Read |
One call with its timeline, duration and price. | account:read |
callSid |
| voice_get_recording Read |
A link that plays a call's recording, with no login, for about 30 minutes. | account:read |
callSid |
| voice_get_transcript Read |
What was said on a call, as text. Only for a project that records and transcribes its calls. | account:read |
callSid |
| voice_list_calls Read |
Your calls, newest first: who, when, status, duration and price. | account:read |
limit status tag |
| voice_list_numbers Read |
Your voice numbers, their status, and what an incoming call does. | account:read |
None |
| voice_place_call Write |
Ring up to 100 phones from your voice number, and read a message aloud or put the person through to another number. | voice:call |
to message connect voice from tag requestId |
| voice_send_otp Write |
Phone a number and read a one-time code aloud, digit by digit. | otp:send |
to code brand repeat voice from |
One-time codes
| Tool | What it does | Permission | Inputs (required in bold) |
|---|---|---|---|
| otp_get Read |
Whether a code was delivered, on which channel, and why it moved on. The code itself is never shown. | account:read |
id |
| otp_send Write |
Deliver a code your own system made, on WhatsApp, then SMS, then a voice call, each only if the one before did not arrive. | otp:send |
to code channels fallback_after template from sms voice callback_url |
Premium SMS
| Tool | What it does | Permission | Inputs (required in bold) |
|---|---|---|---|
| premium_send Write |
Send a premium SMS for one of your offers. The person who receives it pays for it from their airtime. | premium:send |
number keyword message linkId |
| premium_subscribe Write |
Ask the network to subscribe a number to one of your premium offers. The person confirms on their phone. | premium:send |
number keyword |
| premium_unsubscribe Write, permanent |
Cancel a number's subscription to one of your premium offers. | premium:send |
number keyword |
Contacts
| Tool | What it does | Permission | Inputs (required in bold) |
|---|---|---|---|
| contacts_create Write |
Add up to 1,000 contacts, into a group. | contacts:write |
contacts group |
| contacts_delete Write, permanent |
Delete a contact, permanently. | contacts:write |
id |
| contacts_get Read |
One contact, by its id or its exact mobile number. | contacts:read |
id |
| contacts_list Read |
Your contacts, 100 a page, optionally from one group. | contacts:read |
group page |
| contacts_update Write, permanent |
Replace a contact's details. Every field left out is cleared. | contacts:write |
id contact group |
M-Pesa payments
| Tool | What it does | Permission | Inputs (required in bold) |
|---|---|---|---|
| payments_request_mpesa Write |
Send an M-Pesa prompt to a person's phone, for money paid into your own paybill. | payments:request |
phone amount account_reference |
What to ask
Ask in plain words. The assistant picks the tools, tells you what it is about to do, and goes ahead when you confirm. For example:
- "Is everything on Sozuri working right now?"
- "Text everyone in the Nairobi stockists group from DUKA: new prices start Monday at 9am. Tell me the cost first."
- "Schedule an SMS from SHULE to the Form 2 parents group for 7am on Friday: school closes at noon."
- "Send Amina the order_ready template on WhatsApp, then send her the shop's location."
- "Draft a WhatsApp template in English and Swahili for appointment reminders, show me, then submit it."
- "Call the three on-call engineers and read out: the payment server is down."
- "What was said on my last three calls? Summarise each in a line."
- "Add these 40 people from the sign-up sheet to a group called March open day."
- "Send Otieno an M-Pesa prompt for KES 1,200 for invoice 1043."
If you are unsure what a connection may do, ask: "What can you do on Sozuri?" The assistant calls
account_get and tells you the project, the permissions and the expiry.
Safety and limits
- You confirm each send. Every tool that sends, changes or deletes is marked as a write. ChatGPT asks you to confirm each one, and so do Claude and most other assistants by default. In an agent you build, approve writes in your own code (
require_approval: "always"on the OpenAI API). - Your spending limits apply. The daily limits on spend, SMS, WhatsApp, calls, M-Pesa prompts and premium messages, and the monthly budget, set under Billing → Spending limits, cover the agent like any other sender. A send over a limit is refused before anything goes out, and the agent is told why.
- A brake on runaway loops. A connection may make at most 120 write calls a minute. It is a brake, not a budget: use your spending limits for money.
- No double sends. The MCP server never retries a send. If Sozuri could not confirm one, the agent is told it may have gone through and how to check before trying again. SMS and WhatsApp sends carry a key that makes a repeat within 24 hours a no-op, and a call carries an id that stops a second call going out.
- Everything else still applies: your balance, the sender ID rules, your Do-Not-Disturb lists, the WhatsApp sending limits and your voice call limits.
- Every action is on the record. Each request names the connection and the person who approved it.
- Cut off in a minute. Revoke a connection on the AI agent (MCP) connections page and it stops within a minute.
Billing
The MCP server itself costs nothing. Everything an agent sends is billed exactly as the same request through the API: the same rates, from the same project balance, within the same limits. Reads cost nothing.
What your assistant sees
- What a tool returns goes into the assistant's conversation. That includes phone numbers, message text, contact details and call transcripts, and so it reaches the records of the AI company you chose. Tick only the permissions the job needs.
- One-time codes come from your system. A code an agent sends is in its conversation. Have your own system generate it and hand it over. A code a language model makes up is not random.
- Recording links are short-lived.
voice_get_recordinggives a link that plays the recording with no login for about 30 minutes. Anyone holding it can listen until then, so share it only with people who should hear the call. - Text written by other people is information, not instructions. A contact's details or a call transcript can contain anything. The assistant is told to report such text and never act on instructions in it, and your confirmation of each send is the safeguard behind that.
- How Sozuri itself handles your data is in the privacy policy.
Troubleshooting
| What you see | What to do |
|---|---|
| The approval page lists no projects | Only projects you own or administer are listed, and only those open to AI agents. During early access, ask us to add your project. |
| "AI agent connections are in early access and not open to this project yet" | Your project is not in early access yet. Ask us to add it. |
| "This app is not known to Sozuri" | The assistant's registration did not reach Sozuri. Remove the connector in the assistant, add it again, and tell us if it repeats. Say which assistant it was. |
| The assistant says a tool is not allowed, or does not offer it | The connection lacks that permission. Connect again with it ticked, then revoke the old connection. |
| The assistant asks you to sign in again | The connection expired, was revoked, or was not used for 30 days. Reconnect, and choose a longer lifetime if you need one. |
| A send is refused | The assistant passes on Sozuri's reason word for word, for example a sender ID that is not registered, a spending limit reached, or a person on your Do-Not-Disturb list. It is the same reason the API would give. |
| The assistant says Sozuri did not confirm a send | It may have gone through. Check the SMS, WhatsApp or call log in the dashboard before asking again. |
Versions
/v1 is version 1 of the Sozuri API. New tools are added to v1 without changing the ones you use. A
change that would break a connection waits for a new version, announced in advance, and v1 keeps working
alongside it for a stated period.