WhatsApp Business MCP: setup without the boilerplate

You want to send a WhatsApp message from your app. Sounds simple. Two days later you're deep in Meta Business Manager, staring at a rejected message template, wondering why your test number can only message five recipients and why your webhook keeps 401-ing. The WhatsApp Business Platform is powerful, but the setup is a maze of Business Manager accounts, phone number verification, template approvals, and webhook wiring that nobody wants to do twice.
Meta shipping an official MCP server for WhatsApp Business changes what that first day looks like. Instead of clicking through the Meta dashboard and copy-pasting curl commands from the docs, you point an AI coding agent — Claude Code, Cursor, Codex, ChatGPT desktop — at the MCP server and describe what you want. The agent reads the real API surface, calls the right endpoints, and hands you back working code plus a diagnosis when something breaks.
This is a practical walkthrough of what the MCP server actually does, where it saves time, where it doesn't, and how to wire it into a real workflow.
What the WhatsApp Business MCP server actually is
MCP (Model Context Protocol) is Anthropic's open protocol for giving AI agents structured, tool-level access to external systems. An MCP server exposes a set of typed tools — think "send_template_message", "create_template", "get_webhook_status" — that any MCP-compatible client can call. The client is your coding agent. The server is a thin, authenticated wrapper over the WhatsApp Business Platform API.
The important part: the agent isn't guessing at endpoints or hallucinating parameter names. It gets a real schema, real error messages, and real responses. When it writes code, it's writing against tools it just used and verified. That's why MCP-based agent workflows produce fewer "this looks right but doesn't run" moments than pure chat-with-docs approaches.
Compatible clients today include Claude Code, Cursor, ChatGPT's desktop app, Codex CLI, and any client that speaks MCP. You configure the server once and any of them can drive it.
Why WhatsApp Business setup is painful in the first place
Before the MCP server, standing up WhatsApp Business messaging looked like this:
- Create (or claim) a Meta Business Account.
- Add a WhatsApp Business Account (WABA) to it.
- Add a phone number, verify it, and pick a display name Meta will approve.
- Generate a system user access token with the right permissions.
- Register the number for the Cloud API.
- Create and submit message templates for review.
- Wire up a webhook endpoint, verify it with the challenge token, subscribe to the right fields.
- Actually send a message.
Each step has its own failure mode. Display names get rejected for looking too generic. Templates get rejected because a variable placeholder is missing an example. Webhooks fail verification because your handler doesn't echo hub.challenge as plain text. Tokens expire. Phone numbers get stuck in a limbo state where they're added but not registered.
The docs are good. They're also spread across six sections and reference three different API versions in various places. A solo builder trying to add WhatsApp to their SaaS burns two to three days on this the first time. The MCP server compresses that.
Wiring it up in Claude Code and Cursor
Configuration for MCP servers lives in a JSON file that your client reads on startup. Here's the shape for Claude Code (~/.config/claude-code/mcp.json) and Cursor (~/.cursor/mcp.json) — they use the same format.
{
"mcpServers": {
"whatsapp-business": {
"command": "npx",
"args": ["-y", "@meta/whatsapp-business-mcp"],
"env": {
"WHATSAPP_ACCESS_TOKEN": "${WHATSAPP_ACCESS_TOKEN}",
"WHATSAPP_BUSINESS_ACCOUNT_ID": "${WABA_ID}",
"WHATSAPP_PHONE_NUMBER_ID": "${PHONE_NUMBER_ID}"
}
}
}
}
Check the official package name on Meta's developer site before installing — MCP server packages get renamed and re-scoped, and I'd rather you copy the current name than trust a snapshot.
Once the server is registered, restart your client. In Claude Code, run /mcp to see the server status. In Cursor, check the MCP panel in settings. You should see a list of available tools — send message, create template, list templates, verify webhook, get phone number status, and similar.
Now you can just ask. "Send a hello_world template message to +14155551234 from our test number and show me the full response." The agent picks the right tool, fills the parameters, executes, and shows you the response. If it 400s, it reads the error and tells you why.
Handling message templates without losing a day
Template approval is where most first-time WhatsApp integrations stall. Templates are pre-approved message shapes with variable slots — you need them for anything outside a 24-hour customer service window. Meta reviews them for spam, compliance, and clarity.
The rejection patterns are consistent:
- Missing variable examples. Every
{{1}}needs a realistic sample value at submission time. - Vague category. Marketing content submitted as "utility" gets bounced.
- Promotional language in utility templates. "Get 20% off" doesn't fly as a utility message.
- Generic display language. "Hi customer, your thing is ready" reads as a spam pattern.
Ask the agent to draft a template and it will typically produce something like:
{
"name": "order_shipped_v1",
"language": "en_US",
"category": "UTILITY",
"components": [
{
"type": "BODY",
"text": "Hi {{1}}, your order {{2}} shipped and should arrive by {{3}}. Track it here: {{4}}",
"example": {
"body_text": [["Sarah", "A-10428", "Friday, Sep 18", "https://track.example.com/A-10428"]]
}
},
{
"type": "FOOTER",
"text": "Reply STOP to opt out."
}
]
}
Then it submits via the MCP tool, polls status, and reports back. When a template gets rejected, you can paste the rejection reason and the agent will revise. This is where MCP earns its keep: the loop between "submit, get rejected, revise, resubmit" collapses from days to minutes because the agent has the API access to actually do it, not just describe how.
One caveat: Meta rate-limits template submissions and rejects near-duplicates. Don't let the agent spam variations. Have it produce three candidates, pick the best, submit that one.
Testing without messaging real customers
Meta gives you a test phone number when you create a WABA. It can only send to up to five verified recipients and doesn't cost anything per message. That's what you use during development.
A useful pattern is to have the agent build you a small internal CLI that wraps the common test flows. Something like:
# Send a template test to a verified recipient
wa test-template order_shipped_v1 +14155551234 \
--params "Sarah,A-10428,Friday Sep 18,https://track.example.com/A-10428"
# Send a session message (only works inside a 24h window)
wa test-session +14155551234 "Quick question — did that arrive?"
# Check message status
wa status wamid.HBgLMTQxNTU1NTEyMzQVAgARGBI...
You can ask the agent to generate this in an afternoon. The value isn't the CLI itself — it's that the agent already knows the API shape from the MCP server, so the code it writes actually works on the first run instead of the third.
When you're ready for production, you migrate to a real phone number, request higher tier messaging limits, and go through Meta's business verification if you haven't already. The MCP server helps here too — ask it to check current tier and messaging limits, and it'll pull the real numbers from your account instead of guessing.
Webhooks: the part that always breaks
Webhooks are how you receive inbound messages, delivery receipts, and read receipts. They're also where a lot of integrations quietly fall over because the failure is silent — messages just don't arrive in your app.
The setup requires:
- A publicly reachable HTTPS endpoint with a valid certificate.
- A verify token you make up and put in the Meta dashboard.
- A handler that responds to Meta's verification GET request with
hub.challengeas plain text. - A handler that responds
200 OKfast to POST notifications (under a few seconds) or Meta will retry and eventually stop delivering.
Here's a minimal handler the agent will typically produce, in Python with FastAPI:
import hmac
import hashlib
import os
from fastapi import FastAPI, Request, Response, HTTPException
app = FastAPI()
VERIFY_TOKEN = os.environ["WA_VERIFY_TOKEN"]
APP_SECRET = os.environ["WA_APP_SECRET"].encode()
@app.get("/webhook")
async def verify(request: Request):
params = request.query_params
if (params.get("hub.mode") == "subscribe"
and params.get("hub.verify_token") == VERIFY_TOKEN):
return Response(content=params.get("hub.challenge"), media_type="text/plain")
raise HTTPException(status_code=403)
@app.post("/webhook")
async def receive(request: Request):
body = await request.body()
sig = request.headers.get("x-hub-signature-256", "")
expected = "sha256=" + hmac.new(APP_SECRET, body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(sig, expected):
raise HTTPException(status_code=401)
payload = await request.json()
# Return 200 fast; process asynchronously.
# Push to a queue here (SQS, Redis, etc.) and handle in a worker.
return {"status": "received"}
The signature check is the part most tutorials skip and most production integrations regret skipping. Meta signs every webhook with your app secret. Verifying it stops anyone with your webhook URL from injecting fake events.
Once the endpoint is deployed, ask the agent to run the MCP tool that triggers a test webhook or verifies the subscription. It'll tell you whether Meta thinks your endpoint is healthy. If it isn't, it'll tell you why — expired cert, wrong verify token, slow response times.
Troubleshooting: where the agent actually earns its keep
Setup is one-time work. The ongoing win is debugging. WhatsApp Business errors are frequently opaque. A message fails to send and you get back something like error 131047: Re-engagement message. What does that mean? You've fallen outside the 24-hour customer service window and can only send an approved template now.
With the MCP server, you paste the error into your agent and it does three things: looks up the error code, checks your recent message history via the API, and tells you the fix in plain terms. Common ones you'll hit:
| Error code | What it actually means | Fix |
|---|---|---|
| 131026 | Recipient hasn't opted in or number isn't on WhatsApp | Confirm opt-in; verify number via contacts endpoint |
| 131047 | Outside 24h session window | Send an approved template instead of a session message |
| 131051 | Message type not supported for this template | Match template category to content type |
| 132000 | Template param count mismatch | Check {{n}} count vs params array length |
| 133010 | Phone number not registered | Register the number via Cloud API before sending |
The agent can also pull your last N messages, look at delivery vs read rates, spot patterns ("your last 40 messages to Brazil numbers all show delivered but never read — worth checking"), and suggest what to change. That's the kind of ambient monitoring that solo builders usually never get around to.
Where the MCP server doesn't help
Being straight about this so you don't over-invest:
- Business verification. Meta still requires you to upload real business documents. No agent solves that.
- Display name approval. If Meta rejects "AI Assistant" as your display name, the agent can't argue with them.
- Template rejection appeals. You can iterate faster on templates, but Meta's reviewers make the call.
- Higher messaging tier requests. Volume tier upgrades require actual message quality and low block rates over time.
- Compliance with local regulations. WhatsApp business messaging rules vary by country. The agent won't stop you from doing something that's legal in the US but restricted elsewhere.
Also, the MCP server is a wrapper. If Meta's API is down or their template review queue is backed up, the agent just watches with you.
How BizFlowAI approaches this
We wire integrations like this WhatsApp MCP server into Claude-based agents that sit inside real customer workflows — lead capture, order updates, appointment reminders, inbound support routing. The setup work described in this post is the part clients don't want to do themselves, and it's a fraction of the actual project. The larger job is deciding which conversations should be handled by an agent, which should route to a human, what the template library should look like six months from now, and how to keep message quality high enough that Meta keeps raising your tier instead of throttling you.
If you're evaluating adding WhatsApp to your stack and want a working prototype rather than a pitch deck, book a discovery call and we'll walk through what a Claude + WhatsApp MCP setup would look like for your specific customer flow.
What to do this week
If you're serious about adding WhatsApp Business messaging:
- Create the Meta Business Account and WABA today. Verification takes days; start the clock.
- Install the WhatsApp Business MCP server in Claude Code or Cursor tomorrow.
- Draft your first three message templates with the agent and submit for review.
- Build the webhook handler with signature verification. Deploy behind HTTPS.
- Test end-to-end with your test number and five verified recipients.
- Migrate to your production number once templates are approved.
Two focused days if you're a competent developer with the MCP server. Four to five days without it, mostly spent context-switching between docs, dashboard, and terminal. The tool doesn't make WhatsApp Business easy — it makes the boring parts fast, which frees you to think about the parts that actually matter, like what your agent should say when a customer asks something unexpected.
Work with BizFlowAI
If you'd rather have this built for you, that's what we do: production AI automation for solo founders and small teams — agents, integrations, and document pipelines that actually ship.
Book a free discovery call — 30 minutes, we map the highest-ROI automation in your workflow. No pitch deck, just engineering.
More guides like this on the BizFlowAI blog.
Frequently asked questions
How do I configure the WhatsApp Business MCP server in Claude Code or Cursor?
Add an entry to the client's MCP config file (~/.config/claude-code/mcp.json for Claude Code, ~/.cursor/mcp.json for Cursor) that runs the Meta MCP package via npx and passes WHATSAPP_ACCESS_TOKEN, WHATSAPP_BUSINESS_ACCOUNT_ID, and WHATSAPP_PHONE_NUMBER_ID as environment variables. Restart the client, then run /mcp in Claude Code or open the Cursor MCP panel to confirm the tools loaded. Verify the current npm package name on Meta's developer site before installing.
Why do WhatsApp message templates get rejected?
The common rejection reasons are missing example values for {{1}}-style variables, submitting marketing content under the utility category, using promotional language like discount offers in utility templates, and generic spammy phrasing. Every variable needs a realistic sample at submission time and the category must match the actual intent. Meta also rate-limits submissions and rejects near-duplicates, so submit one well-crafted template rather than several variations.
How do I test WhatsApp Business messaging without contacting real customers?
Use the test phone number Meta provides when you create a WhatsApp Business Account. It sends to up to five verified recipients for free and is intended for development. A common pattern is having an AI agent generate a small CLI wrapper for template tests, session messages, and status checks, then migrating to a real number and requesting higher messaging tiers once verified.
What does a WhatsApp Business webhook need to work?
You need a publicly reachable HTTPS endpoint with a valid TLS certificate, a verify token you configure in the Meta dashboard, a GET handler that returns hub.challenge as plain text during verification, and a POST handler that returns 200 OK within a few seconds. Slow or failing responses cause Meta to retry and eventually stop delivering events. Validating the X-Hub-Signature-256 header with your app secret is also required for production.