CallAgent
Documentation

Give your agent a phone.

CallAgent is a remote MCP server. Your agent prepares a call and shows you the plan. Once you approve, a voice agent places the call over the normal phone network and reports back. There's no SDK to install.

Your agentClaude, Codex, any MCP client
→
CallAgent MCPplan · approve · limits
→
Voice agentspeech-to-speech, German
→
Phone networka real number rings

Quickstart

Create an account

Sign in with Google, then finish the setup with your name, country and your own phone number. Your token appears on the dashboard.

Connect your client

Add the server with your token as a bearer header (see Client setup) and reconnect. Call server_status to check the connection.

Ask for a call

Tell your agent what you want in plain language. It calls prepare_call, shows you the plan, and waits for your go-ahead.

Approve and listen

On your go-ahead the agent calls approve_and_start, then loops wait_for_call until the call is over and reports the outcome.

Client setup

Streamable HTTP transport, bearer-token auth. The endpoint is https://34.159.148.7.sslip.io/mcp.

Claude Code

terminal
claude mcp add --transport http callagent https://34.159.148.7.sslip.io/mcp \
  --header "Authorization: Bearer cba_live_…"

JSON config (Claude Desktop, Cursor, others)

mcp.json
{
  "mcpServers": {
    "callagent": {
      "type": "http",
      "url": "https://34.159.148.7.sslip.io/mcp",
      "headers": { "Authorization": "Bearer cba_live_…" }
    }
  }
}

Codex

~/.codex/config.toml
[mcp_servers.callagent]
url = "https://34.159.148.7.sslip.io/mcp"
bearer_token_env_var = "CALLAGENT_MCP_TOKEN"
tool_timeout_sec = 60

Set tool_timeout_sec above 50 s: wait_for_call long-polls for up to 50 seconds.

Authentication

Every request carries Authorization: Bearer cba_live_…. The token is the account. Every tool resolves its caller from it, so there is no account parameter to pass, and no way to read or steer somebody else's call. Treat it like a password: keep it out of repositories and shared configs. An unauthenticated request gets HTTP 401.

Call lifecycle

Preparing and starting are two separate tools, and the second one needs an explicit flag. This is enforced in the protocol, not left to the client, so it holds whichever agent is driving.

prepare_call(number, brief, …)       → run_id, the full plan. Nothing dials.
        │  show the plan to the user, get a yes
approve_and_start(run_id, i_understand_this_places_a_real_call=true)
        │                               → dials once. Repeating it never redials.
wait_for_call(run_id, since_seq)      → new transcript lines, pending questions,
        │  loop until final=true            and finally the result
call_review(run_id)                   → optional: QA review after the call

A call keeps running if your MCP client disconnects. Reconnect and keep polling with the same run_id.

Supervising a live call

When the other side offers something the brief does not cover (a different time, another price, a question nobody planned for), the voice agent does not guess. It says something like „Moment, ich frag kurz nach“ and raises a question to you.

  • wait_for_call returns immediately with pending_questions.
  • Answer with nudge_call(run_id, "<answer>") within about 25 seconds; the voice agent puts it into its own words.
  • You can nudge without being asked, too. Normal nudges apply between replies; urgent=true interrupts the current reply.
  • A nudge cannot widen the approved constraints. abort_call hangs up immediately.

Writing a brief

The brief is Markdown, usually in German, and it is the voice agent's whole instruction set. Four sections carry most of the weight:

brief.md
# Rolle & Ziel
Du rufst bei der Praxis Dr. Huber an und vereinbarst einen Kontrolltermin für Thomas.

# Ton
Freundlich, knapp, natürlich. Keine Floskeln.

# Ablauf
1. Begrüßen und den Grund nennen.
2. Nach freien Terminen am Donnerstag fragen.
3. Den frühesten Termin bestätigen und einmal wiederholen.

# Regeln
- Kein Termin vor 14 Uhr.
- Bei Fragen zu Kosten: nachfragen, nicht raten.

# Fertig wenn
- Termin mit Datum und Uhrzeit bestätigt
- Name der Praxis-Mitarbeiterin notiert

Optional directives

Write thisEffect
# Fertig wennA bullet checklist. The agent works through it, ticks off each item in its outcome, and it decides when the call is done.
# VortragstextText the agent must say word for word: a statement, a reference number, a quote.
Anrede: DuUses du instead of Sie.
Bekannt: jaThe callee knows the caller. Informal, and the opening becomes a personal greeting.
Begrüßung: "…"Your own opening line, in quotes (used with du).
Mailbox: keine NachrichtHang up silently on voicemail. By default the agent leaves a short message.
The agent always says it is an AI. It mentions it once, casually, in the greeting, and confirms it honestly if asked. A brief cannot switch this off.

Put hard rules in constraints (up to 30 strings) instead of prose when they must never bend: budget ceilings, earliest and latest times, things never to disclose.

Results & outcomes

When wait_for_call returns final: true it includes a result:

{
  "success": true,
  "outcome": { "status": "erreicht", "summary": "Termin Do 14:30 bestätigt.",
               "facts": { "termin": "Do 14:30", "ansprechpartnerin": "Frau Berger" } },
  "ended_by": "agent",
  "ended_with_goodbye": true,
  "carrier_status": "completed",
  "duration_seconds": 94,
  "cost": { "total_usd": 0.21, … }
}
outcome.statusMeaning
erreichtGoal reached (success: true)
teilweisePartly reached
abgelehntThe other side declined
voicemail · mailboxReached a mailbox
ivrReached a phone menu
declined_screeningCall screening did not put the call through
unklarUnclear; read the transcript

ended_by is one of agent, callee, supervisor_abort, gateway_auto_hangup or timeout_or_error.

Tools

prepare_callwriteno dial

Creates a run and returns the exact plan. Nothing dials. Show the plan to your user.

ParameterTypeNotes
numberstringE.164, e.g. +4989123456
briefstringMarkdown, 1–12,000 characters. See Writing a brief
constraintsstring[]Optional, ≤ 30 items, ≤ 1,000 characters each
voicestringDefault marin. See voices
vadstringDefault server_fast. See turn detection
max_secondsintHard call limit, 30–900. Default 600

Returns run_id, state: "prepared", the normalised plan, and disclosure. It may also include message_for_user, which must be shown verbatim.

approve_and_startdials

Starts a prepared call. Only call it after your user has approved the plan.

ParameterTypeNotes
run_idstringFrom prepare_call
i_understand_this_places_a_real_callboolMust be true, or the call is refused

Idempotent: repeating it never redials. Returns the status view and a next hint.

wait_for_callread-only

Long-polls a call. It returns as soon as the callee asks a question, the call ends, or the timeout runs out.

ParameterTypeNotes
run_idstring
since_seqintPass the previous next_since_seq. Default 0
timeout_sint1–50, default 45

Returns state, final, new_transcript[], pending_questions[], next_since_seq and, when final, result.

nudge_callwrite

Sends guidance into a live call, or answers a pending question.

ParameterTypeNotes
run_idstringMust be an active call
instructionstring1–3,000 characters
urgentbooltrue interrupts the current reply. Default false

Returns nudge_id and state: "queued". The status later shows nudge_applied once it reached the voice session; this confirms delivery, not that the agent followed it.

abort_callhangs up

Hangs up immediately, and the carrier confirms it. A prepared call that never started is simply cancelled.

ParameterTypeNotes
run_idstring
reasonstringOptional, ≤ 500 characters
call_statusread-only

The full record of a call: state, events, transcript, supervisor_needed, outcome, cost and review summary. wait_for_call is usually the better loop. Use this for a one-off look.

call_reviewread-only

A QA review that runs automatically after each call: tasks done and missed, anything unnatural, brief suggestions, and a score from 1 to 10. rerun=true re-evaluates. Returns call_not_finished while the call is still running.

cost_reportread-only

Cost per call and per day for your own calls, in USD. Pass run_id for one call, or period = 1d · 7d · 30d · all. Each value is marked actual (carrier-reported) or estimated.

server_statusread-only

Checks the connection and configuration without exposing secrets. Returns the model, the call limits, and whether each provider is configured. A good first call after connecting.

States

prepared→starting→ dialing→in-progress→ stopping→completed
StateMeaning
preparedPlan created, nothing dialled
starting · dialingBeing placed, ringing
in-progressConnected; the conversation is running
stoppingHang-up requested, waiting for carrier confirmation
start_uncertainThe carrier's answer to the dial request was lost. Never retried automatically, so it cannot ring twice
completedEnded normally
busy · no-answer · failed · canceled · abortedEnded without, or before, a conversation

Voices & turn detection

voice is fixed for the whole call: marin (default), cedar, alloy, ash, ballad, coral, echo, sage, shimmer or verse.

vadBehaviour
server_fastDefault. Replies about 0.5 s after the other side stops speaking
serverSlightly more patient, with a higher threshold for noisy lines
semantic_high · _medium · _lowWaits for a complete thought. _low is the most patient

Limits

LimitValue
Call length600 s default, 900 s maximum, enforced at the carrier
Concurrent calls1 during the pilot
Brief12,000 characters; ≤ 30 constraints
NumbersE.164 only. Premium and service numbers (+49900, +49137, +49118) are blocked
CountriesEU/EEA, Switzerland, United Kingdom, USA
RecordingNever. Text transcripts only, deleted after 7 days

Errors

Tools fail with a readable message, never a silent success. The common ones:

MessageWhat to do
Explicit real-call approval is requiredPass i_understand_this_places_a_real_call=true, after the user said yes
Use an international E.164 phone numberFormat as +49…, without spaces
Premium/service numbers are blockedBy design
Nudge requires an active call…The call has already ended, or the instruction is empty
Dein kostenloser Testanruf ist aufgebraucht…The free call has been used. More is coming
HTTP 401Missing or wrong bearer token

Pilot accounts

During the invite-only pilot, every website account gets one free test call to its own registered number. Whatever number and brief you pass, prepare_call rings your own phone for a short call of up to 4 minutes, in which the agent asks what you would use phone calls for. If you ask for a different number, the plan comes back with a message_for_user explaining this. A call that never connects (busy, no answer) does not count.

Questions? Read how it works or how we handle data.