Docs / Start

MCP server

The wuapi MCP server gives an AI client that speaks the Model Context Protocol, such as Claude, Cursor or VS Code, 87 tools over your wuapi account: send a message, show the QR code that links a number, read a conversation, add people to a group, set up a webhook, invite a customer. Each tool call is one request to the REST API with your API key, so the key's scope, the limit of 600 requests per minute per key and the dashboard Logs apply as for any other client.

local (stdio)hosted (Streamable HTTP)
runson your machine: npx -y @wuapidev/mcpat https://wuapi.dev/api/mcp
keyWUAPI_API_KEY environment variableAuthorization: Bearer wu_live_... header, or OAuth
needsNode 20 or latera client that sends a custom header or speaks MCP's OAuth

Connect a client

Create a key under API keys in the dashboard. A project key limits the server to one project. Then add the server to your client:

# Local: runs on your machine
claude mcp add wuapi --env WUAPI_API_KEY=wu_live_... -- npx -y @wuapidev/mcp

# Hosted: nothing to install
claude mcp add --transport http wuapi https://wuapi.dev/api/mcp --header "Authorization: Bearer $WUAPI_API_KEY"

The dashboard's MCP server screen (/app/mcp) builds these for you from one of your keys, with read-only and a project as options, one-click install links for Cursor and VS Code and a connection test. Claude Desktop reads claude_desktop_config.json (Settings, Developer, Edit Config). Cursor reads ~/.cursor/mcp.json, or .cursor/mcp.json in a project. VS Code reads .vscode/mcp.json and asks for the key once, so it stays out of the file. Any other client that starts a local command works with the stdio server and WUAPI_API_KEY in its environment; any client that sends a custom header works with the hosted one. Clients that reach remote servers only through OAuth, as Grok, ChatGPT and Claude.ai do, use the next section.

Connect with OAuth

Chat apps that add remote MCP servers as connectors sign in with OAuth instead of a header. Give them the hosted URL, https://wuapi.dev/api/mcp. Most find the rest on their own: the server's 401 points to its metadata, the app registers itself and opens a wuapi page in your browser. Sign in, pick the organization (all of it or one project) and approve. The app gets an API key named MCP · <app>, listed on API keys. Revoke it there to disconnect the app.

If the app asks for the OAuth settings itself, as Grok's custom connector does, fill them in like this:

fieldvalue
Client IDwuapi-mcp
Client secretleave it empty
Authorization endpointhttps://api.wuapi.dev/oauth/authorize
Token endpointhttps://api.wuapi.dev/oauth/token
Scopeswuapi
Token auth methodnone (PKCE only)

The consent page shows where the approval goes (the app's address). Approve only a connection you just started. An OAuth key has the full access of an organization or project key: read-only mode is not available through OAuth yet, so use a header client with Wuapi-Read-Only if you need it. The key does not expire. If you revoke it, the app asks you to connect again.

Configuration

stdio variablehosted headerdoes
WUAPI_API_KEYAuthorization: Bearer ...Required. Your API key.
WUAPI_PROJECTWuapi-ProjectAct inside one project: its id or ext:<externalId>.
WUAPI_MCP_READ_ONLYWuapi-Read-Onlytrue registers only the tools that read. The --read-only flag does the same.
WUAPI_BASE_URLAPI base URL. Default https://api.wuapi.dev. Must be https, or http on localhost.

Tools

areatools
Contextget_current_key
Accountslist_accounts, get_account, get_account_qr_code, create_account, request_pairing_code, reconnect_account, list_proxy_locations, update_account, unlink_account, set_presence, set_disappearing_timer, reject_call
Messagessend_text, send_media, upload_file, send_location, send_contact, send_poll, send_buttons, reply_to_message, react_to_message, get_message, list_messages, edit_message, delete_message, cancel_message, vote_in_poll, forward_message, star_message
Chatslist_chats, get_chat, mark_chat_read, send_read_receipts, archive_chat, pin_chat, mute_chat, delete_chat, manage_labels
Contactslist_contacts, get_contact, check_numbers, lookup_contacts, save_contacts, lookup_whatsapp_info, manage_block_list
Profilemanage_profile, manage_favorite_stickers, manage_privacy
Groupslist_groups, get_group, create_group, add_group_participants, remove_group_participants, promote_group_participants, demote_group_participants, get_group_invite_link, reset_group_invite_link, leave_group, manage_group_settings, manage_group_joins, manage_community
Channelsmanage_channel
Storiespost_story, manage_stories
Webhookslist_webhooks, get_webhook, create_webhook, update_webhook, delete_webhook
Incoming webhookslist_incoming_webhooks, get_incoming_webhook, create_incoming_webhook, update_incoming_webhook, delete_incoming_webhook
Projectslist_projects, get_project, create_project, manage_project
Invitationscreate_invitation, list_invitations, get_invitation, cancel_invitation, resend_invitation, manage_branding
Usageget_usage, get_usage_by_project

Every tool declares a JSON schema for its input and returns the API's own object as structured content, without nulls. Together they reach every operation of the REST API except the two that return a secret. Tools that read carry readOnlyHint. Tools that delete, revoke, reset, block or leave carry destructiveHint and take confirm: true, which the model has to set on purpose and your client shows you before the call: delete_message, cancel_message, delete_chat, remove_group_participants, reset_group_invite_link, leave_group, delete_webhook, delete_incoming_webhook, cancel_invitation, resend_invitation. Sends take an optional idempotencyKey, so a retried call does not send twice. get_account_qr_code returns the QR code as an image the client can show.

Resources with many small operations are one tool with an action argument, so the list stays short enough for a model to pick from. The tool's description lists its actions and each field says which actions use it. Only the destructive actions need confirm: true: unlink_account (logout, delete), manage_labels (delete), manage_block_list (block), manage_profile (delete_picture, reset_contact_link), manage_group_settings (delete_picture), manage_stories (delete), manage_project (delete, revoke_key). In read-only mode a tool that mixes reads and writes keeps only its reading actions. To post to a channel, use send_text or send_media with to set to the channel id.

toolactions
`unlink_account`logout, delete
`set_presence`online, offline, typing, recording, paused, subscribe
`manage_labels`upsert, delete, label_chat, unlabel_chat, label_message, unlabel_message
`save_contacts`one, many, backfill_auto_save
`lookup_whatsapp_info`contact_picture, business_profile, resolve_link, bots, sticker_pack, order
`manage_block_list`list, block, unblock
`manage_profile`update, set_picture, delete_picture, get_contact_link, reset_contact_link
`manage_favorite_stickers`list, get_file, add, remove
`manage_privacy`get, get_story_privacy, update
`manage_group_settings`update, set_picture, delete_picture
`manage_group_joins`preview_invite, join, list_requests, approve_requests, reject_requests
`manage_community`create, list_groups, list_members, link_group, unlink_group
`manage_channel`list, get, preview_invite, list_messages, create, follow, unfollow, mute, unmute, react, mark_viewed
`manage_stories`list, list_own, get, viewers, view, react, reply, delete
`manage_project`update, delete, list_keys, revoke_key
`manage_branding`get, update

Projects, invitations, branding and usage need an organization key. Creating a project API key and rotating a webhook endpoint's signing secret are not tools: both return a secret exactly once, and tool results never carry secrets. Do them in the dashboard or with the SDK. Sending a test webhook event and reading the request log have no public endpoint, so they are not tools either; they are in the dashboard.

Resources and prompts

Resources a client can attach to the conversation: https://wuapi.dev/openapi.json, https://wuapi.dev/llms-full.txt, https://wuapi.dev/llms.txt and wuapi://webhook-events. Prompts, which Claude Code lists as slash commands: send_message (to, message), setup_webhook (url, events) invite_customer (customer, externalId, email) and use_streams (project, language).

Examples

you askthe tools it calls
Send "Your order shipped" to +584241112233 from the Front desk number.list_accounts, check_numbers, send_text, get_message
Link a new number that exits from Mexico City.list_proxy_locations, create_account, get_account_qr_code
What did +584241112233 write today? Reply that we're on it.list_messages, reply_to_message
Send my webhook the incoming messages at https://example.com/hooks/wuapi.list_webhooks, create_webhook
Invite Northwind (customer_8812) to link their WhatsApp.list_projects, create_project, create_invitation
How much did each customer use last month?get_usage_by_project
Follow the channel at https://whatsapp.com/channel/0029Va... and mute it.manage_channel (preview_invite, follow, mute)

Security

  1. The key stays in your client's configuration or header. The server never logs it, never returns it and never puts it in an error. The hosted endpoint stores nothing: it checks the key with GET /v1/me when a client connects, then passes it to the API on each call.
  2. Tool results carry no secrets. A webhook endpoint's signing secret is returned by the API only when the endpoint is created; create_webhook drops it and tells you to reveal it in the dashboard. No tool creates API keys or rotates a signing secret.
  3. Narrow what the model can do: a project key reaches one project, and read-only mode removes every tool that writes.
  4. Media URLs are downloaded by the API, which refuses private and internal addresses; the MCP server fetches nothing on a tool's behalf.
  5. Every argument is checked against the tool's schema before any request. A base URL that is not https is refused, so the key never travels in clear text.
  6. A model can be steered by what it reads, including inbound messages. Keep your client's confirmation prompts on for tools that send or delete.

The source is the npm package @wuapidev/mcp (MIT), built on the TypeScript SDK. It also exports createWuapiMcpServer and a stateless HTTP handler, createWuapiMcpHttpHandler from @wuapidev/mcp/http, to host it yourself.

The tools call the REST API: every endpoint, error code and webhook event is in the docs and openapi.json.