@genuka/whatsapp-mcp
v0.1.0
Published
MCP server for Genuka WA: lets Claude, Cursor, VS Code and other AI agents send WhatsApp messages, templates and campaigns through the official WhatsApp Business Platform (Cloud API).
Readme
@genuka/whatsapp-mcp
An MCP server that lets AI agents and coding assistants (Claude Code, Claude Desktop, Cursor, VS Code, Windsurf and any other MCP client) send WhatsApp messages, templates and campaigns through Genuka WA.
Genuka WA is a REST API for the official WhatsApp Business Platform (Meta's Cloud API). Genuka is a Meta Tech Provider: you connect your own WhatsApp Business number through Meta's Embedded Signup, then send notifications, one-time codes and campaigns over HTTP and receive replies and delivery statuses on signed webhooks, without applying to Meta as a provider yourself. Meta's message rates are billed by Meta with no markup from Genuka; Genuka charges a subscription per WhatsApp number.
This server is a thin, typed layer over that API: every tool maps to one /api/v1 endpoint, with
descriptions that tell the model the rules WhatsApp enforces (the 24-hour window, approved
templates, E.164 numbers) before it gets them wrong.
Full guide: Using Genuka WA from AI agents.
Prerequisites
- A Genuka WA account with at least one connected WhatsApp Business number (sign up, 7-day free trial, no card).
- An API key (
pk_live_…), created in the dashboard on the API keys page. Prefer a key restricted to one business when the agent only needs that business. - Node.js 20 or later (the server runs through
npx).
Configuration
| Variable | Required | Default | Purpose |
| --- | --- | --- | --- |
| GENUKA_WA_API_KEY | yes | | Your Genuka WA API key. |
| GENUKA_WA_BASE_URL | no | https://wa.genuka.com | API origin. Only change it for a self-hosted or local instance. |
The server never prints the key. If it is missing, the server still starts and every tool answers with the reason, so your agent can tell you what to fix.
Claude Code
claude mcp add --env GENUKA_WA_API_KEY=pk_live_xxx --transport stdio genuka-wa -- npx -y @genuka/whatsapp-mcpTo share the setup with your team without committing the key, add a project-scoped .mcp.json
that reads the key from each developer's environment:
{
"mcpServers": {
"genuka-wa": {
"command": "npx",
"args": ["-y", "@genuka/whatsapp-mcp"],
"env": { "GENUKA_WA_API_KEY": "${GENUKA_WA_API_KEY}" }
}
}
}Check it with claude mcp list, or /mcp inside Claude Code.
Claude Desktop
Settings > Developer > Edit Config opens claude_desktop_config.json
(macOS: ~/Library/Application Support/Claude/claude_desktop_config.json,
Windows: %APPDATA%\Claude\claude_desktop_config.json). Add:
{
"mcpServers": {
"genuka-wa": {
"command": "npx",
"args": ["-y", "@genuka/whatsapp-mcp"],
"env": { "GENUKA_WA_API_KEY": "pk_live_xxx" }
}
}
}Then quit and restart Claude Desktop.
Cursor
~/.cursor/mcp.json (every project) or .cursor/mcp.json (this project). ${env:…} reads the key
from your environment:
{
"mcpServers": {
"genuka-wa": {
"command": "npx",
"args": ["-y", "@genuka/whatsapp-mcp"],
"env": { "GENUKA_WA_API_KEY": "${env:GENUKA_WA_API_KEY}" }
}
}
}VS Code (GitHub Copilot)
.vscode/mcp.json in the workspace, or MCP: Open User Configuration for every workspace. VS Code
prompts for the key once and stores it securely:
{
"inputs": [
{ "type": "promptString", "id": "genuka-wa-api-key", "description": "Genuka WA API key", "password": true }
],
"servers": {
"genuka-wa": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@genuka/whatsapp-mcp"],
"env": { "GENUKA_WA_API_KEY": "${input:genuka-wa-api-key}" }
}
}
}Windsurf (Devin Desktop)
Windsurf became Devin Desktop on June 2, 2026. In the Cascade panel, open the … menu, then
Open MCP config file, and add:
{
"mcpServers": {
"genuka-wa": {
"command": "npx",
"args": ["-y", "@genuka/whatsapp-mcp"],
"env": { "GENUKA_WA_API_KEY": "pk_live_xxx" }
}
}
}Tools
| Tool | What it does | Writes? |
| --- | --- | --- |
| list_numbers | Connected WhatsApp numbers and their health. Their id is the connectionId every other tool needs. | no |
| get_number_health | Live quality rating, messaging limit tier, throughput and alerts for one number. | no |
| send_text_message | Free-form text. Delivered only inside the 24-hour customer service window. | sends |
| send_template_message | An approved template, with variables, header, buttons or a one-time code. Works outside the window. | sends |
| send_media_message | Image, video, audio, document or sticker by public link, Genuka asset id or Meta media id. | sends |
| list_templates | Templates with status, category, language and components; optional refresh from Meta. | no |
| get_template | One template, its status history and Meta's live view of it. | no |
| create_template | Create a template and submit it to Meta for review. | yes |
| list_webhooks | Webhook endpoints and their delivery counts. | no |
| create_webhook | Register an https endpoint; returns its signing secret once. | sends your data to that URL |
| test_webhook | Send signed sample events to an endpoint and report its answers. | calls your endpoint |
| list_campaigns | Template campaigns, newest first. | no |
| get_campaign | One campaign with per-status recipient counts. | no |
| list_campaign_recipients | Per-recipient status, message id and failure reason. | no |
| create_campaign | A draft campaign: one template, one number, a list of recipients. Sends nothing. | yes |
| launch_campaign | Send a campaign to every pending recipient. | sends |
| get_subscription | Plan, billing status, and usage against limits. Needs an account-wide key. | no |
Each tool declares MCP annotations (readOnlyHint, destructiveHint, idempotentHint,
openWorldHint), so clients can auto-approve reads and ask before anything that sends. API errors
come back as tool errors carrying the API's own code (plan_limit_messages, connection_not_found,
meta_rejected…), Meta's code and trace id when there is one, the request id shown in the
dashboard logs, and what to do next.
What to ask
- "Add WhatsApp order-shipped notifications to my Next.js app with Genuka WA."
- "Which of my templates are approved in English? Send
order_shippedto +237690000001 for Awa's order ORD-1042, shipped with DHL." - "Create a webhook for
https://example.com/api/whatsappthat receivesmessage.receivedandmessage.failed, then test it."
Safety
- These are real messages. Every send and every campaign launch reaches real people, from your real number. Keep your client's confirmation prompts on for the tools marked "sends".
- A webhook is a data exit.
create_webhookforwards every event it subscribes to, customers' phone numbers and messages included, to its URL for as long as the endpoint stays active. Keep the confirmation prompt on for it too, and check that the URL is one you gave the agent, not one it picked up from a page or a file. - Allowance and Meta billing. Each message counts against your plan's message allowance for the billing period. Template messages are billed by Meta to your own WhatsApp Business Account, at Meta's rates.
- Your number's reputation. Messages people did not ask for get blocked and reported, which lowers the number's quality rating. Send to people who opted in.
- Least privilege. A key restricted to one business can only reach that business's numbers, templates and campaigns. Use one per agent or per environment, and revoke it from the dashboard when you are done.
- Keep the key out of git. Use environment variable expansion (
${GENUKA_WA_API_KEY},${env:GENUKA_WA_API_KEY},${input:…}) as in the snippets above.
Development
npm run build --workspace @genuka/whatsapp-mcp
npm test --workspace @genuka/whatsapp-mcp
# Try it against your account with the MCP Inspector
npx @modelcontextprotocol/inspector -e GENUKA_WA_API_KEY=pk_live_xxx node packages/mcp/dist/index.jsThe tests run without a network: request building, error mapping, and a full client/server round
trip over an in-memory transport with a stubbed fetch.
Publishing to the MCP Registry (maintainers)
server.json follows the official registry schema
under the name com.genuka/whatsapp, which matches mcpName in package.json (the registry checks
it against the published npm package). Keep the version identical in package.json, server.json
(twice) and src/version.ts; the test suite fails otherwise.
package.json has no repository or bugs field on purpose: the source repository is private, so
a link to it would be a dead end on npm and in the MCP directories. Add both, and repository in
server.json, once the package has a public repository.
- Publish the package:
npm publish --workspace @genuka/whatsapp-mcp(prepackbuilds it). - Prove the
com.genukanamespace withmcp-publisher, either through a DNS TXT record on the apex ofgenuka.com(mcp-publisher login dns --domain genuka.com …) or through a/.well-known/mcp-registry-authfile served byhttps://genuka.com(mcp-publisher login http --domain genuka.com …). A file onwa.genuka.comwould only provecom.genuka.wa/*. mcp-publisher publishfrompackages/mcp.
See the registry's authentication guide.
License
MIT
