Skip to main content
Glama

phonecall

Let your agent make phone calls. A Grok Voice agent places the call through Twilio and sounds like a person. When it needs a decision, it asks your agent mid-call and keeps the line open. When the call ends, you get a summary and the full transcript.

How an agent makes a phone call

Quick start

You need:

  • a Cloudflare account

  • an xAI API key

  • a Twilio account with a voice number (trial accounts can only call verified numbers)

  • Node 20 or later

git clone https://github.com/anomalyco/phonecall && cd phonecall
npm install
npx wrangler deploy   # prints your Worker URL: https://phonecall.<you>.workers.dev
npm run setup         # asks for your keys, connects your number to xAI, stores the secrets
npm link              # puts the phonecall CLI on your PATH

Make a test call. A second AI plays the other side, and nobody is dialed:

phonecall call --simulate "You run the counter at a busy pizza place." \
  --brief "Order a large pepperoni for pickup at 7pm." --watch

Then call a real number:

phonecall call +14155550100 --watch \
  --brief "Book a table for 2 on Friday around 7pm. Anything from 6:30 to 8 is fine."

Related MCP server: Twilio Call Service MCP Server

Use it from an agent

The Worker is also an MCP server at /mcp. In OpenCode, add this to opencode.json:

{
  "mcp": {
    "phonecall": {
      "type": "remote",
      "url": "https://phonecall.<you>.workers.dev/mcp",
      "oauth": false,
      "timeout": 90000,
      "headers": { "Authorization": "Bearer {file:~/.config/phonecall/token}" }
    }
  }
}

Other MCP clients need the same URL and an Authorization: Bearer <token> header. The token is in ~/.config/phonecall/token. phonecall_watch can take up to 50 seconds, so allow at least that much time per tool call.

Tool

What it does

phonecall_start

Starts a call from a number and a brief, and returns a job_id

phonecall_watch

Waits for the next question or the end of the call

phonecall_reply

Answers a question while the call is live

phonecall_report

Returns the summary, the questions and the transcript

phonecall_list

Lists recent calls

phonecall_hangup

Ends a call now

An agent calls phonecall_start, then calls phonecall_watch repeatedly. What it does next depends on the type phonecall_watch returns:

  • input_request: the caller is on the line waiting for an answer. Reply within about a minute.

  • running: nothing new yet. Watch again.

  • done: the call is over, and the report is included.

CLI

Command

What it does

phonecall call <number> --brief "…"

Starts a call. Add --watch to follow it live

phonecall watch <job>

Prints progress, then exits with one JSON line: a question to answer, or the final report

phonecall reply <job> <question-id> "…"

Answers a question

phonecall report <job>

Shows the summary, the questions and the transcript

phonecall transcript <job>

Shows the transcript as plain text

phonecall list

Lists recent calls

phonecall hangup <job>

Ends a call now

call also takes these options:

  • --for sets who the call is for.

  • --as sets the caller's name (default Sam).

  • --voice picks eve, ara, rex, sal or leo.

  • --max-minutes caps the call length (default 10).

  • --answer-timeout sets how many seconds the caller waits for an answer (default 60).

Writing a brief

The brief is the only thing the caller knows. Include:

  • the goal

  • the facts it may share

  • what it may decide on its own

  • what to ask you about first

For example:

Move my dentist cleaning at Bright Smile Dental from Thursday Nov 12 at 2pm
to any weekday morning next week. My date of birth is March 3, 1990, if they
need it. Don't agree to any fee without asking me.

Anything outside the brief turns into a question for you. The caller never makes up details. It never pays for or signs up to anything unless the brief allows it.

How it works

  • Twilio dials the number. When someone answers, TwiML <Dial><Sip> connects the call to xAI's SIP endpoint. An X-Job-Id header tells the Worker which job the call belongs to.

  • A Durable Object per call joins the call over xAI's realtime WebSocket (Grok Voice 3.0). It gives the voice agent a prompt (src/prompt.ts) and four tools: send_dtmf, request_input, check_messages and end_call.

  • Questions go to whoever is watching. Answers reach the voice agent as a check_messages tool result, which it relays straight away.

  • When Twilio reports that the call has ended, Grok 4.7 writes the report from the transcript.

  • Simulated calls dial a second xAI SIP number, where another Grok session plays the other side. That number comes from the fictional 555-0100 to 555-0199 range, so it can't be a real line.

Configuration

npm run setup stores everything as Worker secrets. Nothing is kept in the repo.

Secret

Value

XAI_API_KEY

Your xAI API key

TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN

Your Twilio credentials

TWILIO_PHONE_NUMBER

The number calls come from

PRINCIPAL_NAME

Who calls are made for, by default

PHONECALL_TOKEN

The bearer token for the API, CLI and MCP

SIP_USERNAME, SIP_PASSWORD, XAI_WEBHOOK_SECRET, SIM_NUMBER

Created by setup for the xAI SIP connection

You can also set AGENT_NAME, VOICE and SUMMARY_MODEL with npx wrangler secret put to change the defaults (Sam, eve, grok-4.7).

Running npm run setup again replaces the xAI registration and SIP credentials. It makes a new API token unless PHONECALL_TOKEN is set in your environment. Run npm run setup -- --no-sim to skip the simulator number.

Good to know

  • A call costs about $0.10 a minute: Grok Voice is $0.08, and Twilio outbound plus SIP is about $0.02 in the US.

  • The caller never claims to be human. If someone asks, it says it's an AI assistant.

  • Rules on AI calls vary by place. For example, the FCC treats AI voices as artificial voices under the TCPA. Check the rules that apply to you before calling people.

  • Setup leaves your Twilio number's incoming-call settings alone. Calls back to that number go wherever they went before.

License

MIT

Related MCP Connectors

Related MCP Servers