Open in
Use ThunderPhone as an MCP server
Build, test, validate, and operate ThunderPhone voice agents from Claude, ChatGPT, Claude Code, Codex, Cursor, VS Code, or another Streamable HTTP MCP client.
ThunderPhone exposes a Streamable HTTP Model Context Protocol server at:
https://api.thunderphone.com/v1/mcpThis is the opposite direction from connecting a remote MCP server to a voice agent:
| Direction | Result |
|---|---|
| Remote MCP server → ThunderPhone agent | A voice agent can call the remote server's tools. |
| ThunderPhone → your MCP client | Your coding agent can build, test, and operate ThunderPhone. |
Authenticate
Use OAuth by default for directory clients: sign in, choose an organization, and approve the requested permissions. Revoke access under Organization → API keys → Authorized apps.
For clients configured with an API key, create an sk_live_ key under Organization → Keys and expose it to your MCP client as THUNDERPHONE_API_KEY. The key is bound to one organization; an id owned by another organization behaves as not found.
CLI and stdio alternatives
The ThunderPhone CLI can write client configuration while preserving unrelated servers:
npx -y @thunderphone/mcp setup --client cursor --api-key-env THUNDERPHONE_API_KEY
npx thunderphone mcp setup --client claude-desktop --scope userAfter a global install of @thunderphone/mcp, use thunderphone-mcp setup with the
same options. Setup supports Claude Code, Codex, Cursor, VS Code, Gemini, Claude
Desktop and Windsurf. Direct HTTP is preferred; Desktop uses stdio.
For any stdio-capable client, configure command: "npx" with
args: ["-y", "@thunderphone/mcp"]. The wrapper uses THUNDERPHONE_API_KEY first,
then credentials from thunderphone login, refreshing expired tokens, then
OAuth through mcp-remote. Device login and OAuth require the corresponding API
OAuth rollout. The API-key path does not. Direct HTTP configurations do not read
the CLI credential store; use the stdio wrapper to reuse device login.
These are alternatives to the manual client configurations below.
Client configuration
Claude and ChatGPT sign in with OAuth; no API key is involved. If you do not have a ThunderPhone account yet, choose Create account on the sign-in page and you return to the approval screen after verifying your email.
Claude (web, desktop, and mobile)
- Open Customize → Connectors (Settings → Connectors in older versions). If ThunderPhone appears in the connector directory, select it. Otherwise choose Add custom connector, name it
ThunderPhone, and enterhttps://api.thunderphone.com/v1/mcp. - Select Connect, sign in to ThunderPhone, pick the organization, and approve the permissions.
- In a chat, enable ThunderPhone from the tools menu and ask for what you need, for example "List my agents".
Claude asks before it uses each tool for the first time. To skip most of those prompts, open Customize → Connectors → ThunderPhone and set Read-only tools to always allow. Those tools only look things up: agents, calls, transcripts, balances, docs. Leave Write/delete tools on approval if you want to see each change before it happens.
Custom connectors need a paid Claude plan. On Team and Enterprise plans an owner adds the connector under the organization's connector settings first, then each member connects their own ThunderPhone account.
ChatGPT
- If ThunderPhone appears in the ChatGPT app directory, select it and connect.
- Otherwise open Settings → Apps & Connectors → Advanced settings, turn on Developer mode, and create a connector with the URL
https://api.thunderphone.com/v1/mcpand OAuth authentication. - Sign in to ThunderPhone, pick the organization, and approve the permissions. Add ThunderPhone to a chat from the tools menu.
Deleting an agent or phone number, discarding a draft, launching a campaign, and sending a test request that can write to an external system ask for a second confirmation in either app; see Confirming destructive actions.
Claude Code
claude mcp add --transport http thunderphone https://api.thunderphone.com/v1/mcp \
--header "Authorization: Bearer $THUNDERPHONE_API_KEY"Codex
Add this to ~/.codex/config.toml:
[mcp_servers.thunderphone]
url = "https://api.thunderphone.com/v1/mcp"
bearer_token_env_var = "THUNDERPHONE_API_KEY"Cursor
Create .cursor/mcp.json:
{
"mcpServers": {
"thunderphone": {
"url": "https://api.thunderphone.com/v1/mcp",
"headers": {
"Authorization": "Bearer ${env:THUNDERPHONE_API_KEY}"
}
}
}
}Claude Desktop
Add an mcp-remote bridge to the Claude Desktop configuration:
{
"mcpServers": {
"thunderphone": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://api.thunderphone.com/v1/mcp",
"--header",
"Authorization: Bearer ${THUNDERPHONE_API_KEY}"
],
"env": {
"THUNDERPHONE_API_KEY": "sk_live_YOUR_API_KEY"
}
}
}
}VS Code
Create .vscode/mcp.json and enter the key through VS Code's input prompt:
{
"inputs": [
{
"type": "promptString",
"id": "thunderphone-api-key",
"description": "ThunderPhone organization API key",
"password": true
}
],
"servers": {
"thunderphone": {
"type": "http",
"url": "https://api.thunderphone.com/v1/mcp",
"headers": {
"Authorization": "Bearer ${input:thunderphone-api-key}"
}
}
}
}Tools
Every tool carries MCP annotations. In the tables, R means read-only, D destructive, I idempotent, and O open-world/network interaction. A dash means no hint is set.
Connection
| Tool | Main arguments | Annotations | What it does |
|---|---|---|---|
get_connection_identity | — | R, I | Validates the credential and returns its organization and safe credential metadata. |
Agents
| Tool | Main arguments | Annotations | What it does |
|---|---|---|---|
list_agents | — | R, I | Lists agents. |
get_agent | agent_id | R, I | Gets one agent. |
create_agent | agent configuration | — | Creates an agent. |
update_agent | agent_id, changed fields | D | Stages fields in the agent draft, replacing what the draft had. Runs without a confirmation step: the deployed agent is unchanged until deploy_agent, and discard_agent_draft reverts the draft. |
deploy_agent | agent_id, optional if_updated_at | D, I | Promotes the draft to production. |
discard_agent_draft | agent_id, optional if_updated_at, confirmation_token on the second request | D, I | Discards staged changes. Two-step, see Confirming destructive actions. |
duplicate_agent | agent_id, optional name | — | Copies an agent inside the organization. |
delete_agent | agent_id, confirmation_token on the second request | D, I | Permanently deletes an agent. Two-step. |
list_agent_versions | agent_id | R, I | Lists deployed configuration versions. |
Phone numbers and carriers
| Tool | Main arguments | Annotations | What it does |
|---|---|---|---|
list_phone_numbers | — | R, I | Lists organization numbers and routing. |
get_phone_number_limits | — | R, I | Gets managed-number usage and limits. |
provision_phone_number | optional area_code, city, state, idempotency_key | D, O | Buys a ThunderPhone-managed inbound number. |
list_voip_connections | — | R, I | Lists connected customer carriers. |
search_voip_numbers | connection_id, country, type, optional area_code | R, I, O | Searches carrier inventory. |
import_voip_numbers | connection_id, numbers | D, O | Imports numbers already owned at the carrier. |
update_phone_number | phone_number_id, routing/label/webhook fields | D | Updates number routing, including agent assignment. |
delete_phone_number | phone_number_id, confirm, optional release_at_provider, confirmation_token on the second request | D, I, O | Releases a number. Two-step. |
SMS
| Tool | Main arguments | Annotations | What it does |
|---|---|---|---|
send_sms | from_number, to, body, idempotency_key | D, I, O | Sends one plain-text SMS through a connected Twilio or Telnyx number. |
Calls
| Tool | Main arguments | Annotations | What it does |
|---|---|---|---|
list_calls | optional filters, limit, offset | R, I | Lists calls with the REST call-history filters. |
get_call | call_id | R, I | Gets call status and metadata. |
get_call_transcript | call_id, optional live | R, I | Gets the call transcript. |
get_call_audio_url | call_id, optional download | R, I, O | Returns a signed audio URL; it never streams audio through MCP. |
get_call_grade | call_id | R, I | Gets the latest call grade. |
place_call | agent_id, from_number, to_number | D, O | Places one non-idempotent outbound call. |
export_calls | call filters, export_format | R, I | Exports up to the REST endpoint's cap as JSON or CSV. |
Testing and validation
| Tool | Main arguments | Annotations | What it does |
|---|---|---|---|
list_test_scenarios | agent_id | R, I | Lists test scenarios. |
create_test_scenario | agent_id, title, scenario_prompt, optional conditions | — | Creates a scenario. |
generate_test_scenarios | agent_id, optional count, include_edge_cases, locale | O | Generates scenarios from the agent prompt. |
run_agent_tests | agent_id, channel, consent_to_charge, optional selection/matrix | D, O | Executes scenarios through web or telephony. |
get_test_run | agent_id, batch_id | R, I | Gets batch status and per-scenario results. |
list_validation_runs | agent_id | R, I | Lists recent draft validation runs. |
get_validation_status | agent_id | R, I | Gets the latest validation state and draft match. |
Knowledge
| Tool | Main arguments | Annotations | What it does |
|---|---|---|---|
list_knowledge_bases | — | R, I | Lists knowledge bases. |
create_knowledge_base | name, optional description | — | Creates a knowledge base. |
add_knowledge_document | knowledge_base_id, name, content | — | Adds text or Markdown. |
import_knowledge_url | url, optional name | O | Queues a public page for safe ingestion. |
search_knowledge | knowledge_base_id, query | R, I | Searches through production retrieval. |
Integrations, webhooks, and remote MCP servers
| Tool | Main arguments | Annotations | What it does |
|---|---|---|---|
list_integrations | — | R, I | Lists HTTP function integrations. |
create_integration | display_name, function spec, optional endpoint fields | — | Creates an HTTP tool. Add authentication headers in the dashboard. |
test_integration | url, optional method/body/timeout, integration_id with header_names, confirmation_token on the second request | D, O | Sends a bounded, SSRF-protected test request. Saved header values are filled in from the integration and only sent to its own host. POST (the default), PUT, PATCH and DELETE are two-step; GET runs immediately. |
list_webhook_endpoints | — | R, I | Lists signed webhook endpoints. |
list_webhook_deliveries | optional agent_id, optional endpoint_id | R, I | Lists recent payload-free webhook delivery outcomes. |
create_webhook_endpoint | label, url, optional events/status | O | Creates a signed webhook endpoint. |
test_webhook_endpoint | endpoint_id | O | Sends a synthetic event through normal delivery. |
list_mcp_servers | — | R, I | Lists remote servers callable by voice agents. |
create_mcp_server | display_name, url | O | Registers and syncs a remote server. Servers that need authentication headers are added in the dashboard. |
sync_mcp_server_tools | server_id | D, O | Refreshes a remote server's tool catalog. |
Campaigns
| Tool | Main arguments | Annotations | What it does |
|---|---|---|---|
list_campaigns | — | R, I | Lists outbound campaigns. |
create_campaign | campaign fields | — | Creates a draft campaign. |
add_campaign_contacts | campaign_id, contacts | — | Adds up to 5,000 JSON contacts. |
campaign_action | campaign_id, action, optional consent_to_charge, confirmation_token on the second request | D, O | Runs start, pause, resume, or stop. start and resume are two-step; pause and stop run immediately. |
get_campaign_stats | campaign_id | R, I | Gets counters and recent outcomes. |
Voices, billing, and docs
| Tool | Main arguments | Annotations | What it does |
|---|---|---|---|
list_voices | — | R, I | Lists voices and supported languages. |
preview_voice | voice, language, text | O | Generates a sample and returns a signed URL. |
list_voice_clones | — | R, I | Lists custom voice clones. |
get_billing_summary | — | R, I | Gets balance and authoritative tier prices; no payment mutations are exposed. |
search_docs | query, optional limit | R, I, O | Searches the public docs index. |
get_doc_page | path | R, I, O | Fetches one public Markdown docs page. |
All product tools use the same REST code paths as the public API. REST validation, organization scoping, roles, billing admission, quotas, TCPA confirmation, provider safety, and audit behavior therefore apply unchanged.
Confirming destructive actions
Tools marked D change or remove something, or begin dialing real people. Those that cannot be undone take two requests. The first request changes nothing and returns:
{
"status": "confirmation_required",
"action": "Delete agent",
"target": { "id": 195, "name": "Front Desk Receptionist" },
"confirmation_token": "…",
"expires_in_seconds": 600,
"next_step": "…"
}The assistant shows the user what is affected and asks for a yes. It then repeats the request with the same arguments plus confirmation_token. A token is valid for 10 minutes and covers one organization, one tool and one exact set of arguments, so deleting three agents takes three confirmations. campaign_action with pause or stop skips this step so a running campaign can always be halted at once, and so does test_integration with GET. Some D tools run in one request because the D marks their effect, not a server-side confirmation: update_agent replaces what the draft had (discard_agent_draft reverts it), deploy_agent replaces the live configuration, update_phone_number reroutes live calls, sync_mcp_server_tools replaces a remote server's tool catalog, import_voip_numbers re-points numbers at your carrier, run_agent_tests can spend credit, send_sms and place_call reach a real person (place_call keeps its own consent confirmation), and provision_phone_number buys a number. Your MCP client may still ask you to approve them.
Starter prompts
prompts/list advertises five reusable workflows:
create_inbound_receptionistrun_agent_testsbuy_and_attach_numberreview_low_grade_callsadd_url_to_agent_knowledge
Use prompts/get with the listed prompt name and its declared arguments to receive a ready-to-run user message.
Resources
resources/list exposes public, cached references:
| URI | Content |
|---|---|
thunderphone://docs/llms.txt | Public documentation index. |
thunderphone://docs/quickstart | Quickstart Markdown. |
thunderphone://pricing | Current public pricing Markdown. |
Read one with resources/read. Public fetches use a short timeout, a 2 MiB limit, and a ten-minute in-process cache.
Protocol and errors
The server supports protocol versions 2025-06-18 and 2025-03-26; it echoes a supported client version and otherwise selects 2025-06-18. It implements initialize, ping, tools, prompts, resources, and notifications. Notifications return 202 Accepted. This stateless server does not expose an SSE listener or session deletion, so GET and DELETE return 405 Method Not Allowed with Allow: POST.
Tool failures remain successful JSON-RPC responses with isError: true. Their text contains a short sentence followed by a JSON block:
{
"code": "insufficient_balance",
"detail": "There is not enough prepaid balance.",
"next_step": "Call get_billing_summary, add funds in Organization > Billing, then retry."
}The distinct outbound_tcpa_confirmation_required: prefix is retained for place_call. Unknown JSON-RPC methods return -32601 in an HTTP 200 response. JSON-RPC batches are not supported by MCP 2025-06-18 and return a clean -32600 invalid-request error.