Skip to main content
Glama
wuapi MCP server

wuapi MCP server

Official
by wuapidev

wuapi MCP server

npm version CI license

A Model Context Protocol server for wuapi, the WhatsApp API for developers. It lets Claude, Cursor, VS Code and other MCP clients use your wuapi account: send messages, link numbers, read conversations, manage groups, communities, channels, labels, profile and privacy, webhooks, projects and invitations.

Every tool is a call to the wuapi REST API with your own API key, through @wuapidev/sdk. The API decides what the key may do, rate limits it (600 requests per minute per key) and logs each call in your dashboard, exactly as for any other client.

Docs: wuapi.dev/docs/mcp.

How it works. wuapi links your own numbers as devices, the same way WhatsApp Web works. It does not use the WhatsApp Business Platform. WhatsApp can restrict numbers that behave like spam: send only to people who expect your messages.

Two ways to connect

Local (stdio)

Hosted (Streamable HTTP)

Runs

on your machine: npx -y @wuapidev/mcp

at https://wuapi.dev/api/mcp

Key

your npx @wuapidev/cli login, or the WUAPI_API_KEY environment variable

Authorization: Bearer wu_live_... header

Needs

Node 20 or later

a client that sends custom headers

The quickest local setup uses the wuapi CLI: it logs you in from the browser, stores a key on your machine (~/.config/wuapi/credentials.json, readable only by you) and registers the server with your client, with no key in the client's config:

npx @wuapidev/cli login
npx @wuapidev/cli mcp add          # Claude Code, Cursor or VS Code

The local server uses WUAPI_API_KEY when the client sets it, and otherwise that stored login: the current profile, or the one WUAPI_PROFILE names (npx @wuapidev/cli profiles lists them). Or create an API key yourself at wuapi.dev/app/api-keys and pass it as below. A project key limits the server to one project.

Claude Code

# Local, with the key from `npx @wuapidev/cli login`
claude mcp add wuapi -- npx -y @wuapidev/mcp

# Local, with a key in the config
claude mcp add wuapi --env WUAPI_API_KEY=wu_live_... -- npx -y @wuapidev/mcp

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

Claude Desktop

Settings > Developer > Edit Config, then add to claude_desktop_config.json:

{
  "mcpServers": {
    "wuapi": {
      "command": "npx",
      "args": ["-y", "@wuapidev/mcp"],
      "env": { "WUAPI_API_KEY": "wu_live_..." }
    }
  }
}

Cursor

~/.cursor/mcp.json (or .cursor/mcp.json in a project):

{
  "mcpServers": {
    "wuapi": {
      "command": "npx",
      "args": ["-y", "@wuapidev/mcp"],
      "env": { "WUAPI_API_KEY": "wu_live_..." }
    }
  }
}

Or the hosted server:

{
  "mcpServers": {
    "wuapi": {
      "url": "https://wuapi.dev/api/mcp",
      "headers": { "Authorization": "Bearer wu_live_..." }
    }
  }
}

VS Code

.vscode/mcp.json. VS Code asks for the key once and stores it outside the file:

{
  "inputs": [{ "type": "promptString", "id": "wuapi-key", "description": "wuapi API key", "password": true }],
  "servers": {
    "wuapi": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@wuapidev/mcp"],
      "env": { "WUAPI_API_KEY": "${input:wuapi-key}" }
    }
  }
}

For the hosted server use "type": "http", "url": "https://wuapi.dev/api/mcp" and "headers": { "Authorization": "Bearer ${input:wuapi-key}" }.

Other clients

Any client that starts a local command works with npx -y @wuapidev/mcp, with WUAPI_API_KEY in its environment or after npx @wuapidev/cli login. Any client that connects to a remote server with a custom header works with the hosted endpoint. Clients that only connect to remote servers through OAuth, as some chat apps do, cannot use the hosted endpoint yet.

Related MCP server: WhatsApp MCP Stream

Configuration

Variable

WUAPI_API_KEY

Your API key, wu_live_.... When unset, the key npx @wuapidev/cli login stored is used.

WUAPI_PROFILE

Which stored login to use (npx @wuapidev/cli profiles). Default: the current one. Its project and base URL apply unless the two variables below are set.

WUAPI_PROJECT

Act inside one project: its id or ext:<externalId>. Sent as Wuapi-Project.

WUAPI_BASE_URL

API base URL. Default https://api.wuapi.dev. Must be https (or http on localhost).

WUAPI_MCP_READ_ONLY

true registers only the tools that read. Same as the --read-only flag.

The hosted endpoint takes the same options as headers: Wuapi-Project: <id or ext:externalId> and Wuapi-Read-Only: true.

Tools

87 tools reach every operation of the REST API, except the two that return a secret and the two steps of an upload through an upload URL (see below). Tools that read are marked readOnlyHint. Tools that delete, revoke, reset, block or leave are marked destructiveHint and take confirm: true, which the model has to set on purpose and your client shows you before the call.

Area

Tools

Context

get_current_key

Accounts

list_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

Messages

send_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

Chats

list_chats, get_chat, mark_chat_read, send_read_receipts, archive_chat, pin_chat, mute_chat, delete_chat, manage_labels

Contacts

list_contacts, get_contact, check_numbers, lookup_contacts, save_contacts, lookup_whatsapp_info, manage_block_list

Profile

manage_profile, manage_favorite_stickers, manage_privacy

Groups

list_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

Channels

manage_channel

Stories

post_story, manage_stories

Webhooks

list_webhooks, get_webhook, create_webhook, update_webhook, delete_webhook

Incoming webhooks

list_incoming_webhooks, get_incoming_webhook, create_incoming_webhook, update_incoming_webhook, delete_incoming_webhook

Projects

list_projects, get_project, create_project, manage_project

Invitations

create_invitation, list_invitations, get_invitation, cancel_invitation, resend_invitation, manage_branding

Usage

get_usage, get_usage_by_project

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 (marked below) need confirm: true.

Tool

Actions

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

* needs confirm: true.

To post to a channel, use send_text or send_media with to set to the channel id. In read-only mode a tool that mixes reads and writes keeps only its reading actions (manage_channel keeps list, get, preview_invite and list_messages).

get_account_qr_code returns the QR code as an image your client can show. Projects, invitations, branding and usage need an organization key.

Not exposed: creating a project API key, rotating a webhook endpoint's signing secret and rotating an incoming webhook's URL. Both return a secret exactly once, and tool results never carry secrets, so a tool would create a key or secret nobody could read (and a rotation would break your server's signature check at once). Do both in the dashboard or with the SDK. Also not exposed: completing and reading an upload. They belong to the upload-URL flow, where the file's raw bytes are posted to a URL, which a tool cannot do; upload_file takes the bytes in its one call and returns the upload ready to send. Sending a test webhook event and reading request logs have no public API endpoint; they are in the dashboard.

src/operations.ts maps every API operation to the tools that call it; a test keeps it equal to the OpenAPI spec.

Resources and prompts

Resources: https://wuapi.dev/openapi.json (the OpenAPI 3.1 spec), https://wuapi.dev/llms-full.txt (the docs as Markdown), https://wuapi.dev/llms.txt (their index) and wuapi://webhook-events (every event type).

Prompts: send_message (to, message), setup_webhook (url, events), invite_customer (customer, externalId, email) and use_streams (project, language). use_streams helps you receive events with Streams, the live alternative to Webhooks for code with no public endpoint: with the SDK's events.stream in TypeScript and Rust, and the rules of a client in any other language.

Security

  • The key stays where you put it: in the client's configuration, a header, or the CLI's credentials file (mode 0600), which the server only reads. The server never logs it, never returns it, and never includes it in an error.

  • Tool results never contain secrets. A webhook endpoint's signing secret is returned by the API only once, when the endpoint is created; create_webhook drops it and tells you to reveal it in the dashboard instead. An incoming webhook's URL is a credential too: its tools drop it, and the user copies it from the dashboard. There is no tool that creates API keys.

  • Scope the key: a project key reaches one project, and WUAPI_MCP_READ_ONLY=true removes every tool that writes.

  • Media is fetched by the wuapi API, never by this server. The API refuses private and internal addresses.

  • Every argument is validated against the tool's JSON schema before any request. A base URL that is not https is refused, so the key never travels in clear text.

Use it as a library

import { Wuapi } from "@wuapidev/sdk";
import { createWuapiMcpServer } from "@wuapidev/mcp";
import { createWuapiMcpHttpHandler } from "@wuapidev/mcp/http";

// One server per client connection, acting as this key.
const server = createWuapiMcpServer({ client: new Wuapi({ apiKey: process.env.WUAPI_API_KEY }) });

// Or a stateless Streamable HTTP handler: (Request) => Promise<Response>,
// authenticated with each caller's own key as a bearer token.
const handle = createWuapiMcpHttpHandler();

License

MIT

Available Tools

87 tools
add_group_participantsAdd people to a groupA

Add participants to a group the account administers. Each result says whether it worked; someone who cannot be added directly comes back with an invite code.

Inputs: groupId (required), accountId (required), contactIds (required).

archive_chatArchive or unarchive a chatB
Idempotent

Archive a chat on the linked devices, or unarchive it with archived: false.

Inputs: chatId (required), accountId (required), archived.

cancel_invitationCancel an invitationA
DestructiveIdempotent

Cancel an invitation: its link stops working. Completed invitations cannot be cancelled.

Inputs: confirm (required), invitationId (required).

cancel_messageCancel a queued messageA
DestructiveIdempotent

Stop a message that is still queued from being sent. It ends failed with error code cancelled. Fails with not_queued when the message already left; use delete_message for those.

Inputs: confirm (required), messageId (required).

check_numbersCheck numbers on WhatsAppA
Read-onlyIdempotent

Which of these phone numbers have WhatsApp, with their contact id, business name and username when known. Check before sending to a new number.

Inputs: phones (required), accountId (required).

create_accountConnect a new numberA

Start linking a new WhatsApp number. Pick proxyLocation with list_proxy_locations (near where the phone is). Then show the QR code with get_account_qr_code, or pass pairingPhone to link with an 8-character pairing code instead. A linked number is billable; a new organization links its first number with no card. To let someone else link their own number, use create_invitation.

Inputs: proxyLocation (required), name, projectId, historySync, +2 more.

create_groupCreate a groupA

Create a WhatsApp group with the account as owner, inside a community when communityId is given. Participants whose privacy settings refuse being added get an invite code instead (see the result).

Inputs: name (required), accountId (required), participants (required), communityId, +1 more.

create_incoming_webhookCreate an incoming webhookA

Create a secret URL that sends a WhatsApp message from one of the user's numbers to one fixed contact or group when something POSTs to it (JSON {text} or plain text, no API key). The URL is a credential, so it is not returned through this tool: the user copies it from the wuapi dashboard (Integrations, Incoming webhooks).

Inputs: to (required), name (required), accountId (required).

create_invitationInvite someone to link their numberA

Create a branded page (url) where a customer links their own WhatsApp number to your project by QR code or pairing code, without an account on wuapi. Send them the url: it is returned only here. With inviteeEmail, wuapi can email it too.

Inputs: methods, projectId, returnUrl, accountName, +8 more.

create_projectCreate a projectA

Create a project for one of your customers. Set externalId to your own customer id so you can address it as ext:<externalId>. Then invite the customer to link their number with create_invitation. Organization keys only.

Inputs: name (required), metadata, externalId, maxAccounts, +1 more.

create_webhookCreate a webhook endpointA

Register a public https URL to receive events as signed POST requests. The signing secret is not returned through this tool, to keep it out of the conversation: the user reveals it in the wuapi dashboard (Webhooks, rotate the endpoint's secret) and stores it with their server.

Inputs: url (required), events (required), projectId, idempotencyKey.

delete_chatDelete a chatA
DestructiveIdempotent

Delete a chat from the account's linked devices (the phone and WhatsApp Web). The messages wuapi stores are kept and still readable with list_messages. This cannot be undone on the devices.

Inputs: chatId (required), confirm (required), accountId (required), deleteMedia.

delete_incoming_webhookDelete an incoming webhookA
DestructiveIdempotent

Delete an incoming webhook. Its URL stops working at once, for whatever still calls it.

Inputs: confirm (required), incomingWebhookId (required).

delete_messageDelete a messageA
DestructiveIdempotent

Delete an outbound message for everyone (or only on the linked devices with forEveryone: false). A message still queued is cancelled instead and never sent. This cannot be undone.

Inputs: confirm (required), messageId (required), forEveryone.

delete_webhookDelete a webhook endpointA
DestructiveIdempotent

Delete a webhook endpoint. Its events stop at once, including deliveries still retrying.

Inputs: confirm (required), webhookEndpointId (required).

demote_group_participantsRemove admin rightsA
Idempotent

Turn group admins back into regular members.

Inputs: groupId (required), accountId (required), contactIds (required).

edit_messageEdit a sent text messageA
Idempotent

Change the text of an outbound text message, within WhatsApp's edit window (about 15 minutes). A message still queued is sent with the new text.

Inputs: text (required), messageId (required).

forward_messageForward a messageA

Forward a stored message (received or sent) to up to 5 chats of the same account, the way WhatsApp forwards: the recipients see it as forwarded and no file is uploaded again. Works for text, images, videos, audio, voice notes, documents, stickers, locations and contact cards; polls, calendar events, reactions, view-once and deleted messages answer not_forwardable, and so does a contact's story (only a story the account posted, which is a message, can be forwarded). A message that is forwardedManyTimes goes to one chat per call. Returns a list with one queued message per chat, in the order of to; check each with get_message. To label new content as forwarded, use a send tool with forwarded: true instead.

Inputs: to (required), messageId (required), idempotencyKey.

get_accountGet an accountA
Read-onlyIdempotent

One account: status, linked phone number, profile name, proxy location, disconnect reason and last error. hasQrCode says a QR code is waiting to be scanned (get it with get_account_qr_code).

Inputs: accountId (required).

get_account_qr_codeGet the QR code to link a numberA
Read-onlyIdempotent

The QR code to scan in WhatsApp (Settings > Linked devices > Link a device), as an image. Waits a few seconds for one when the account is still starting. QR codes rotate about every 20 seconds: call again if it expired. Returns the status instead when the account is already linked, and the pairing code when it links by phone number.

Inputs: accountId (required), waitSeconds.

get_chatGet a chatA
Read-onlyIdempotent

One conversation of an account: its name, its latest message in full, and WhatsApp's unread, pinned, archived and muted state (a field that is missing is not known yet, which is not the same as false). A chat wuapi stored no message of answers not_found.

Inputs: chatId (required), accountId (required).

get_contactGet a contactA
Read-onlyIdempotent

One contact of an account's address book, by number or lid: id: its saved name, profile name, username and picture id as wuapi stored them. A number that is not saved on the phone answers not_found; lookup_contacts asks WhatsApp about any number.

Inputs: accountId (required), contactId (required).

get_current_keyWho am IA
Read-onlyIdempotent

The organization, API key (name and last 4 characters, never the key) and project this server acts as. Call it first when you are unsure whether the key is an organization key or a project key.

Inputs: no named parameters.

get_groupGet a groupB
Read-onlyIdempotent

A group's name, description, settings and participants with their roles (member, admin, owner).

Inputs: groupId (required), accountId (required).

get_incoming_webhookGet an incoming webhookA
Read-onlyIdempotent

One incoming webhook: its number, destination and whether it is enabled. Never its URL.

Inputs: incomingWebhookId (required).

get_invitationGet an invitationA
Read-onlyIdempotent

One invitation's status, and the linked accountId once completed.

Inputs: invitationId (required).

get_messageGet a messageA
Read-onlyIdempotent

One message with its status (queued, sent, delivered, read, failed, or received for inbound), content, and error when it failed. Received media is on demand by default (media.downloaded: false): pass fetchMedia: true to download it once and get a direct mediaFile.url that needs no API key.

Inputs: messageId (required), fetchMedia.

get_projectGet a projectA
Read-onlyIdempotent

One project: name, external id, status, account limit and count. Organization keys only.

Inputs: projectId (required).

get_usageGet this month's usageA
Read-onlyIdempotent

The current month's bill so far: billable numbers, proxy traffic, and the total in cents (USD). Organization keys only.

Inputs: no named parameters.

get_usage_by_projectGet usage per projectA
Read-onlyIdempotent

Numbers, proxy traffic and messages sent and received per project for a month, for rebilling your customers. With projectId, that project only. Organization keys only.

Inputs: month, projectId.

get_webhookGet a webhook endpointA
Read-onlyIdempotent

One webhook endpoint: its URL, events and whether it is active. Never its signing secret.

Inputs: webhookEndpointId (required).

leave_groupLeave a groupA
DestructiveIdempotent

Make the account leave a group. To come back it has to be added or invited again.

Inputs: confirm (required), groupId (required), accountId (required).

list_accountsList accountsA
Read-onlyIdempotent

List the linked WhatsApp numbers (accounts), newest first, with their status: ready can send; qr_ready waits for a QR scan; disconnected or failed need attention.

Inputs: limit, cursor, projectId.

list_chatsList chatsA
Read-onlyIdempotent

An account's conversations, the one with the newest message first: each chat's name, picture id, latest message and WhatsApp's unread, pinned, archived and muted state. Only chats wuapi stored a message of. A state field that is missing (unread, unreadCount, pinned, pinnedAt, archived, muted) is not known to wuapi yet, which is not the same as false. Filter by archived, unread or type, or search names, numbers and recent text with q. Read a conversation with list_messages and the chat's id as chatId.

Inputs: accountId (required), q, type, limit, +3 more.

list_contactsList contactsA
Read-onlyIdempotent

An account's address book as its phone synced it to wuapi, ordered by saved name: each contact's id, number, savedName, WhatsApp profile name, and the username and picture id seen so far. Only contacts the phone saved (or that have a business name); people the account just chatted with are in list_chats. Read from what wuapi stored, so about and deviceCount are not here: lookup_contacts asks WhatsApp for those. Search names, usernames and numbers with q.

Inputs: accountId (required), q, limit, cursor.

list_groupsList groupsA
Read-onlyIdempotent

Every group the account is in, read live from WhatsApp, with the participant count. A group inside a community has that community's id as communityId (absent when it is in none), and default: true when it is the community's announcement group. Use get_group for the participants.

Inputs: accountId (required), limit, cursor.

list_incoming_webhooksList incoming webhooksA
Read-onlyIdempotent

The incoming webhooks: secret URLs that send a WhatsApp message from one of your numbers to one fixed contact or group. Shows the name, the number, the destination and whether each is enabled. Never the URLs themselves.

Inputs: limit, cursor, projectId.

list_invitationsList invitationsB
Read-onlyIdempotent

Invitations and their status: pending, in_progress, completed (with the new accountId), failed, cancelled or expired.

Inputs: limit, cursor, status, projectId.

list_messagesList messagesA
Read-onlyIdempotent

Messages wuapi stored, newest first: sent and received. Filter by account, chat and direction to read a conversation. Use list_chats to see which conversations an account has.

Inputs: limit, chatId, cursor, accountId, +2 more.

list_projectsList projectsB
Read-onlyIdempotent

Projects: one per customer of a platform, each with its own numbers, keys, webhooks and usage. Organization keys only.

Inputs: limit, cursor, status, externalId.

list_proxy_locationsList proxy locationsA
Read-onlyIdempotent

Countries and cities a new number's proxy can exit from, for create_account and create_invitation. Search with q (sao finds Sao Paulo) or filter by country.

Inputs: q, limit, cursor, country.

list_webhooksList webhook endpointsA
Read-onlyIdempotent

The webhook endpoints that receive events: URL, events and whether active. Signing secrets are never shown here.

Inputs: limit, cursor, projectId.

lookup_contactsLook up contactsA
Read-onlyIdempotent

About text, picture id, WhatsApp username, business name and device count of 1 to 50 contacts, asked from WhatsApp (the saved names are in list_contacts). Usernames cannot be searched: WhatsApp does not let a linked device resolve an @username, so look contacts up by number or lid: id.

Inputs: accountId (required), contactIds (required).

lookup_whatsapp_infoLook up WhatsApp detailsA
Read-onlyIdempotent

Read details from WhatsApp through a linked number: a contact's profile picture or business profile, who a contact QR link or business message link points to, WhatsApp's AI bot directory, and the sticker pack or catalog order a message refers to. Nothing is changed.

Actions:

  • contact_picture: The contact's profile picture URL, when the account can see it.

  • business_profile: A business contact's address, email, categories, time zone and opening hours.

  • resolve_link: Who a contact QR link or business message link points to, and its prefilled text. Fails with not_supported when WhatsApp does not offer it to the account.

  • bots: WhatsApp's AI bot directory as the account sees it. Fails with not_supported where WhatsApp does not offer it.

  • sticker_pack: A sticker pack and its stickers.

  • order: The products, quantities and totals of a catalog order received as a message.

Inputs: action (required), code, kind, limit, +7 more.

manage_block_listBlock or unblock contactsA
DestructiveIdempotent

The account's block list on WhatsApp: list blocked contacts, block a contact (it can no longer message or call the account) or unblock it.

Actions:

  • list: Blocked contacts, with their number and lid: id when known.

  • block: Block a contact. Needs confirm: true.

  • unblock: Unblock a contact.

Inputs: action (required), limit, cursor, confirm, +2 more.

manage_brandingManage invitation brandingA
Idempotent

How the invitation page and email look to your customers: display name, logo, accent color, support link, and whether the "Powered by wuapi" footer shows. Organization keys only.

Actions:

  • get: The current branding.

  • update: Change any of the fields. Returns the branding.

Inputs: action (required), logoUrl, supportUrl, accentColor, +2 more.

manage_channelManage channelsA

WhatsApp channels (one-to-many broadcasts, ids end in @newsletter): list the ones the account follows or owns, read one and its posts, preview an invite, create a channel, follow, unfollow, mute and unmute, react to posts and count as a viewer. To post to a channel the account administers, use send_text or send_media with to set to the channel id.

Actions:

  • list: Channels the account follows or administers, with its role.

  • get: One channel: name, description, subscriber count, the account's role and whether it is muted.

  • preview_invite: The channel behind an invite code or link, without following it.

  • list_messages: The channel's recent posts, newest first, with view and reaction counts.

  • create: Create a channel with the account as owner. Returns it.

  • follow: Follow the channel.

  • unfollow: Stop following the channel.

  • mute: Mute the channel's notifications.

  • unmute: Unmute the channel.

  • react: React to a post with an emoji, or remove the reaction with an empty string.

  • mark_viewed: Count the account as a viewer of these posts.

Inputs: action (required), code, name, emoji, +9 more.

manage_communityManage communitiesA

WhatsApp communities: a community is a group with community: true that links other groups. Create one, list its groups and members, and link or unlink groups (the account must admin both). get_group reads the community itself; send to it like a group. To create a new group inside a community, use create_group with communityId; list_groups shows each group's communityId.

Actions:

  • create: Create a community with the account as owner. Returns it.

  • list_groups: The groups linked to the community, marking its default (announcement) group.

  • list_members: Members across the community's linked groups.

  • link_group: Link a group into the community.

  • unlink_group: Unlink a group from the community. The group itself stays.

Inputs: action (required), name, limit, cursor, +4 more.

manage_favorite_stickersManage favorite stickersA
Idempotent

The account's favorite stickers: the star tab of WhatsApp's sticker picker, which WhatsApp keeps in sync with the phone. List them, get one's file, favorite a sticker from a message or an uploaded WebP file, or remove one. Adding and removing change the list on the phone too.

Actions:

  • list: The favorites, newest first, from what wuapi stored (no call to WhatsApp). Each has media.url and media.downloaded; animated and emojis are null until its file was fetched.

  • get_file: A direct URL to one favorite's file that needs no API key. Fetches the file from WhatsApp the first time, which needs the account ready.

  • add: Favorite a sticker: pass messageId or uploadId, one of them. A sticker that is a favorite already is returned as is.

  • remove: Take a sticker out of the favorites. It can be favorited again.

Inputs: action (required), limit, cursor, uploadId, +4 more.

manage_group_joinsJoin groups and handle join requestsA

Joining groups: preview the group behind an invite link, join it, and, in a group that needs approval to join, list, approve or reject the pending requests (the account must be an admin).

Actions:

  • preview_invite: The group behind an invite code or link, without joining: name, description, size.

  • join: Join a group with an invite code or link. Returns the group id; a group that needs approval makes it a pending request instead.

  • list_requests: Pending requests to join the group.

  • approve_requests: Let these people in. Each result says whether it worked.

  • reject_requests: Turn these requests down. Each result says whether it worked.

Inputs: action (required), code, limit, cursor, +4 more.

manage_group_settingsChange a group's info and settingsA
DestructiveIdempotent

Change a group the account administers: its name, description and settings (who can send, who can edit the info, whether joining needs approval, who can add members), and its picture.

Actions:

  • update: Change any of name, description, announce, locked, joinApproval and memberAddMode. Returns the group.

  • set_picture: Set the group picture from an https URL or base64 JPEG. Returns the picture.

  • delete_picture: Remove the group picture. Needs confirm: true.

Inputs: action (required), name, locked, confirm, +8 more.

manage_labelsManage labelsA
DestructiveIdempotent

WhatsApp Business labels on chats and messages: create or edit a label, delete it, and add it to or remove it from a chat or a message. WhatsApp Business accounts only; others answer not_supported. There is no endpoint that lists labels: they arrive in label.updated webhook events, and upsert creates one under an id you choose.

Actions:

  • upsert: Create the label with this id, or rename or recolor it. Returns the label.

  • delete: Delete the label. Needs confirm: true.

  • label_chat: Add the label to a chat.

  • unlabel_chat: Remove the label from a chat.

  • label_message: Add the label to a message, as the account that sent or received it.

  • unlabel_message: Remove the label from a message.

Inputs: action (required), name, color, chatId, +4 more.

manage_privacyManage privacy settingsA
Idempotent

The account's WhatsApp privacy settings: who sees its last seen, profile picture, stories and online status, who may add it to groups or call it, and whether it sends read receipts.

Actions:

  • get: Every privacy setting.

  • get_story_privacy: Who sees the account's stories: its contacts, all but some, or only some.

  • update: Change one or more settings. Each setting is one change on WhatsApp. Returns every setting.

Inputs: action (required), online, callAdd, profile, +6 more.

manage_profileManage the account's profileA
Destructive

The linked number's own WhatsApp profile: its display name and About text, its profile picture, and its contact QR link (a https://wa.me/qr/... link that opens a chat with it).

Actions:

  • update: Change the display name, the About text, or both.

  • set_picture: Set the profile picture from an https URL or base64 JPEG. Returns the picture.

  • delete_picture: Remove the profile picture. Needs confirm: true.

  • get_contact_link: The account's contact QR link.

  • reset_contact_link: Revoke the contact QR link and return a new one. The old link stops working. Needs confirm: true.

Inputs: action (required), name, about, confirm, +3 more.

manage_projectUpdate, delete or audit a projectA
DestructiveIdempotent

Change a project (rename it, set its external id, metadata or account limit, suspend or resume it), delete it, and list or revoke its API keys. Suspending refuses every send and write in the project while reads and inbound messages keep working. Organization keys only. New project keys are created in the wuapi dashboard: no tool returns an API key.

Actions:

  • update: Change any of name, externalId, metadata, maxAccounts and status. Returns the project.

  • delete: Delete the project: its keys stop working at once, and its numbers are logged out and deleted in the background with its webhook endpoints. Needs confirm: true.

  • list_keys: The project's API keys, revoked ones included: name, last 4 characters, last use. Never the key itself.

  • revoke_key: Revoke one of the project's API keys. It stops working at once. Needs confirm: true.

Inputs: action (required), name, limit, cursor, +7 more.

manage_storiesRead and answer storiesA
Destructive

Stories (WhatsApp Status): read the ones the account's contacts posted in the last 24 hours, mark one as viewed, react or reply to it, and see or delete the ones the account posted (post with post_story). Reading stories tells the contact nothing; view does, so call it only when the user wants the contact to know. Contacts' stories arrive only for accounts with stories turned on.

Actions:

  • list: Contacts' stories, grouped by contact, the contact with the newest story first.

  • list_own: The stories the account posted in the last 24 hours, with how many contacts saw each.

  • get: One story. With fetchMedia, also its file's direct URL.

  • viewers: Who saw a story the account posted, with their reactions, the latest viewer first.

  • view: Tell the contact the account saw their story: the account then shows in the story's viewers. Only when the user asked for it. authorNotified: false in the answer means WhatsApp did not tell them (read receipts are off).

  • react: React to a contact's story with an emoji, or remove the reaction with an empty string. Only the story's author sees it.

  • reply: Reply to a contact's story with text: a message in the chat with its author, who sees it as a reply to their story.

  • delete: Delete a story the account posted, for everyone. Needs confirm: true.

Inputs: action (required), text, emoji, limit, +8 more.

mark_chat_readMark a chat read or unreadA
Idempotent

Clear (or set, with unread: true) the chat's unread badge on the linked devices. Sends no read receipts; use send_read_receipts for blue ticks.

Inputs: chatId (required), accountId (required), unread.

mute_chatMute or unmute a chatA
Idempotent

Mute a chat's notifications for a while or until unmuted, or unmute it with muted: false.

Inputs: chatId (required), accountId (required), muted, durationSeconds.

pin_chatPin or unpin a chatA
Idempotent

Pin a chat to the top on the linked devices, or unpin it with pinned: false.

Inputs: chatId (required), accountId (required), pinned.

post_storyPost a storyA

Post a story from the account: text on a colored background, or an image or video with an optional caption, from a public URL (mediaUrl) or a file uploaded with upload_file (uploadId).

Inputs: accountId (required), text, type, mediaUrl, +3 more.

promote_group_participantsMake participants adminsB
Idempotent

Make participants admins of a group the account administers.

Inputs: groupId (required), accountId (required), contactIds (required).

react_to_messageReact to a messageA
Idempotent

React to a message with an emoji, as the account that received or sent it. An empty string removes the reaction.

Inputs: emoji (required), messageId (required).

reconnect_accountReconnect an accountA
Idempotent

Restart the account's session. Use it when an account is disconnected; when the link is no longer valid it produces a fresh QR code.

Inputs: accountId (required).

reject_callReject an incoming callA

Reject a WhatsApp call ringing on the account, with the id and from of its call.received webhook event. To reject every call automatically, set rejectCalls with update_account.

Inputs: from (required), callId (required), accountId (required), idempotencyKey.

remove_group_participantsRemove people from a groupA
DestructiveIdempotent

Remove participants from a group the account administers.

Inputs: confirm (required), groupId (required), accountId (required), contactIds (required).

reply_to_messageReply to a messageA

Reply with text to a message, quoting it, in the same chat and from the same account. Works for messages in direct chats and groups.

Inputs: text (required), messageId (required), idempotencyKey.

request_pairing_codeGet a pairing codeA

Link by phone number instead of QR code: returns an 8-character code the owner types in WhatsApp. It lives about 160 seconds. Fails with already_linked when the account is ready.

Inputs: phone (required), accountId (required).

resend_invitationResend an invitationA
Destructive

Give an invitation a new link and expiry and email it again when it has an inviteeEmail. The previous url stops working; send the new one from the result. An account the invitee already started is kept, so they resume where they left off.

Inputs: confirm (required), invitationId (required), idempotencyKey.

save_contactsSave contacts on the phoneA
Idempotent

Save contacts on the linked phone, in WhatsApp and in the phone's own address book, as if they were saved on the phone. Any number can be saved. Saves are queued (also while the account reconnects): each contact's phoneSync says pending, then synced or failed (not_on_whatsapp, account_offline), and contact.updated fires; the phone shows the name about a minute later. Removing a contact is not supported. backfill_auto_save queues the contacts of the account's existing direct chats, named with its auto-save templates (update_account contactAutoSave), at most 200 a day.

Actions:

  • one: Save one contact under savedName. Returns the contact with its phoneSync.

  • many: Save up to 500 contacts at once. Returns the batch id and each contact's status.

  • backfill_auto_save: Queue the auto-save of the contacts of the account's existing direct chats.

Inputs: action (required), contacts, accountId, contactId, +2 more.

send_buttonsSend buttonsA

Send a message with 1 to 10 tappable buttons. A quick reply (id) answers as a message.received of type button with button.id; a link (url, HTTPS) opens when tapped. WhatsApp disables a quick reply in the sender's own view of the message; recipients can tap it. The body is text, with an optional footer.

Inputs: to (required), text (required), buttons (required), accountId (required), +4 more.

send_contactSend contact cardsC

Send one contact card, or up to 20 in one message.

Inputs: to (required), contacts (required), accountId (required), mentions, +2 more.

send_locationSend a locationC

Send a map pin, with an optional place name and address.

Inputs: to (required), latitude (required), accountId (required), longitude (required), +5 more.

send_mediaSend an image, video, audio or documentA

Send a file: an image, video, audio, voice note (ogg/opus), document or sticker, with an optional caption. Give exactly one of url (a public URL wuapi downloads itself) or uploadId (a file uploaded before with upload_file). Images go out at the account's image quality (standard by default, as WhatsApp sends a photo); pass quality to change it for one image, or send the file as a document to deliver it untouched.

Inputs: to (required), type (required), accountId (required), url, +9 more.

send_pollSend a pollA

Send a poll with 2 to 12 options. Votes arrive as poll.voted webhooks and in the message's poll tally (get_message).

Inputs: to (required), options (required), question (required), accountId (required), +4 more.

send_read_receiptsSend read receiptsA
Idempotent

Send read receipts (blue ticks) for inbound messages in a chat: the given ids, or every unread inbound message wuapi stores for it.

Inputs: chatId (required), accountId (required), messageIds.

send_textSend a text messageA

Send a text message from a linked number to a contact, group or channel. The message is queued and sent at the account's pace; the result has its id and queued status. Send only to people who expect it.

Inputs: to (required), text (required), accountId (required), mentions, +2 more.

set_disappearing_timerSet disappearing messagesA
Idempotent

Turn disappearing messages on or off: for one chat with chatId, or without it the account's default timer, which new chats start with. Messages already stored in wuapi are kept.

Inputs: accountId (required), durationSeconds (required), chatId.

set_presenceSet presence or typingA
Idempotent

Presence as contacts see it: the account online or offline, typing or recording in a chat, and presence events from a contact. Typing shows until paused or the next message. With typing turned on in the account's pacing (update_account), sends show it on their own.

Actions:

  • online: Show the account as online to contacts.

  • offline: Show the account as offline.

  • typing: Show typing in a chat.

  • recording: Show recording audio in a chat.

  • paused: Clear the typing or recording indicator in a chat.

  • subscribe: Receive contact.presence_updated webhook events when the contact comes online, goes offline or types. Fails with not_supported when the account cannot receive presence events.

Inputs: action (required), chatId, accountId, contactId.

star_messageStar or unstar a messageA
Idempotent

Star a message on the phone and the other linked devices, or unstar it with starred: false. Returns the message.

Inputs: messageId (required), starred.

update_accountUpdate an accountA
Idempotent

Change an account's settings: rename it, reject incoming calls automatically, turn on and tune its pacing (the anti-ban protections, off by default), choose whether the next link imports recent chats, choose which received media is downloaded right away (the rest on demand), choose the quality its images are sent at, save the contacts of new chats on the phone automatically (contactAutoSave), or move its proxy location. Pacing applies from the next send. A proxy location change gives the number a new exit IP and reconnects it; it is refused within 10 minutes of the previous change. Returns the updated account with its pacing.

Inputs: accountId (required), name, pacing, historySync, +6 more.

update_incoming_webhookUpdate an incoming webhookA
Idempotent

Rename an incoming webhook, or pause it (enabled: false) and resume it. The destination cannot change: create another one.

Inputs: incomingWebhookId (required), name, enabled.

update_webhookUpdate a webhook endpointA
Idempotent

Change a webhook endpoint's URL or events, or pause it (active: false) and resume it.

Inputs: webhookEndpointId (required), url, active, events.

upload_fileUpload a file to sendA

Upload a file whose bytes you have (not a URL) so it can be sent: returns an upload whose id goes in uploadId of send_media or post_story. The file can be sent for 24 hours, to any number of chats. Up to 5 MB; the hosted server takes requests up to 1 MB, so about 700 KB of file there. For a file that is already at a public URL, skip this and pass the URL to send_media.

Inputs: base64 (required), mimeType (required), filename, idempotencyKey.

vote_in_pollVote in a pollA
Idempotent

Vote in a poll message as the account that received or sent it, with the names of its options (get_message shows them). An empty list retracts the vote. Returns the poll with its tally.

Inputs: options (required), messageId (required), idempotencyKey.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

    TDQS

    A3.6/5.0

    Scored across 87 tools

    Disambiguation4/5

    The tools mostly target clearly distinct resources and actions, and the rich descriptions clarify overlaps like list_messages vs manage_channel.list_messages or get_contact vs lookup_contacts. A few umbrella tools (manage_labels, manage_channel, manage_stories) and similarly named contact/chat tools could still require careful reading, but genuine misselection is limited.

    Naming Consistency5/5

    Names consistently use snake_case and mostly follow a verb_noun pattern (send_text, get_chat, create_group, manage_channel). The repeated manage_* convention for multi-action resources is predictable, and there are no style collisions such as camelCase or vague single-word tools.

    Tool Count2/5

    Eighty-seven tools is very large even for a broad WhatsApp API surface, and many tools bundle multiple actions internally, making the external surface unusually heavy. The domain is extensive, but the set would benefit from consolidation or clearer grouping.

    Completeness5/5

    Coverage is exceptionally broad: accounts, messaging, media, chats, contacts, groups, communities, channels, stories, labels, privacy, webhooks, projects, invitations, billing, and more. The tool surface handles lifecycle operations and edge cases with few obvious dead ends.

    Maintenance

    ActivityActive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers