Soprano Connect MCP Server
This MCP server lets AI agents send, broadcast, and track Soprano Connect communications across multiple channels through natural-language tools.
Send single messages on SMS, WhatsApp, RCS, Email, Voice, Viber, and Push (
send_message), including channel-specific rich content like media, templates, buttons/lists, rich cards, and text-to-speech.Send multiple messages in one batch (
send_batch) or broadcast SMS to lists, contacts, and groups (send_broadcast).Check delivery status for a single message (
get_message_status) or multiple SMS messages (get_batch_status).List approved WhatsApp Business templates (
list_whatsapp_templates).Upload or delete WhatsApp media (
upload_whatsapp_media,delete_whatsapp_media).Supply Soprano credentials per request via API key, OAuth2, Basic, Legacy OAuth2, or session cookie for WABA templates.
Enables sending Viber messages through Soprano Connect's send_message tool, with plain-text content and an extra passthrough field for content not covered by typed parameters.
Enables sending WhatsApp messages through Soprano Connect, including media (image/video/document/audio), interactive buttons and lists, pre-approved templates, location, reactions, and reply context. Also supports listing WhatsApp Business (WABA) templates and uploading/deleting WhatsApp media.
Soprano Connect MCP Server
Soprano Connect MCP Server enables you to build AI agents that can communicate, engage customers, and manage communications workflows through Soprano Connect — a global Communications Platform as a Service (CPaaS) — using the Model Context Protocol (MCP).
The Soprano Connect MCP Server enables AI assistants, copilots, autonomous agents, and enterprise applications to securely interact with Soprano Connect's global CPaaS platform. Using natural language, AI agents can send messages, manage customer data, administer accounts, and orchestrate communications across multiple channels in a controlled, enterprise-grade environment.
No complex API integrations. No custom middleware. Simply connect your MCP-compatible AI client and start building intelligent communications workflows — connect any MCP-compatible client (Claude, VS Code Copilot, Cursor, etc.) to the Soprano MCP server and let your agent send messages and check delivery status across multiple channels, all through natural language.
💡 Why Soprano MCP?
Soprano Connect MCP transforms communications capabilities into AI-native tools that can be consumed directly by AI agents. With Soprano MCP, AI agents can:
Send omnichannel communications across all channels supported by Soprano Connect platform
Manage contacts and customer contact lists
Query messaging history and delivery status
Automate customer engagement workflows
Build AI-powered communications use cases without custom integration code
Operate within an enterprise-grade security and governance framework
Related MCP server: Infobip
🛠️ Key Features
Send communications through any channel supported by Soprano Connect such as SMS, RCS, WhatsApp, Viber, Email, Voice, Mobile Push
Rich content per channel — WhatsApp (media, interactive buttons/lists, templates, location, reactions), RCS (rich cards, carousels, suggestions), Voice (text-to-speech, pre-recorded audio, Call Control Objects), Push Notification
Batch and broadcast sending, plus single/batch message status lookups
WhatsApp Business (WABA) template listing, and media upload/delete
Pluggable upstream (Soprano) authentication — API Key, OAuth2 (client credentials), Basic, Legacy OAuth2, and a session-cookie outlier for WABA templates — selected per request, credentials supplied by the caller and never stored server-side
📋 Prerequisites
A Soprano Design Connect API account, provisioned with a license for each channel you want to use
Python 3.12+ and uv — only needed for the stdio transport (running the server locally as a subprocess). Connecting to an already-deployed streamable HTTP server needs no local Python install at all
AI agent or application with MCP client support
Each tool/channel is only available if your Soprano account is subscribed to and provisioned for the corresponding service. Features outside your current subscription must be enabled via Soprano's onboarding or account management process before use.
Table of Contents
🔌 Transports
The Soprano MCP server supports both of the transports defined by the MCP spec — unlike a hosted multi-tenant service, you run it yourself (locally or deployed), so there's a single endpoint/process rather than one per channel.
Streamable HTTP
Supports streamable HTTP transport for remote/deployable use (e.g. behind an ALB, Lambda Function URL, or API Gateway). Point your MCP client at the server's /mcp endpoint, replacing <mems-mcp-server-url> with wherever you've deployed it (or http://127.0.0.1:8000 if running locally).
If the server has Client Authentication (MCP_CLIENT_AUTH_MODE=oauth2.1) enabled with the Layer 2 fallback turned on — the recommended setup for hosted deployments — no X-Soprano-* headers are needed at all:
{
"servers": {
"mems-mcp (http)": {
"type": "http",
"url": "<mems-mcp-server-url>/mcp"
}
}
}Your MCP client will redirect you through an OAuth login/consent page, where you enter your Soprano Connect API ID and API KEY — that's the only credential you need to supply. The server uses it both to authenticate you (Layer 1) and, via the Layer 2 fallback, to authenticate its own calls to Soprano on your behalf, so per-request headers become unnecessary.
Otherwise (MCP_CLIENT_AUTH_MODE=none, or you want to pass different Soprano credentials per request regardless), supply Layer 2 credentials explicitly via X-Soprano-* headers instead:
{
"servers": {
"mems-mcp (http)": {
"type": "http",
"url": "<mems-mcp-server-url>/mcp",
"headers": {
"X-Soprano-Auth-Method": "api_key",
"X-Soprano-Api-Id": "${input:soprano-api-id}",
"X-Soprano-Api-Key": "${input:soprano-api-key}"
}
}
}
}X-Soprano-Domain-Url can usually be left out: if the server's own public hostname follows the mcp- naming convention (e.g. mcp-aus.sopranodesign.com), it derives your Soprano domain automatically by stripping that prefix (https://aus.sopranodesign.com). Set the header explicitly only if your deployment doesn't follow that convention, or to target a different domain than the one implied by the hostname.
The X-Soprano-* headers above are for the api_key method — swap them for any of the other supported auth methods (see Authentication below) by using the matching header set instead:
// oauth2 (client credentials)
"headers": {
"X-Soprano-Auth-Method": "oauth2",
"X-Soprano-Client-Id": "${input:soprano-client-id}",
"X-Soprano-Client-Secret": "${input:soprano-client-secret}"
}// basic
"headers": {
"X-Soprano-Auth-Method": "basic",
"X-Soprano-Username": "${input:soprano-username}",
"X-Soprano-Password": "${input:soprano-password}"
}// legacy_oauth2
"headers": {
"X-Soprano-Auth-Method": "legacy_oauth2",
"X-Soprano-Username": "${input:soprano-username}",
"X-Soprano-Password": "${input:soprano-password}"
}The legacy
ssetransport (append the server's--transport sseflag, endpoint/sse) is also available for MCP clients that don't yet support streamable HTTP.
stdio
For local use (e.g. launched as a subprocess by VS Code, Claude Desktop, etc.), run with --transport stdio. Since stdio has no HTTP headers, Soprano credentials are supplied via SOPRANO_* environment variables instead:
{
"servers": {
"mems-mcp (stdio)": {
"type": "stdio",
"command": "uv",
"args": ["run", "--directory", "${workspaceFolder}", "mems-mcp", "--transport", "stdio"],
"env": {
"SOPRANO_DOMAIN_URL": "https://aus.sopranodesign.com",
"SOPRANO_AUTH_METHOD": "api_key",
"SOPRANO_API_ID": "${input:soprano-api-id}",
"SOPRANO_API_KEY": "${input:soprano-api-key}"
}
}
}
}Same as above, swap the env block for any other auth method:
// oauth2 (client credentials)
"env": {
"SOPRANO_DOMAIN_URL": "https://aus.sopranodesign.com",
"SOPRANO_AUTH_METHOD": "oauth2",
"SOPRANO_CLIENT_ID": "${input:soprano-client-id}",
"SOPRANO_CLIENT_SECRET": "${input:soprano-client-secret}"
}// basic
"env": {
"SOPRANO_DOMAIN_URL": "https://aus.sopranodesign.com",
"SOPRANO_AUTH_METHOD": "basic",
"SOPRANO_USERNAME": "${input:soprano-username}",
"SOPRANO_PASSWORD": "${input:soprano-password}"
}// legacy_oauth2
"env": {
"SOPRANO_DOMAIN_URL": "https://aus.sopranodesign.com",
"SOPRANO_AUTH_METHOD": "legacy_oauth2",
"SOPRANO_USERNAME": "${input:soprano-username}",
"SOPRANO_PASSWORD": "${input:soprano-password}"
}✉️ Messaging Channels
All channels are exposed through one generic send_message tool (channel parameter selects the target) rather than one MCP server per channel — this keeps the tool surface (and token footprint) small while still giving access to every channel-specific rich content type the Connect API supports.
Channel |
| Rich content supported |
SMS |
| Plain text only |
| Media (image/video/document/audio), interactive buttons/lists, pre-approved templates, location, reactions, context (replies) | |
RCS |
| Rich cards, carousels, suggested replies/actions, media |
| Plain text, CC/BCC | |
Voice |
| Text-to-speech, pre-recorded audio file, Call Control Objects |
Viber |
| Plain text (rich content not documented by the Connect API guide — use the |
Mobile Push Notification |
| Title + body |
Anything not covered by a typed parameter can be sent via send_message's extra field, merged verbatim into the outgoing Connect API payload.
🧰 Available Tools
Tool | Description | Maps to |
| Send a single real-time message on any supported channel (SMS, WhatsApp, RCS, Email, Voice, Viber, Push).Example prompt: "Send a WhatsApp message to +33612345678 letting them know their order has shipped." |
|
| Check the delivery status of a single previously-sent message.Example prompt: "What's the delivery status of SMS message 123456?" |
|
| Send multiple messages (optionally across different channels) in one call.Example prompt: "Send this appointment reminder as SMS to these 20 customers." |
|
| Check delivery status for multiple SMS messages at once.Example prompt: "Check the delivery status of these 10 SMS message IDs." |
|
| Send a broadcast SMS order to lists, contacts, and/or groups.Example prompt: "Broadcast a storm warning SMS to everyone in the 'North Region' contact list." |
|
| List approved WhatsApp Business (WABA) message templates.Example prompt: "What WhatsApp templates do we have approved for order confirmations?" |
|
| Upload media (image/video/document/audio) for use in WhatsApp messages.Example prompt: "Upload this product image so I can send it via WhatsApp." |
|
| Delete previously uploaded WhatsApp media.Example prompt: "Delete the WhatsApp media file we just uploaded." |
|
🤖 Agent Permission and Access Control
Every tool is annotated with MCP's standard tool annotations (readOnlyHint, destructiveHint, openWorldHint) so a client can apply governance before invoking it — e.g. send_message/send_batch/send_broadcast/upload_whatsapp_media are non-read-only and reach an open world (real message delivery/spend), and delete_whatsapp_media is additionally flagged destructive. Since sending messages has real-world cost and reputational impact, apply your MCP client/host's permission controls (confirmation prompts, allow-lists, scoped credentials) to these tools rather than granting an agent unrestricted access — see the MCP spec's own implementation considerations for guidance.
🔐 Authentication
Soprano credentials are supplied per request, never stored server-side or cached between calls. How you supply them depends on transport (HTTP headers for streamable-http/sse, environment variables for stdio):
Auth method | stdio env vars | HTTP headers |
API Key |
|
|
OAuth2 (client credentials) |
|
|
Basic |
|
|
Legacy OAuth2 |
|
|
Session cookie ( |
|
|
Both transports also require the target domain — SOPRANO_DOMAIN_URL (stdio) or X-Soprano-Domain-Url (HTTP), e.g. https://aus.sopranodesign.com. For streamable-http/sse, this header can be omitted if the server's own public hostname follows the mcp- naming convention (e.g. mcp-aus.sopranodesign.com) — the domain is then derived automatically by stripping that prefix.
🔒 Client Authentication (optional)
Everything above is Layer 2 (this server → Soprano). Independently, you can also require authentication on incoming MCP requests (Layer 1 — client → this server), off by default:
Env var | Required | Description |
| — |
|
| if | Your Authorization Server's issuer URL(s) — comma-separated if this deployment fronts multiple domains. With the built-in self-hosted AS, this is derived automatically per-request from the caller's own |
| if | Expected token |
| if | This server's own public URL — fallback default when a request's |
| optional | Defaults to |
| optional | Comma-separated required scopes |
Works with any standards-compliant OAuth2/OIDC Authorization Server (Auth0, Okta, Cognito, ...).
Built-in self-hosted Authorization Server
Some MCP clients (confirmed: Zendesk Agent) require a full interactive OAuth 2.0 Authorization
Code + consent flow rather than just bearer-token verification. Rather than standing up a
separate IdP, this server can act as its own Authorization Server, using the caller's Connect
API ID/API KEY as their identity — the routes below are always mounted, and become useful once
MCP_CLIENT_AUTH_MODE=oauth2.1 points MCP_OAUTH_ISSUER_URL at this same deployment:
GET/POST /oauth/authorize— login+consent form, validating the API ID/API KEY against the Connect API domain derived from the request's ownHostheader (if it follows themcp-convention), falling back toMEMS_CONNECT_API_URLotherwisePOST /oauth/token—authorization_code(+ PKCE),client_credentials, andrefresh_tokengrantsPOST /oauth/register— RFC 7591 Dynamic Client Registration; always registers a public (PKCE-secured) client, noclient_secretissuedGET /.well-known/oauth-authorization-server/GET /.well-known/jwks.json— RFC 8414/7517 discovery metadata
Most MCP clients discover required scopes automatically from that metadata. If yours doesn't, check its scopes_supported list at {your-deployment-url}/.well-known/oauth-authorization-server and configure them manually in the client.
Env var | Required | Description |
| Yes | Fallback Connect API domain, used when a request's |
| Recommended | PEM RSA private key used to sign issued JWTs; an ephemeral key is generated (with a warning) if neither is set — fine for a single local process only |
| optional | DynamoDB table names backing client/code/consent/audit/refresh-token storage (default to |
| optional | Lets clients that can't send |
🚀 Installation & Running
git clone https://github.com/soprano-mcp/mcp.git
cd mcp
uv sync
# stdio (local subprocess, e.g. launched by an MCP client config)
uv run mems-mcp --transport stdio
# streamable-http (remote/deployable)
uv run mems-mcp --transport streamable-http
# host/port: MEMS_MCP_HOST (default 127.0.0.1), MEMS_MCP_PORT (default 8000)🛠️ Troubleshooting
Authentication issues
Confirm the
X-Soprano-*headers (orSOPRANO_*env vars) match one of the 5 supported auth methods exactly, including the domain URL.list_whatsapp_templatesis the one outlier requiringsession_cookieauth — every other tool accepts the other 4 methods.
Message delivery issues
Make sure the recipient's destination is valid for the channel (a phone number for SMS/WhatsApp/RCS/Voice/Viber, an email address for Email).
Check
get_message_status(orget_batch_statusfor SMS) — a successfulsend_messageresponse only means Soprano accepted the request (ENROUTE), not that it was delivered.Some channels/accounts require an explicit license/provisioning on the Soprano side (e.g. Viber client connection) — a clean auth/payload but a licensing-style error back from the API means checking with Soprano support.
Other issues
Errors from the Connect API are surfaced via the tool's error text (Soprano's
errorDescriptionfield). For deeper HTTP-level detail, see the Connect API guide's response/error format documentation.
🤝 Contributing
Issues and pull requests are welcome on the repository.
📄 License
Available Tools
8 toolsdelete_whatsapp_mediaBDestructive
Delete previously uploaded WhatsApp media from Facebook.
Maps to DELETE {domain_url}/cgpapi/waba/media/{media_id}.
| Name | Required | Description | Default |
|---|---|---|---|
| media_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and readOnlyHint=false, so irreversibility is covered. The description adds the actual HTTP route, which is useful, but says nothing about whether deletion is permanent, idempotent, or fails silently on an unknown media_id.
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 short lines, action stated first, endpoint second. Nothing is padded, though the raw endpoint line is developer-facing and only partially earns its place for an agent.
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?
The presence of an output schema removes the need to describe return values, and the annotations cover the safety profile. Still missing is the practical context of obtaining the media_id and the permanence of deletion, which matters for a destructive one-arg tool.
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 0% for the single parameter, and the description only indirectly hints at its meaning by embedding '{media_id}' in the endpoint template. It never states the identifier's origin or format, so it adds marginal meaning over the bare schema.
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 ('Delete previously uploaded WhatsApp media') plus the backing endpoint, so the action is unambiguous. It distinguishes itself from the sibling upload_whatsapp_media by implication only; it never names the counterpart operation or other siblings.
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?
No when-to-use guidance, no when-not-to-use, and no mention of where a media_id comes from (presumably the upload_whatsapp_media response). The agent is left to infer the full lifecycle from sibling names.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_batch_statusARead-only
Query the status of multiple messages at once.
Maps to POST {domain_url}/cgpapi/batch/messages/status. Each item is
{"id": <message id>, "message_type": "SMS"} (currently only SMS is
supported by this Connect API endpoint).
| Name | Required | Description | Default |
|---|---|---|---|
| items | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds the upstream endpoint mapping and the supported message_type constraint, but says nothing about batch size limits, partial-failure behavior, or rate limits for a bulk query.
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?
Front-loaded with the purpose, followed by endpoint mapping and the critical item format in two short sentences with no filler. The endpoint line is slightly extraneous but serves as a lead-in to the payload shape.
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?
An output schema exists, so return values need not be described. Combined with readOnlyHint, the description covers the essentials an agent needs (batch scope, item schema, SMS-only constraint); only batch-size and error-semantics details are absent.
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 0% and the single `items` parameter is an untyped object array, so the description carries the burden — and it does: it gives the exact item shape `{"id": <message id>, "message_type": "SMS"}` and notes SMS is the only supported type. It does not state whether the array size is bounded, but the core structure is fully supplied.
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 ('Query the status of multiple messages at once') and the batching scope distinguishes it from the single-message sibling get_message_status. It stops short of naming that sibling explicitly, so the differentiation is implied rather than stated.
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 phrase 'multiple messages at once' implies the batch use case versus the single-message alternative, but no explicit when-to-use, when-not-to-use, or named alternative (get_message_status / send_batch) is given. Usage is inferable but not guided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_message_statusBRead-only
Query the status of a single previously-sent message.
Maps to GET {domain_url}/cgpapi/messages/{channel}/{message_id}.
| Name | Required | Description | Default |
|---|---|---|---|
| channel | Yes | ||
| message_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=false, so safety is covered. The description adds the concrete REST endpoint, which helps the agent understand the underlying call, but says nothing about error behavior for unknown message ids or throttling. A 3 is appropriate given annotations carry the safety profile.
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 short lines, the purpose is front-loaded and the endpoint mapping follows as supporting detail. No filler and nothing redundant.
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?
The tool is a simple single-item read, annotations cover the safety profile, and an output schema exists so return values need not be described. The description supplies the endpoint and parameter placement, leaving only minor gaps around failure cases.
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 0%, so the description must compensate. It partly does: placing {channel} and {message_id} in the URL path clarifies that both are path segments, which the bare schema does not convey. It still gives no format hint for message_id or note that the channel enum values come from the path vocabulary.
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 ('Query the status of a single previously-sent message'), and the word 'single' implicitly separates it from the sibling get_batch_status. However, it never names that sibling, so the differentiation requires the agent to infer it from wording rather than being told.
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 phrase 'previously-sent' hints that the message must already exist, but there is no explicit when-to-use, no when-not-to-use, and no routing to alternatives such as get_batch_status for batch lookups. The agent gets no guidance on choosing this tool over its siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_whatsapp_templatesARead-only
List approved WhatsApp Business (WABA) message templates.
Maps to GET {domain_url}/cgpapi/waba/templates. Templates with the same
name but different languages appear as separate objects (name, language,
languageName, category, components, status).
Auth outlier: unlike every other tool, this endpoint requires a portal
session cookie rather than one of the 4 standard auth methods - set
X-Soprano-Auth-Method: session_cookie and X-Soprano-Session-Cookie: <JSESSIONID value> (or SOPRANO_AUTH_METHOD/SOPRANO_SESSION_COOKIE over
stdio).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint/openWorldHint annotations, the description discloses that templates with the same name but different languages appear as separate objects, and flags a genuine auth outlier requiring a portal session cookie with exact header names and env-var equivalents. This is exactly the operational context an agent cannot get from annotations or schema.
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?
Front-loaded with the purpose, then endpoint mapping, then the auth caveat. Information-dense with little waste; the auth paragraph is longer than ideal but each clause (header names, env-var fallback) is load-bearing.
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?
No output schema exists, yet the description enumerates the return fields and explains the language-duplication semantics. Combined with the explicit auth instructions, an agent has everything needed to call and interpret this tool 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?
The schema has zero parameters, so the baseline is 4. The description lists the fields present on each returned object (name, language, languageName, category, components, status), which adds useful shape information even though there are no inputs to document.
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 (List) and resource (approved WABA message templates) plus the endpoint it maps to. The sibling set is entirely send/media operations, so an agent can immediately distinguish this read-only template-listing tool from the others.
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 purpose implies the usage context (browsing approved templates, presumably before sending), but there is no explicit when-to-use guidance, no prerequisites stated, and no alternatives named. Adequate but leaves the agent to infer the scenario.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_batchA
Send multiple messages in a single batch call.
Maps to POST {domain_url}/cgpapi/batch/messages. Each item in messages
follows the same shape as send_message's payload fields, e.g.
{"channel": "sms", "destination": "...", "text": "..."}.
| Name | Required | Description | Default |
|---|---|---|---|
| messages | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false, openWorldHint=true, and destructiveHint=false, but the description adds no behavioral context beyond the endpoint path and payload shape. It omits batch limits, partial-failure behavior, ordering, rate limits, auth requirements, and atomicity — all important for a batch send tool.
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?
The description is three short sentences, front-loaded with the core action and followed by the endpoint and payload detail. Every sentence contributes directly to correct invocation, with 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?
An output schema exists, so return-value details are appropriately omitted, and the payload shape is referenced. However, for an open-world batch-send operation, the description lacks key operational context such as batch size limits, error handling, and how to track the resulting batch.
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 0%, so the schema itself provides almost no semantic detail for the messages array. The description compensates well by explaining that each item follows send_message's payload fields and gives a concrete example with channel, destination, and text, though it does not document every possible field.
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 states a specific verb and resource — 'Send multiple messages in a single batch call' — and clearly distinguishes the batch operation from the singular send_message sibling. An agent can identify the tool's purpose and scope 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?
The phrase 'multiple messages in a single batch call' implies the intended use case versus send_message, but it does not explicitly state when to choose this tool over send_message, send_broadcast, or get_batch_status. The guidance is implied rather than spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_broadcastB
Send a broadcast SMS order to lists, contacts and/or groups.
Maps to POST {domain_url}/cgpapi/broadcast/sms. endpoints is a list of
{"type": <int>, "id": <int>} references (list/contact/group). Ad-hoc
mobile-only destinations require at least 250 entries.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | ||
| endpoints | Yes | ||
| batch_size | No | ||
| registered | No | ||
| sleep_duration | No | ||
| max_destinations | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false, destructiveHint=false and openWorldHint=true, so the write/external-call profile is covered. The description usefully adds the underlying endpoint (POST .../broadcast/sms) and the shape of `endpoints` references, but says nothing about batching, throttling (sleep_duration/batch_size implications), or what happens to partially failed sends.
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 short, front-loaded sentences with no filler; the action comes first and the constraints follow. The embedded API path is slightly noisy but is the kind of detail that aids mapping to the backend.
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?
An output schema exists, so return values need not be described, and the endpoint structure is covered. However, with six parameters at 0% schema coverage and four of them unexplained — including pacing controls like batch_size and sleep_duration — the definition is not complete enough to invoke the tool confidently.
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 0% and only one of six parameters (`endpoints`) is explained, including its {type, id} reference shape. `text`, `batch_size`, `registered`, `sleep_duration` and `max_destinations` are entirely undocumented in both schema and description, so the description does not compensate for the coverage gap.
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 ('Send a broadcast SMS order') plus the target types (lists, contacts, groups), so the resource is unambiguous. It does not, however, differentiate itself from siblings like send_message or send_batch, leaving the agent to infer when a broadcast is preferable.
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 description gives one concrete usage constraint — ad-hoc mobile-only destinations require at least 250 entries — which implicitly tells the agent when this tool is and isn't viable. But there is no guidance on choosing between this and send_message/send_batch, and no prerequisites or exclusions are stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_messageA
Send a single real-time message via the Soprano Connect API.
Maps to POST {domain_url}/cgpapi/messages/{channel}. Returns the created
message summary (id, destination, status). destination may be a comma
separated list of up to 250 recipients. Either text, template_name, or
one of the channel-specific rich content objects below must be provided.
rcs: RCS-only. Provide exactly one oftext,media,rich_card({"rich_card": {"cards": [{"title": ..., "media": {"file_url": ...}, "suggestions": [{"text": ..., "postback_data": ...}]}]}}). Overridestext/template_namewhen present.whatsapp:{"type": "image"|"video"|"document"|"audio", "image": {"url": ..., "caption": ...}}for media;{"type": "text", "text": {"body": ...}};{"type": "interactive", "interactive": {"type": "button"|"list", "body": {"text": ...}, "action": {...}}};{"type": "template", "template": {"name": ..., "language": ...}};{"type": "location"|"reaction"|"context", ...}.voice:{"text2voice": {"password": ..., "language": "en-AU", ...}}, or{"call_control_object": {"id": ...}}, or{"audio": {"url": ...}}.push_notification:{"notification": {"title": ..., "body": ...}}.
extra is a passthrough dict merged verbatim into the outgoing JSON payload,
for anything not covered by the parameters above (e.g. Viber, which has no
documented rich-content schema in the Connect API guide). See the "Payload
Parameters" section of the Connect API guide for full field details.
| Name | Required | Description | Default |
|---|---|---|---|
| rcs | No | ||
| text | No | ||
| extra | No | ||
| voice | No | ||
| source | No | ||
| channel | Yes | ||
| subject | No | ||
| email_cc | No | ||
| reply_to | No | ||
| No | |||
| email_bcc | No | ||
| key_values | No | ||
| registered | No | ||
| destination | Yes | ||
| reply_to_ton | No | ||
| template_name | No | ||
| launch_timestamp | No | ||
| client_message_id | No | ||
| push_notification | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnlyHint=false, destructiveHint=false, openWorldHint=true). The description goes beyond them usefully: it discloses the REST mapping, that it returns the created message summary, the 250-recipient cap, the mutual-exclusion/override behavior of rich content ('Overrides text/template_name when present'), and that extra is merged verbatim. It omits auth requirements and rate limits, but adds substantive non-obvious behavior.
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?
Front-loads the core action, endpoint, and return in the first two sentences, then organizes channel-specific payload schemas as bullets. It is long but dense and mostly earns its length; the inline nested JSON examples are wordy given no output/param schema help.
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?
An output schema exists so return values needn't be explained, and the description covers the main content paths. However, for a 19-parameter tool with 0% schema coverage, roughly half the parameters go undocumented, and it defers to an external 'Payload Parameters' section an agent may not have.
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 0% for 19 parameters, so the description must carry the burden. It documents the major content-bearing params (text, template_name, rcs, whatsapp, voice, push_notification, extra) and the destination comma-list semantics, but leaves roughly ten params (source, subject, email_cc, email_bcc, reply_to, reply_to_ton, key_values, registered, launch_timestamp, client_message_id) completely unexplained. Partial compensation only.
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 ('Send a single real-time message via the Soprano Connect API'), names the concrete endpoint (POST /cgpapi/messages/{channel}), and the word 'single' implicitly delineates it from send_batch and send_broadcast siblings.
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?
Provides clear context that this sends one message and that either text, template_name, or a channel-specific rich object must be supplied, plus per-channel selection rules (e.g. rcs is RCS-only, push_notification needs a notification object). It stops short of explicitly stating when to choose this over send_batch/send_broadcast, so it is clear but not fully routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
upload_whatsapp_mediaA
Upload media to Facebook for use in WhatsApp messages.
Maps to POST {domain_url}/cgpapi/waba/media/{source} (multipart upload).
source is the WhatsApp sender number the media is uploaded against.
file_content_base64 is the file's raw bytes, base64-encoded. Uses the
connection's normal auth method (no session cookie needed here - that's
only required by list_whatsapp_templates).
| Name | Required | Description | Default |
|---|---|---|---|
| source | Yes | ||
| filename | Yes | ||
| content_type | Yes | ||
| file_content_base64 | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false and destructiveHint=false, so the safety profile is covered. The description adds real value beyond that: the exact endpoint, that it is a multipart upload, and that it uses the connection's normal auth rather than a session cookie. It omits what is created/returned, but an output schema exists.
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?
Compact and front-loaded: the purpose leads, followed by endpoint/path, then the two non-obvious parameter facts and the auth note. No padding, though the parenthetical about session cookies is more detail than most callers need.
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?
With an output schema present, return values need not be described, and annotations cover the safety profile. The description supplies endpoint, transport, auth behavior and the two ambiguous parameters, leaving only `filename`/`content_type` semantics implicit, which are largely self-evident.
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 0%, so the description must carry parameter meaning, and it covers only two of four: `source` (the sender number the media is uploaded against) and `file_content_base64` (raw bytes, base64-encoded). `filename` and `content_type` are left entirely to inference, so the compensation is partial.
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 gives a specific verb+resource ('Upload media to Facebook for use in WhatsApp messages') and even cites the underlying endpoint, so the agent knows exactly what operation it is. It does not contrast itself against the close sibling delete_whatsapp_media or clarify the upload/send pipeline, so it stops short of 5.
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 only implied: the auth note distinguishes this tool from list_whatsapp_templates, which is a partial when-to-use signal. There is no statement of when to call this versus send_message/send_broadcast, nor prerequisites such as a media ID being needed for later sends.
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.
8 tool updates
v0.1.0- First observed
delete_whatsapp_media - First observed
get_batch_status - First observed
get_message_status - First observed
list_whatsapp_templates - First observed
send_batch - First observed
send_broadcast - First observed
send_message - First observed
upload_whatsapp_media
TDQS
Scored across 8 tools
Tools are mostly distinct: send_message (single), send_batch (multiple in one call), and send_broadcast (SMS to lists/groups) have different scopes, and status tools are clearly paired. Minor potential confusion between send_batch and send_broadcast for bulk SMS, but descriptions differentiate well.
All tool names follow a consistent verb_noun or verb_noun_status snake_case pattern (e.g., send_message, get_message_status, upload_whatsapp_media). No mixed conventions or vague verbs.
Eight tools are well-scoped for a messaging API, covering single/batch/broadcast sends, status queries, and WhatsApp-specific templates and media operations without redundancy.
Core messaging lifecycle is covered (send, status, batch, broadcast, WhatsApp media/templates). Minor gaps exist: no tools for managing contacts/lists/groups referenced by send_broadcast, and no dedicated broadcast status query.
Maintenance
Related MCP Connectors
Official MCP server for OmniDimension. Drive voice agents, dispatch calls, and run bulk campaigns.
MCP server for building and testing AI agents with multi-model experimentation and insights.
MCP server unifying ERPs, CRMs, APIs and knowledge base for Claude, ChatGPT and Gemini.
MCP Server for agents to onboard, pay, and provision services autonomously with InFlow
Related MCP Servers
AlicenseAqualityFmaintenanceMCP Server that connects AI agents to Chargebee Platform.245 npm16MIT- AlicenseNot gradedqualityBmaintenanceInfobip MCP Servers let you build AI agents to interact with the Infobip platform through the Model Context Protocol (MCP). Connect to Infobip and enable your agents to perform actions, such as sending messages over channels like SMS, WhatsApp, or Viber, or managing customer data in a controlled, pr35MIT
- FlicenseAqualityNot gradedmaintenanceAn MCP server for interacting with Saptiva AI's suite of models, offering capabilities such as chat completions, chain-of-thought reasoning, and OCR. It enables users to generate semantic embeddings, access specialized prompts, and manage AI-driven workflows through a standardized interface.7-

Smallest MCP Serverofficial
AlicenseAqualityAmaintenanceMCP server for the Smallest AI platform that enables managing AI voice agents, debugging calls, and viewing analytics directly from your IDE.8471 npm1MIT