Agents can already read, write, and decide. They cannot pick up a phone. So the moment a workflow needs a human voice, it stops and waits for you, and the thing you were automating becomes a task on your list again.
This is a full VoIP line your agent can drive over MCP. It dials real numbers through your own caller ID, detects and drops answering machines, and the second a live human speaks it puts them through. The audio arrives in your browser over WebRTC, so a headset is the whole setup and the person who picks up never waits on a second phone ringing.
You give it numbers. Everything that happens between dialing them and a person being on the line is the product.
Every call is answered in your browser, so a screened-in human always has a live leg waiting. What differs is HOW we decide a pickup is a person, and that decision is where connect delay comes from.
dial(numbers=[...]) // classic detection, the default dial(numbers=[...], screening="gate") // instant connect dial(numbers=[...], screening="gate", gate_ring_seconds=8)
Gate mode fails OPEN: if the ring never registered, the call is treated as a human and put through. Missing a machine costs you a few seconds, wrongly dropping a real person costs you the conversation.
It is a tool, not an app, so it composes with whatever your agent already does.
Two minutes, and afterwards the only thing you need is somewhere to take the call.
Dialing is prepaid: $30 per 1,000 dials, billed once, no subscription behind it. Credits do not expire and do not reset monthly.
This authenticates your MCP client. It is shown once and stored only as a hash, so copy it now.
Paste this into your client config (Claude Desktop uses claude_desktop_config.json) and restart the client. Nothing to install: npx fetches the current version each time it launches, so fixes reach you without you doing anything.
{
"mcpServers": {
"callcloud-agent-dialer": {
"command": "npx",
"args": ["-y", "callcloud-agent-dialer-mcp"],
"env": {
"CALLCLOUD_API_KEY": "cak_YOUR_KEY_HERE"
}
}
}
}The agent calls dial with your numbers and a destination, polls run_status until nothing is left, then reads run_results. Give it a number to ring your phone, or "browser" to take the audio in a tab. You just answer the calls that reach you.
Seven tools. Your agent picks them up automatically once the client restarts.
Register one endpoint and we push these to it. Signed HMAC-SHA256 over `${timestamp}.${rawBody}`, so a captured payload cannot be replayed.
The answer-to-bridge path is handled entirely server-side and never waits on your endpoint: a human is conferenced into your browser leg first, and the event follows. Nothing you build sits between a prospect answering and your rep hearing them.
What connect_to: "browser" needs behind it. Your backend mints a short-lived browser token with your API key, your frontend goes online with it, and live humans arrive over WebRTC.
// your backend (keeps the cak_ key server-side)
POST https://dialer.callcloud.app/api/agent-dialer/browser-token
Authorization: Bearer cak_...
-> { sw_token, browser_token, dial_number, pin, session_id }
// your frontend: copy app/components/useAgentBrowserLine.ts + npm i @signalwire/js
const line = useAgentBrowserLine() // line.goOnline(), line.call, line.goOffline()
// your agent, via MCP:
dial(numbers=[...], connect_to="browser")Working reference build you can try right now: /mcp/console.
If you are building your own UI around the dialer, there is a full integration guide written to be pasted straight into an agent's context: exact request and response shapes, the credential model, the run lifecycle, and the browser-leg mechanics.