MCP vs REST · voice agents
MCP vs REST for Voice Agents
Short answer: use REST when your code decides what happens, and MCP when a model decides. For phone calls the two are not rivals. In CallMCP most tools state the REST route they mirror, so both surfaces reach the same handlers with the same key. The question is who is holding the steering wheel.
First, separate the control plane from the audio
Neither MCP nor REST carries the conversation. Once a call connects, audio flows between the carrier and a voice runtime that listens and speaks in real time. What your agent touches is the control plane: start a call, check its status, fetch the transcript, attach a number, register a webhook. Those are short request/response operations, not a media stream, so "MCP adds overhead to my voice agent" is usually the wrong worry. The tool call that starts a call happens once; the speech loop runs elsewhere.
your agent ──tools/call or REST──▶ control plane ──▶ carrier ──▶ phone
│ ▲
└── voice runtime ◀────┘ (audio, real time)
your agent ◀──transcript, status, webhooks── control planeTwo meanings of "MCP for voice"
Search results blur two different things. Some MCP servers help a coding agent write telephony code. Twilio's, for example, is described by Twilio as a server that lets coding agents search and retrieve its API specs so they generate accurate integration code. Other MCP servers execute actions at runtime: the tool call itself places the call. CallMCP is the second kind. If you need your agent to phone someone at 3pm tomorrow, a documentation server won't do it. You either write the REST integration it helps you generate, or connect a runtime server.
Same action, both surfaces
list_numbers says it mirrors GET /api/v1/numbers. Here is the MCP form an agent sends:
POST https://callmcp.ai/mcp
Authorization: Bearer kc_live_...
Content-Type: application/json
Accept: application/json, text/event-stream
{ "jsonrpc": "2.0", "id": 7, "method": "tools/call",
"params": { "name": "list_numbers", "arguments": {} } }Other pairs, quoted from the tool descriptions: attach_number mirrors POST /api/v1/phone-numbers, detach_number mirrors DELETE /api/v1/phone-numbers, search_available_numbers mirrors GET /api/v1/phone-numbers/search, set_webhook mirrors POST /api/v1/webhooks, and create_agent mirrors POST /api/v1/agents. Because the handlers are shared, a call record created through one surface reads back identically through the other.
Where they actually differ
| Discovery | MCP: tools/list returns every tool with its JSON Schema, unauthenticated, at runtime. REST: you read docs or an OpenAPI file at build time. |
| Who chooses | MCP: the model picks the tool and fills the arguments from context. REST: your code picks the endpoint. |
| Risk signals | MCP tools carry readOnlyHint, destructiveHint, idempotentHint and openWorldHint. Clients like Claude use them to decide when to ask a human. REST has no shared equivalent. |
| Results | MCP returns a text block a model can read plus structuredContent for code. REST returns JSON for code. |
| Auth | Same bearer key, same per-tool scopes (calls:write, numbers:write, and so on). |
| Events | Webhooks are plain signed HTTP POSTs either way. Your receiver is ordinary server code. |
Annotations are hints, not guardrails
The strongest argument for MCP in a calling agent is the human-in-the-loop pattern, and it is also the easiest to overstate. The MCP tools specification says clients must treat annotations as untrusted unless they come from trusted servers, and that there should always be a human able to deny tool invocations. A destructiveHint: true on make_call makes a well-behaved client ask first. It does not stop a client that ignores it. CallMCP is explicit about this: make_call executes on a valid scoped key with no server-side approval step, while buy_number and config-changing tools go through a server-side approval broker. The safety page lists exactly which is which.
When to choose REST
- Deterministic pipelines. A nightly job that confirms tomorrow's appointments from your database does not need a model to choose a tool.
- Batch work and reporting. Pulling call logs into a warehouse is ordinary data plumbing.
- Your own UI. A button in your app that starts a call should hit an endpoint directly.
When to choose MCP
- The model decides whether to call. "Follow up with anyone who asked for a quote this week" is a judgment call over context, which is what tool use is for.
- You want the client's confirmation UI. MCP clients that honor annotations put a human prompt in front of destructive tools without you building one.
- You want discovery without a client library. Point any MCP client at
https://callmcp.ai/mcpand it learns the catalog fromtools/list.
Most production setups use both: MCP for the agent's judgment calls, REST and webhooks for the deterministic plumbing around it. If the next question is getting a line in the first place, see how to give an AI agent a phone number.