callcloud-agent-dialer-mcp
v0.5.0
Published
MCP server for the CallCloud Agent Dialer: give an AI agent a phone line. Dials real numbers, screens out answering machines, and connects live humans to your browser over WebRTC.
Maintainers
Readme
CallCloud Agent Dialer — MCP server
Lets an AI agent (Claude, Cursor, etc.) run outbound calls through CallCloud: dial a list, screen out answering machines, and connect live humans to your browser leg over WebRTC.
Separate product from CallCloud's parallel human dialer. It shares telephony + numbers but none of that dialer's machinery.
Machine-readable spec:
https://cdn.jsdelivr.net/npm/callcloud-agent-dialer-mcp/openapi.yaml(OpenAPI 3.1, no auth). Generate your client from this rather than from prose.Docs
- INTEGRATION.md — the API: exact request/response shapes, the credential model, the run lifecycle, browser-leg mechanics, usage and spend.
- BUILD-A-DIALER.md — build a parallel dialer cockpit like CallCloud's own web dialer: architecture, concurrency model, UI rules, and a pre-ship checklist.
All three are fetchable from the CDN with no auth, so you can point an agent straight at the URL:
https://cdn.jsdelivr.net/npm/callcloud-agent-dialer-mcp/INTEGRATION.md
Pricing
$30 per 1,000 dials. No seat, no subscription. Buy a block of 1,000 in Settings → Plan; every dial placed burns one credit. Credits don't expire and don't reset monthly.
A dial is charged when the call is handed to the carrier, so a number that never reaches the
network is never billed. With an empty balance dial returns an error and places no calls, and a
run already in flight stops at the credit that runs out rather than overshooting by however many
lines are live. run_status returns credits_remaining, so an agent can watch the balance without
leaving the tool.
Screening modes
The one real choice, and it is a latency tradeoff. Calls are always answered in the browser, so a screened-in human already has a live leg waiting; what differs is how a pickup is judged.
| Mode | How it decides | Connect delay |
|---|---|---|
| amd (default) | Carrier listens to the pickup audio | Detection delay on every connect, including real people |
| gate | Ring duration, judged before the bridge (the rule our web dialer runs on) | None |
dial(numbers=[...]) // classic detection
dial(numbers=[...], screening="gate") // instant connectGate mode treats a pickup faster than gate_ring_seconds (default 0.5) of real ringing as a machine.
That 0.5s is the parallel dialer's proven production value: voicemail answers within a few hundred
ms of ring start, a person never does.
Both modes fail OPEN: an unmeasurable call is put through, because missing a machine costs seconds
and dropping a real person costs the conversation.
There is deliberately no option to ring a phone. Dialing a phone after the prospect answers makes them wait through your ring time, which is the pause this product exists to remove.
Setup
- In CallCloud, open
/mcpand mint an Agent Dialer API key (cak_…). Shown once. - Add to your MCP client config (e.g. Claude Desktop
claude_desktop_config.json).npxfetches the current version on each launch, so fixes reach you without reinstalling anything:
{
"mcpServers": {
"callcloud-agent-dialer": {
"command": "npx",
"args": ["-y", "callcloud-agent-dialer-mcp"],
"env": {
"CALLCLOUD_API_KEY": "cak_your_key"
}
}
}
}Tools
| Tool | Does |
|---|---|
| dial | Start a run: numbers[], screening? (amd | gate), gate_ring_seconds?, caller_id?, parallel?. Returns run_id. |
| run_status | Poll counts + the currently bridged call + credits_remaining. |
| run_results | Per-number outcomes (filter: humans/machines/connected/all). |
| pause_run | Stop pulling new numbers without losing the queue. In-flight calls finish normally. |
| resume_run | Carry on from where a pause stopped. Re-checks account standing and dial balance. |
| hangup_call | End ONE call and move on, leaving the run dialing. The "next" button in a cockpit. |
| transfer_call | Bring a third party into a live call. Warm: all three are on, the rep can then drop. Costs a dial credit. |
| stop_run | Halt and hang up live calls. |
| list_caller_ids | Numbers the workspace can dial from. |
| list_numbers | Numbers with reputation status + how much of the included allotment is left. |
| search_numbers | Carrier inventory in an area code (read-only, nothing is reserved). |
| provision_number | Provision a number. Free within the included allotment, then $1/month (needs a card on file). |
| release_number | Release a number and stop its $1/month charge. Irreversible; refuses to release the last one. |
| get_usage | Credits, dials, outcome mix, daily series, purchase ledger, auto top-up state, recent runs. |
| set_result | Record a disposition and/or notes on a call. Free-text: you own your taxonomy. |
| schedule_callback | Book a follow-up. Stored and queryable, never auto-dialled. |
| list_callbacks | Scheduled callbacks, soonest first. due=true is the work queue to poll. |
| update_callback | Mark done or cancelled, move the time, edit the note. |
| get_outcomes | The workspace outcome taxonomy your UI should offer. Shared with the CallCloud web dialer. |
| set_outcomes | Replace the outcome list. Labels slugged to stable ids, de-duplicated, max 30. |
| list_runs | Paginated run history, filterable by status and date. |
| get_analytics | Human-answer rate by caller ID, by hour, by screening mode, plus ring-time percentiles. |
| get_webhook | Webhook config + delivery health (last status, last error, consecutive failures). |
| set_webhook | Register the endpoint that receives call events, so you can stop polling. |
| list_calls | Workspace call history (parallel dialer + quick dial) with dispositions, AI summaries, transcript/recording flags. |
| get_call | Full call detail: transcript, AI summary + next steps, rep notes, and a 15-min signed recording_url. |
Events
Register a webhook and stop polling. Signed HMAC-SHA256 over `${timestamp}.${rawBody}`.
| Event | When |
|---|---|
| call.ringing | The destination started ringing. |
| call.connected | A screened-in human was put through. Fires while the call is LIVE. |
| call.voicemail | Screened out as a machine and hung up on. Never bridged, never recorded. |
| call.failed | Never reached the network, or the carrier ended it abnormally. |
| call.completed | The call ended. Carries duration and final verdict. |
| call.transcript | Transcription finished. Lands after call.completed. |
| run.finished | A run reached done or stopped, with final counters. |
| session.paused / session.resumed | Dialing stopped or restarted. |
| rep.disconnected | The browser leg went away. With no leg online, screened-in humans get hung up on. |
The answer-to-bridge path is handled server-side and never waits on your endpoint: the human is conferenced into your browser leg first, the event follows. Nothing you build sits between a prospect answering and your rep hearing them.
See INTEGRATION.md for payload shapes and a verification example.
Example agent flow
"Call these 40 leads, skip the voicemails, and put anyone who picks up through to me."
Agent calls dial(numbers=[...]), polls run_status until remaining=0, then reads
run_results(filter="connected").
