Voice Calls, SMS, and WhatsApp for Claude Code with cross-channel context sharing.
Better Call Claude MCP Server
Better Call Claude enables bi-directional communication for Claude Code via Voice Calls, SMS, and WhatsApp, supporting cross-channel context sharing. You can initiate tasks by calling Claude, and receive callbacks when Claude needs input or wants to share status. The server is identified as io.github.sns45/better-call-claude and lists 10 tools.
๐ ๏ธ Key Features
Voice calls, SMS, and WhatsApp communication
Bi-directional messaging with Claude Code
Cross-channel context sharing
๐ Use Cases
Start a task by calling Claude from your phone
Get a callback when Claude needs a decision or input
Receive status updates when Claude wants to share progress
โก Developer Benefits
Use phone or messaging channels to trigger and monitor Claude Code tasks
Share context across channels to keep communication aligned
โ ๏ธ Limitations
Tooling scope is limited to the 10 tools reported by this server; detailed capabilities beyond communication are not specified in the provided excerpt.
Declared in the repository manifest (tools.json). Not verified against a live endpoint.
receive_inbound_call
Parameters1
timeout_ms
number
optional
How long to wait for an incoming call (default: 5000ms)
Raw schema
{
"type": "object",
"properties": {
"timeout_ms": {
"type": "number",
"description": "How long to wait for an incoming call (default: 5000ms)"
}
}
}
initiate_call
Parameters1
message
string
required
The message to speak when the user answers
Raw schema
{
"type": "object",
"properties": {
"message": {
"type": "string",
"description": "The message to speak when the user answers"
}
},
"required": [
"message"
]
}
continue_call
Parameters2
conversation_id
string
required
The ID of the active call conversation
message
string
required
The message to speak to the user
Raw schema
{
"type": "object",
"properties": {
"conversation_id": {
"type": "string",
"description": "The ID of the active call conversation"
},
"message": {
"type": "string",
"description": "The message to speak to the user"
}
},
"required": [
"conversation_id",
"message"
]
}
speak_to_user
Parameters2
conversation_id
string
required
The ID of the active call conversation
message
string
required
The message to speak
Raw schema
{
"type": "object",
"properties": {
"conversation_id": {
"type": "string",
"description": "The ID of the active call conversation"
},
"message": {
"type": "string",
"description": "The message to speak"
}
},
"required": [
"conversation_id",
"message"
]
}
end_call
Parameters2
conversation_id
string
required
The ID of the call conversation to end
message
string
optional
Optional closing message before hanging up
Raw schema
{
"type": "object",
"properties": {
"conversation_id": {
"type": "string",
"description": "The ID of the call conversation to end"
},
"message": {
"type": "string",
"description": "Optional closing message before hanging up"
}
},
"required": [
"conversation_id"
]
}
receive_inbound_message
Parameters2
channel
string
optional
Which channel to check for messages (default: any)
timeout_ms
number
optional
How long to wait for an incoming message (default: 5000ms)
Raw schema
{
"type": "object",
"properties": {
"channel": {
"type": "string",
"enum": [
"sms",
"whatsapp",
"any"
],
"description": "Which channel to check for messages (default: any)"
},
"timeout_ms": {
"type": "number",
"description": "How long to wait for an incoming message (default: 5000ms)"
}
}
}
send_sms
Parameters3
message
string
required
The message to send
wait_for_reply
boolean
optional
Wait for user to reply (default: true)
timeout_ms
number
optional
How long to wait for a reply (default: 180000ms / 3 minutes)
Raw schema
{
"type": "object",
"properties": {
"message": {
"type": "string",
"description": "The message to send"
},
"wait_for_reply": {
"type": "boolean",
"description": "Wait for user to reply (default: true)"
},
"timeout_ms": {
"type": "number",
"description": "How long to wait for a reply (default: 180000ms / 3 minutes)"
}
},
"required": [
"message"
]
}
send_whatsapp
Parameters3
message
string
required
The message to send
wait_for_reply
boolean
optional
Wait for user to reply (default: true)
timeout_ms
number
optional
How long to wait for a reply (default: 180000ms / 3 minutes)
Raw schema
{
"type": "object",
"properties": {
"message": {
"type": "string",
"description": "The message to send"
},
"wait_for_reply": {
"type": "boolean",
"description": "Wait for user to reply (default: true)"
},
"timeout_ms": {
"type": "number",
"description": "How long to wait for a reply (default: 180000ms / 3 minutes)"
}
},
"required": [
"message"
]
}
reply_to_conversation
Parameters4
conversation_id
string
required
The ID of the conversation to reply to
message
string
required
The message to send
wait_for_reply
boolean
optional
Wait for user to reply (default: true)
timeout_ms
number
optional
How long to wait for a reply
Raw schema
{
"type": "object",
"properties": {
"conversation_id": {
"type": "string",
"description": "The ID of the conversation to reply to"
},
"message": {
"type": "string",
"description": "The message to send"
},
"wait_for_reply": {
"type": "boolean",
"description": "Wait for user to reply (default: true)"
},
"timeout_ms": {
"type": "number",
"description": "How long to wait for a reply"
}
},
"required": [
"conversation_id",
"message"
]
}
get_conversation_history
Parameters1
conversation_id
string
required
The ID of the conversation
Raw schema
{
"type": "object",
"properties": {
"conversation_id": {
"type": "string",
"description": "The ID of the conversation"
}
},
"required": [
"conversation_id"
]
}
Better Call Claude - Agentic AI Communication Solution
Bi-directional communication for Claude Code via Voice Calls, SMS, and WhatsApp.
Call Claude from your phone to start tasks, and receive callbacks when Claude needs input or wants to share status.
๐ "Hey Claude, refactor the auth module and call me when you're done or need a decision."
[20 minutes later, phone rings]
๐ค "I've finished the refactor but found a security issue. Should I fix it now or create a ticket?"
๐ฌ Or via SMS/WhatsApp:
You: "Claude, how's the deployment going?"
Claude: "Deployment complete. 3 services updated, all health checks passing."
Features
๐ฑ Inbound calls - Call Claude Code from your phone to start tasks
๐ฒ Outbound calls - Claude calls you when done, stuck, or needs decisions
๐ฌ SMS messaging - Send and receive text messages with Claude
๐ฑ WhatsApp - Full WhatsApp Business integration
๐ Cross-channel context - Start on voice, continue on WhatsApp seamlessly
๐ Persistent sessions - Claude stays alive listening for WhatsApp messages
๐ Secure transport - Tailscale Funnel with guided auto-setup
๐ฃ๏ธ Natural conversations - Multi-turn interactions across all channels
๐ง Tool composable - Claude can use other tools while communicating
โก Auto-webhook updates - Twilio webhooks auto-update when URL changes
๐ Free WhatsApp via Baileys - Personal WhatsApp with zero API costs, no business verification
โ Works anywhere - Phone, smartwatch, or any device
โ ๏ธ Testing Status
Channel
Provider
Status
Voice
Twilio
โ Tested & Working
WhatsApp
Twilio Sandbox
โ Tested & Working
SMS
Twilio
โณ Pending A2P 10DLC verification
Voice
Telnyx
๐ฌ Not yet tested
SMS
Telnyx
๐ฌ Not yet tested
WhatsApp
Telnyx
๐ฌ Not yet tested
WhatsApp
Baileys (free)
๐ฌ New - testing welcome
Contributions welcome for testing other provider/channel combinations!
Quick Start
1. Choose Your Setup
Setup
What You Get
Cost
Accounts Needed
Baileys only
WhatsApp messaging
Free
None
Twilio/Telnyx
Voice + SMS + WhatsApp
~$1/mo + usage
Twilio/Telnyx + OpenAI
Hybrid
Voice + SMS (Twilio) + WhatsApp (Baileys)
~$1/mo + voice usage
Twilio/Telnyx + OpenAI
Just want WhatsApp? Skip to Option C: Baileys โ no accounts, no API keys, completely free.
Set webhook URL to your tunnel URL + /webhook/twilio/whatsapp
Get your Account SID and Auth Token
Option C: Baileys (Free WhatsApp โ no API provider needed)
Baileys connects directly to WhatsApp's Web protocol via WebSocket. It uses your personal WhatsApp account โ no business verification, no API costs, no Twilio/Telnyx required.
How it works: Same as WhatsApp Web โ you link a device by scanning a QR code.
Step 1: Clone and install
bash
git clone https://github.com/sns45/better-call-claude
cd better-call-claude
bun install
Step 2: Pair your WhatsApp
bash
bun run baileys:pair
A QR code will appear in your terminal
Open WhatsApp on your phone > Settings > Linked Devices > Link a Device
Scan the QR code
Wait for "Paired successfully!" message
Your session is saved in data/baileys-auth/ โ you won't need to scan again.
Step 3: Add to Claude Code (~/.claude.json or ~/.claude/settings.json):
That's it! No Tailscale, no Twilio, no OpenAI keys needed.
Step 4: Restart Claude Code and test
Send a WhatsApp message to yourself (or have someone message you) โ Baileys receives it and spawns a Claude task. Or ask Claude to send you a WhatsApp:
Note: Tailscale setup is automatic on first run. The server will guide you through installation and authentication if needed.
Restart Claude Code. Done!
Environment Variables
Required Variables
Variable
Description
BETTERCALLCLAUDE_PHONE_PROVIDER
telnyx or twilio
BETTERCALLCLAUDE_PHONE_ACCOUNT_SID
Provider account/connection ID
BETTERCALLCLAUDE_PHONE_AUTH_TOKEN
Provider API key/auth token
BETTERCALLCLAUDE_PHONE_NUMBER
Your Telnyx/Twilio phone number (E.164)
BETTERCALLCLAUDE_WHATSAPP_NUMBER
WhatsApp number if different (e.g., Twilio Sandbox)
BETTERCALLCLAUDE_USER_PHONE_NUMBER
Your personal phone number
BETTERCALLCLAUDE_OPENAI_API_KEY
OpenAI API key for TTS/STT
Baileys (Free WhatsApp)
Variable
Default
Description
BETTERCALLCLAUDE_WHATSAPP_PROVIDER
(unset)
Set to baileys to enable free WhatsApp
BETTERCALLCLAUDE_BAILEYS_AUTH_DIR
data/baileys-auth
Session credential directory
Baileys-only mode: When WHATSAPP_PROVIDER=baileys and no Twilio/Telnyx credentials are set, only USER_PHONE_NUMBER is required. No Tailscale, no OpenAI key needed.
๐ค "Build failed on line 42 of auth.ts. Reply with 'fix' to auto-fix or 'skip' to continue."
WhatsApp
You โ Claude (Inbound WhatsApp)
Send a WhatsApp message to your business number:
๐ฌ "Show me the error logs from the last hour"
Claude responds in WhatsApp:
๐ค "Found 3 errors:\n1. Connection timeout at 14:32\n2. Auth failure at 14:45\n3. Rate limit at 15:01\n\nWant me to investigate any of these?"
Claude โ You (Outbound WhatsApp)
Claude can send rich WhatsApp messages:
๐ค "Code review complete! Found 2 issues:\nโข Line 23: Unused variable\nโข Line 67: Missing error handling\n\nReply 'fix' to auto-fix or 'details' for more info."
Cross-Channel Context
Start a task on voice and seamlessly continue on WhatsApp - Claude remembers everything.
Example Flow
Call Claude:
๐ "Hey Claude, run the todo app in dev mode and let's continue on WhatsApp"
Claude starts the app and enters WhatsApp listening mode:
๐ค "Todo app running on port 5173. Send me WhatsApp messages for more instructions."
Send WhatsApp message:
๐ฌ "Expose it via localtunnel and add the URL to allowed hosts"
Claude responds via WhatsApp:
๐ค "Done! Localtunnel URL: https://xyz.loca.lt - I've added it to vite.config.ts allowedHosts"
Continue the conversation:
๐ฌ "What's the public IP so I can access it remotely?"
๐ค "Your public IP is 203.0.113.42. Access the app at https://xyz.loca.lt"
Key phrases to trigger WhatsApp listening:
"Continue on WhatsApp"
"Let's talk on WhatsApp"
"Listen for my WhatsApp messages"
WhatsApp Sandbox (Twilio)
For testing, you can use Twilio's WhatsApp Sandbox instead of a full WhatsApp Business account.
Typical WhatsApp exchange: Free (Baileys) or ~$0.01-0.02 (Twilio/Telnyx)
Infrastructure
Service
Cost
Phone number
~$1/month
Tailscale Funnel
Free
Security Considerations
Tailscale Funnel Security
Funnel creates a public endpoint but traffic routes through Tailscale's secure network
Integrates with SSO/SCIM for enterprise use
Audit logs available in Tailscale admin console
Webhook signatures verified by default
General
Phone numbers are never logged
Call transcripts are ephemeral (cleared on restart)
Use environment variables, never hardcode credentials
Capability attestation
This repo ships a smithmark capability manifest, smithmark.yaml, at the repo root. It is a "trust as code" declaration of everything this server touches outside its own process: the network hosts it egresses to (Twilio, Telnyx, OpenAI, WhatsApp/Baileys infrastructure, and, transitively, api.anthropic.com via the spawned claude subprocess), the filesystem paths it reads/writes (Baileys auth state, spawn debug logs), the binaries it executes (claude, tailscale, which, open, sudo), the environment variables it reads, and the secret types it handles (Twilio, Telnyx, and OpenAI API keys).
On every GitHub release, .github/workflows/smithmark-attest.yml produces a keyless Sigstore attestation over the published npm tarball: GitHub's OIDC token is exchanged for a short-lived Fulcio signing certificate, the attestation is signed with it, and the signature is recorded in the public Rekor transparency log. There are no signing keys and no secrets involved. The resulting smithmark-attestation.sigstore.json is attached to the GitHub release.
smithmark.yaml is the authoritative declaration of this server's capability surface. smithmark lint (and verify in strict mode) is deliberately host-unaware: it flags every network/exec/filesystem call site as a generic "undeclared" finding regardless of what the manifest declares at the host level, so it will report advisory findings against any real MCP server that talks to the network. Those findings are expected noise, not a sign the manifest is out of date; the manifest above is the record to trust.
Troubleshooting
Voice Issues
Claude doesn't answer calls
Check the MCP server is running: claude --debug
Verify webhook URL is configured in provider dashboard
Ensure Tailscale Funnel is active
Can't make outbound calls
Verify BETTERCALLCLAUDE_USER_PHONE_NUMBER is correct
Check phone number is verified with provider
Ensure sufficient balance in provider account
Audio quality issues
Check network connectivity
Try different TTS voice: BETTERCALLCLAUDE_TTS_VOICE=nova
Check tailscale funnel status shows /bcc pointing to your port
Verify your phone provider webhook URL matches the Tailscale URL (with /bcc path)
Test with curl https://your-hostname.ts.net/bcc/health
Development
bash
# Clone the repo
git clone https://github.com/sns45/better-call-claude
cd better-call-claude
# Install dependencies
bun install
# Run in development mode
bun run dev
Testing locally
bash
# Start the MCP server
bun run dev
# In another terminal, test with MCP inspector
npx @anthropics/mcp-inspector