Connect your AI to Sautikit over MCP
Connect claude.ai with a sign-in — or Claude Code, Cursor, VS Code, or Windsurf with an API key — to the hosted Sautikit MCP server and browse the tools.
Sautikit runs a hosted MCP server at
https://mcp.sautikit.com/mcp (Streamable HTTP). It gives your AI client tools
over your workspace: calls, numbers, wallet, webhooks, voice agents, and
broadcast campaigns — the same public REST API your own code uses, with the
same auth, rate limits, and billing. Agent and broadcast endpoints additionally
enforce scopes server-side.
There are two ways to connect:
On claude.ai, Sautikit connects as a custom connector with a sign-in — no API key required. Access is tied to your Sautikit account and the workspace you pick, and you can revoke it any time.
Add the connector. In claude.ai, open Settings → Connectors → Add custom connector and enter the server URL exactly:
https://mcp.sautikit.com/mcp
The trailing /mcp is required — a bare https://mcp.sautikit.com or a
trailing slash will fail the connection.
Sign in and choose a workspace. Claude sends you to the Sautikit
sign-in. Sign in and pick the workspace this connection should act on —
every call, number, agent, and campaign it touches lives in that workspace.
If you have more than one workspace with the same name, confirm you picked
the right one: after connecting, ask Claude to run list_numbers and check
your numbers appear.
Approve the scopes. The consent screen groups what Claude may do:
Tick only what you need, then choose Allow. Least privilege is a checkbox.
You're connected. The tools are live in that Claude chat. Money-spending and destructive tools still ask you to confirm before they run — for a live, multi-step flow, choosing "Always allow for this chat" keeps it moving.
To revoke, open Settings → Connected apps in the dashboard and remove the connection — access is cut on its next request. To change scopes, remove and re-add the connector in claude.ai.
Create a key in the dashboard (Settings → API keys at app.sautikit.com). The JWT itself is the secret and is shown once — store it in your environment:
export SAUTIKIT_API_KEY="eyJhbGciOiJFUzI1NiIs..."claude mcp add --transport http sautikit https://mcp.sautikit.com/mcp \
--header "Authorization: Bearer $SAUTIKIT_API_KEY"Verify with claude mcp list — sautikit should show as connected.
Add to ~/.cursor/mcp.json (or .cursor/mcp.json in your project):
{
"mcpServers": {
"sautikit": {
"url": "https://mcp.sautikit.com/mcp",
"headers": { "Authorization": "Bearer YOUR_SAUTIKIT_API_KEY" }
}
}
}Add to .vscode/mcp.json — the promptString input keeps the key out of
the file:
{
"servers": {
"sautikit": {
"type": "http",
"url": "https://mcp.sautikit.com/mcp",
"headers": { "Authorization": "Bearer ${input:sautikit-key}" }
}
},
"inputs": [
{
"id": "sautikit-key",
"type": "promptString",
"password": true,
"description": "Sautikit API key"
}
]
}Add to ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"sautikit": {
"serverUrl": "https://mcp.sautikit.com/mcp",
"headers": { "Authorization": "Bearer YOUR_SAUTIKIT_API_KEY" }
}
}
}Treat an AI client like any other integration: mint it a narrow key.
scopes claim and advertises tools based on
your key's permissions. Scopes on agent and broadcast tools are enforced
by the API itself — a key without broadcasts.manage cannot start a broadcast,
whether through MCP or direct REST calls. For calls, numbers, wallet, and webhook
tools, scopes currently control which tools the MCP server advertises; API-side
enforcement for those families is rolling out.place_call, claim_number,
release_number, hangup_call, delete_webhook, start_broadcast,
resume_broadcast, send_agent_call, delete_agent, publish_agent)
carry MCP annotations, so well-behaved clients ask you to confirm before
running them. Keep confirmations on.upsert_agent_tool are write-only — no
read tool ever returns them, so secrets cannot leak into a model's
context.| Tool | Wraps | Behavior |
|---|---|---|
list_calls | GET /v1/calls | read-only; direction/status/date/number filters |
get_call | GET /v1/calls/{id} | read-only; includes the event timeline |
get_call_stats | GET /v1/calls/stats | read-only |
get_call_recording | GET /v1/calls/{id}/recording | read-only; URL + metadata |
place_call | POST /v1/calls | spends money — client confirms |
hangup_call | POST /v1/calls/{call_id}/hangup | destructive |
wait_for_call_event | GET /v1/calls/{id}/control/events | read-only; long-poll for live events (answered, digits) on an mcp-controlled call |
respond_to_call_event | POST /v1/calls/{id}/control/respond | write; reply to a live call event with voice actions |
| Tool | Wraps | Behavior |
|---|---|---|
list_numbers | GET /v1/numbers | read-only |
get_number | GET /v1/numbers/{id} | read-only; call rates folded in |
search_available_numbers | GET /v1/numbers/available | read-only |
claim_number | POST /v1/numbers/{id}/claim | spends money — client confirms |
release_number | DELETE /v1/numbers/{id} | destructive — client confirms |
update_number_routing | PUT /v1/numbers/{id}/routing | write |
| Tool | Wraps | Behavior |
|---|---|---|
get_wallet_balance | GET /v1/wallet/balance | read-only |
list_wallet_statements | GET /v1/wallet/statements | read-only |
get_ai_spend | GET /v1/wallet/ai-spend | read-only |
| Tool | Wraps | Behavior |
|---|---|---|
list_webhooks | GET /v1/webhooks | read-only |
list_webhook_deliveries | GET /v1/webhooks/{id}/deliveries | read-only |
create_webhook | POST /v1/webhooks | write |
update_webhook | PATCH /v1/webhooks/{id} | write |
test_webhook | POST /v1/webhooks/{id}/test | write, safe |
delete_webhook | DELETE /v1/webhooks/{id} | destructive |
| Tool | Wraps | Behavior |
|---|---|---|
list_broadcasts | GET /v1/broadcasts | read-only; state filter, cursor |
get_broadcast | GET /v1/broadcasts/{id} | read-only; funnel + costs |
get_broadcast_report | GET /v1/broadcasts/{id}/report.csv | read-only; summary + outcomes |
create_broadcast | POST /v1/broadcasts | write |
add_broadcast_contacts | POST /v1/broadcasts/{id}/contacts | write; bulk variant folded in |
start_broadcast | POST /v1/broadcasts/{id}/start | spends money at scale — strongest confirm |
pause_broadcast | POST /v1/broadcasts/{id}/pause | write |
resume_broadcast | POST /v1/broadcasts/{id}/resume | spends money — client confirms |
| Tool | Wraps | Behavior |
|---|---|---|
list_agents | GET /v1/agents | read-only |
get_agent | GET /v1/agents/{id} | read-only |
create_agent | POST /v1/agents | write |
update_agent | PUT /v1/agents/{id} | write |
delete_agent | DELETE /v1/agents/{id} | destructive — client confirms |
publish_agent | POST /v1/agents/{id}/publish | write — client confirms |
list_agent_revisions | GET /v1/agents/{id}/revisions | read-only; optional revision param |
list_agent_tools | GET /v1/agents/{id}/tools | read-only; header keys only |
upsert_agent_tool | PUT /v1/agents/{id}/tools/{toolID} | write; header values write-only |
delete_agent_tool | DELETE /v1/agents/{id}/tools/{toolID} | destructive |
send_agent_call | POST /v1/agents/{id}/send | spends money — client confirms |
get_agent_limits | GET /v1/agents/limits | read-only |
| Tool | Wraps | Behavior |
|---|---|---|
validate_voice_actions | local schema validation | read-only; no API call, no cost |
| Tool | Wraps | Behavior |
|---|---|---|
create_workspace | POST /v1/workspaces | write; requires the account.manage scope |
Per-number configuration, so these ride the same numbers.read /
numbers.claim scopes as the rest of the Numbers group. Provisioning is
asynchronous: enable, rotate, and retry return immediately with the trunk
in pending — poll get_whatsapp_calling until it reaches active or
failed. Connecting the WhatsApp Business account itself is not an MCP
tool: Meta's Embedded Signup is an interactive browser flow, so connect the
account in the dashboard first.
| Tool | Wraps | Behavior |
|---|---|---|
get_whatsapp_calling | GET /v1/numbers/{id}/whatsapp | read-only |
get_whatsapp_call_settings | GET /v1/numbers/{id}/whatsapp/call-settings | read-only; live read degrades to stored |
enable_whatsapp_calling | POST /v1/numbers/{id}/whatsapp | write; async — returns pending |
disable_whatsapp_calling | DELETE /v1/numbers/{id}/whatsapp | destructive — client confirms |
rotate_whatsapp_trunk | POST /v1/numbers/{id}/whatsapp/rotate | write; async |
retry_whatsapp_provisioning | POST /v1/numbers/{id}/whatsapp/retry | write; only a failed trunk |
update_whatsapp_call_settings | PUT /v1/numbers/{id}/whatsapp/call-settings | write; synchronous |
set_whatsapp_recording | PUT /v1/numbers/{id}/whatsapp/recording | write |
set_whatsapp_transcription | PUT /v1/numbers/{id}/whatsapp/transcription | write |
All six require the whatsapp.messages scope. Free-form text is only
permitted inside the 24-hour customer service window the contact opened by
messaging you — outside it, send an approved template.
Sautikit does not store WhatsApp messages: inbound messages and delivery
statuses are relayed to your webhook verbatim as whatsapp.event.received,
so there is no conversation history to read back through a tool.
| Tool | Wraps | Behavior |
|---|---|---|
send_whatsapp_message | POST /v1/whatsapp/messages | write; async delivery |
mark_whatsapp_message_read | POST /v1/whatsapp/messages/{wamid}/read | write |
get_whatsapp_call_permission | GET /v1/whatsapp/call-permissions | read-only |
request_whatsapp_call_permission | POST /v1/whatsapp/call-permissions/request | write |
send_whatsapp_call_button | POST /v1/whatsapp/call-buttons | write |
delete_whatsapp_media | DELETE /v1/whatsapp/media/{id} | destructive |
Media upload and download are REST-only — they move binary files, which
MCP carries poorly. Use POST /v1/whatsapp/media (multipart) and
GET /v1/whatsapp/media/{id} (streams the bytes) directly.
Tool failures return the API's error code and message plus a hint — e.g.
wallet.insufficient_balance tells the agent to ask you to top up in the
dashboard, and a 401 means the key is invalid or revoked (mint a new one in
the dashboard). Docs resources ship with the server too: the OpenAPI spec,
the voice-actions JSON schema, and a quickstart are available to your
client as sautikit://docs/* resources.