Integrations
MCP server
A Model Context Protocol server that lets AI agents list channels and templates, check delivery status and the balance, and send messages behind explicit safeguards.
Tools#
The package @omnimessage/mcp speaks stdio, for desktop clients, and streamable HTTP.
| Tool | Kind | What it does |
|---|---|---|
list_channels | Read-only | Channels with type, identifier, connection status and supported message types. |
list_templates | Read-only | WhatsApp templates of a channel. |
get_message_status | Read-only | Status, error and status history of a message. |
get_balance | Read-only | Wallet (micro-USD and USD) and remaining package credits. |
send_message | Sends | One text, template or media message to one recipient. |
Sending is guarded#
A sent message reaches a real person, costs money in live mode and cannot be undone. The server therefore:
- requires
user_confirmed: trueon everysend_messagecall; the tool description tells the model to set it only after the user approved the recipient and the exact content; - refuses to send with a live key unless the operator sets
OMNIMESSAGE_MCP_ALLOW_LIVE_SEND=true; - can restrict recipients to an allowlist (
OMNIMESSAGE_MCP_ALLOWED_RECIPIENTS); - holds back a message identical to one sent to the same recipient in the last five minutes, because agents repeat tool calls after timeouts, unless
allow_duplicateis set; - can run without the send tool at all (
--read-only).
Quick start (stdio)#
Add the server to the MCP configuration of your client. With an om_test_ key nothing is delivered and nothing is billed; sandbox channels are named ch_test_<type>.
{
"mcpServers": {
"omnimessage": {
"command": "npx",
"args": [
"-y",
"@omnimessage/mcp"
],
"env": {
"OMNIMESSAGE_API_KEY": "om_test_..."
}
}
}
}Streamable HTTP#
OMNIMESSAGE_API_KEY=om_test_... OMNIMESSAGE_MCP_TOKEN=$(openssl rand -hex 24) npx @omnimessage/mcp --http --port 3920
# endpoint: http://127.0.0.1:3920/mcp (clients send Authorization: Bearer <OMNIMESSAGE_MCP_TOKEN>)- Server-held key (
OMNIMESSAGE_API_KEYset): every caller acts as that account and authenticates withOMNIMESSAGE_MCP_TOKEN. The server refuses to bind to a non-loopback address without a token. - Caller’s key (
OMNIMESSAGE_API_KEYunset): each request carries the caller’s own OmniMessage API key as the bearer token, and the server stores nothing. - The endpoint is stateless (
POSTonly, JSON responses). On loopback it rejects requests whoseHostorOriginis not a loopback name, which stops web pages from reaching a local server through DNS rebinding. Behind a reverse proxy, add the public host names withOMNIMESSAGE_MCP_ALLOWED_HOSTSand terminate TLS in the proxy.
Configuration#
| Variable | Default | Meaning |
|---|---|---|
OMNIMESSAGE_API_KEY | — | API key. Required for stdio. |
OMNIMESSAGE_BASE_URL | https://api.omnimessage.co/v1 | API base URL. |
OMNIMESSAGE_MCP_ALLOW_LIVE_SEND | false | Allow send_message with a live key. |
OMNIMESSAGE_MCP_ALLOWED_RECIPIENTS | — | Comma-separated recipients send_message may reach. |
OMNIMESSAGE_MCP_READ_ONLY | false | Do not expose send_message (same as --read-only). |
OMNIMESSAGE_MCP_DUPLICATE_WINDOW_SECONDS | 300 | Hold back identical sends for this long; 0 disables. |
OMNIMESSAGE_MCP_TOKEN | — | HTTP mode: the bearer token clients must present. |
OMNIMESSAGE_MCP_ALLOWED_HOSTS | — | HTTP mode: extra Host names to accept. |
Give the server a key with messages:write, messages:read, channels:read and billing:read, not full access. Create it in the console under API keys with selected scopes.
Use as a library#
import { createServer, configFromEnv } from '@omnimessage/mcp';
const server = createServer({ config: configFromEnv(process.env) });