Use Kelam from Claude
Kelam's API doubles as a remote MCP server. Paste one URL into Claude and it can place real phone calls from your agents, follow them while they happen, read the transcripts, and text people back — in claude.ai, in Claude Code, and on your phone.
Why this matters: voice becomes something you can just ask for. "Call these four suppliers and tell me who's cheapest" is one message, not an integration project. No SDK, no webhooks, no glue code.
Set it up
Everything starts with one command, which prints a URL unique to your workspace. It is stable — running it again returns the same URL.
kelam connector
https://api.kelam.sh/mcp/k/kelam_sk_…
Add it to Claude:
claude.ai Settings -> Connectors -> Add custom connector -> paste the URL
Claude Code claude mcp add --transport http kelam <url>
Keep the URL secret — it authenticates your workspace.
Don't have the CLI? curl -fsSL https://kelam.sh | sh then
kelam login — see the quickstart. The URL is also
available from the API directly at GET /connector with your workspace
credential.
claude.ai (web and desktop)
- Settings → Connectors → Add custom connector.
- Paste the URL. Name it Kelam.
- Save. There is no sign-in step — the key is in the URL, which is exactly why this dialog accepts it without an OAuth flow.
The connector then rides along on Claude mobile too, on the same account.
Claude Code
claude mcp add --transport http kelam <url>
Check it with /mcp inside a session. In Claude Code you'll often want the
CLI skill as well — the connector is the fastest path to calls and call
data, while the CLI gives an agent the full build loop (files, verify, tests, experiments).
Any other MCP client
The endpoint is Streamable HTTP at POST /mcp, stateless — plain JSON
responses, no SSE stream, no session id. Auth is HTTP-level and takes two forms: an
Authorization: Bearer <key> header, or the key embedded in the path
(/mcp/k/<key>) for clients whose UI has nowhere to put a header.
Every tool the connector exposes
Eleven tools, each a thin adapter over the same REST route the CLI uses.
| Tool | What it does |
|---|---|
| list_agents | The workspace's agents — id, name, description, phone number, deploy status. |
| get_agent | One agent in full: its config, its scenarios, its tools. |
| place_call | Place an outbound call. to is a phone number, or another agent's name for a free agent-to-agent call. Takes prompt (steer this one call), language, transfer_to, and extract (typed fields to pull out afterwards). Returns a call_id immediately. |
| wait_for_call | Block until the call ends, then return the finished record. This is how Claude follows a call without polling. |
| get_call | One call right now: status, who answered, duration, cost, the live or final transcript, the recording, extracted fields. |
| list_calls | Recent calls, newest first; filter by agent and status. |
| hangup_call | End a live or queued call — immediately, or letting the agent say goodbye first. |
| send_text | Send an SMS from an agent's number. |
| list_messages | Messages, newest first — workspace-wide, one agent's, or a single thread. |
| list_peers | Who your agents have been talking to lately, across calls and texts. |
| get_conversation | Everything with one person: their SMS thread plus every call transcript, oldest first — the bundle to compose a reply from. |
Building and editing agents stays in the Builder or the CLI; the connector is deliberately scoped to operating them.
Things worth asking for
"Call these five roofers, ask for a ballpark on a 1,400 sq ft flat roof, and give me a table of who quoted what and who can start soonest."
"What came in on the line overnight? Summarise each call and flag anything that sounds like a complaint."
"Anyone who called yesterday and didn't book — text them the booking link from the front desk agent."
"Ring the pharmacy on Elm and find out if they have it in stock. Tell me yes or no and the price."
"Pull up the call from the 617 number this morning and tell me exactly where it went wrong."
"Is anything on the line right now? If that call is still going after five minutes, end it politely."
Patterns that work well
Place, then wait — never poll
place_call returns immediately with a call_id; the call runs in
the background. wait_for_call blocks until it finishes and hands back the whole
record. Claude does this on its own, but if it starts checking get_call in a
loop, say "use wait_for_call".
Ask for fields, not summaries
When you want an answer rather than a story, tell Claude to pass extract.
The values land as typed data on the call record, which makes ten calls comparable instead
of ten paragraphs to read.
Batch, then sweep
For a list of numbers: place every call first (they queue safely if you exceed the concurrency cap), collect the ids, then wait on them. Splitting results on who actually answered — a person, a voicemail box, a phone tree — is usually the first thing you want.
Give the call a goal, not a script
prompt is per-call steering layered over the agent's own instructions. "Find
out their Saturday hours and whether they take walk-ins" works. Writing out the dialogue
line by line does not — the agent is having a real conversation.
Security model
- The URL is a credential. Anyone holding it can act in your workspace. Treat it like a password: don't paste it into a shared doc, a screenshot, or a public repo.
- It's a dedicated key. The connector URL carries its own workspace key, minted once and reused, distinct from your CLI login and from the Builder's — so the connector surface is separately identifiable and can be cut without disturbing anything else.
- Workspace-scoped. The key is pinned to one workspace and cannot reach another. The URL form only ever accepts a workspace key, never an operator password.
- No second authorization path. Every tool call is dispatched through the same API routes and the same middleware the CLI hits, so your quotas, roles and tenant isolation are enforced exactly once, in one place.
- Calls cost money and ring real phones. The tool descriptions say so, and Claude will normally confirm before dialing — but that's a norm, not a lock. Don't hand the URL to anything you wouldn't hand your phone bill to.
FAQ
Do I need the CLI to use the connector?
Only to print the URL the first time (kelam connector), or you can fetch it
from GET /connector with your workspace credential. After that the connector
works on its own — including on mobile, where no terminal exists.
Can Claude build agents through it?
Not through the connector — it reads and operates, and it can read an agent's full
configuration with get_agent. To create and edit, use the
Builder, or give your coding agent the
CLI skill, which covers the whole build loop.
Does it work on Claude mobile?
Yes. A custom connector added on your claude.ai account is available in the mobile app, which means "call them and tell me what they said" from a phone with no laptop nearby.
Why is the URL always the same?
Deliberately: a URL saved in claude.ai has to keep working, so the key is minted once per
workspace and reused. Running kelam connector again never rotates it.
Self-service revocation is a rough edge we haven't finished — if a connector URL leaks, email privacy@kelam.sh and remove the connector from claude.ai in the meantime.
Can I point it at my own deployment?
Yes — the connector URL is just your API's host plus /mcp. Set
KELAM_API_URL and kelam connector prints the URL for that
server.
Which MCP transport is this?
Streamable HTTP, stateless: plain JSON responses, no SSE stream and no session id. That's permitted by the spec and is what makes it work in clients that only offer a URL field.