wazap-mcp
wazap-mcp gives an AI assistant 20 tools to read your own WhatsApp account locally — chats, messages, media, contacts, groups — and to draft (then explicitly confirm) replies, all stored on your machine.
Learn & diagnose —
learn(tool guide),get_status(connection, sync, accounts, versions),link_account(pair via 8-character code).Read chats & messages —
list_chats(all/unread/groups/individual/archived),read_messages(paging back, plus stories viachat_id: "status"),get_message(quotes, reactions, poll votes, receipts).Catch up —
catch_upreturns what you missed across accounts within a token budget: waiting asks, mentions, calls, groups, stories.Find things —
searchby meaning and words with date/sender/chat filters;find_contactresolves names, nicknames, relationships, tags;get_group_infofor participants, admins and settings.Media & voice —
get_mediareturns transcripts of voice notes, attaches photos, or saves files to disk;wait_for_messagesblocks up to 55 s for new messages with a cursor.Local memory —
rememberstores notes, tags and fields about people on your machine, including#privateand#no-catchuptags; nothing touches WhatsApp.Send safely —
send_messageonly drafts (text, media, polls, locations, forwards) andconfirm_sendsends once after your explicit yes; nothing leaves without approval.Modify messages —
edit_message(15-minute window),react_to_message,delete_message(for everyone or locally).Manage chats & groups —
manage_chat(archive, pin, mute, mark read, star, clear, delete, block) andmanage_group(create, join, rename, add/remove/promote members, invite links, join requests, settings, leave).Privacy controls — read-only mode (
WAZAP_READ_ONLY=1) unregisters write tools entirely; send allow/deny lists; writes rate-limited to 20/min; all data in~/.wazapwith no telemetry or third-party account.
Provides tools for interacting with a linked WhatsApp account, enabling management of chats, messages, media, contacts, and groups, including sending messages, searching history, downloading media, and administering group settings.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@wazap-mcpwhat did I miss on WhatsApp today?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
██╗ ██╗ █████╗ ███████╗ █████╗ ██████╗
██║ ██║██╔══██╗╚══███╔╝██╔══██╗██╔══██╗
██║ █╗ ██║███████║ ███╔╝ ███████║██████╔╝
██║███╗██║██╔══██║ ███╔╝ ██╔══██║██╔═══╝
╚███╔███╔╝██║ ██║███████╗██║ ██║██║
╚══╝╚══╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═╝WhatsApp for your AI assistant. wazap is an MCP server that puts your own WhatsApp account — chats, messages, media, contacts, groups — behind 20 tools any MCP client can call, so Claude, ChatGPT, Gemini, Cursor or Codex can read your inbox and draft your replies.
What it does
It links your account as a linked device, the way WhatsApp Web does, and keeps what it sees on this machine. Then you talk to your assistant instead of to a tool:
"What did I miss on WhatsApp today?" — one answer across every linked account: who is waiting on a reply, mentions, missed calls, groups condensed.
"Find the invoice Dan sent in spring." — search by meaning and by words at once, then open the file.
"What did the voice note from mama say?" — voice messages come back as text.
"Tell Ana I'll be twenty minutes late." — the assistant shows you the recipient and the exact words, and nothing leaves until you say yes.
Built on Baileys, which speaks the WhatsApp multi-device protocol over a WebSocket. No browser, no phone-number reseller, no account with us — there is no us: wazap runs on your machine.
Related MCP server: wa-bridge
Get started
The npm package is wazap-mcp; the command it installs is wazap.
npx wazap-mcp setupThat is the whole install. It links your account, finds the MCP clients installed on this machine, writes their config, copies the five skills where that client reads them, and tells you what to restart.
Or have your agent do it. Paste this:
Set up WhatsApp for me: run npx wazap-mcp setup --agent and follow what it prints.
Then ask your assistant: "what did I miss on WhatsApp today?"
Or the path your harness prefers
Harness | Fastest path |
Claude Code |
|
Claude Desktop | download |
Gemini CLI |
|
Cursor | the Install in Cursor badge, then |
Codex CLI |
|
A hosted agent (claude.ai, ChatGPT) | a URL it signs in to: Keep it running |
Anything else | the MCP entry |

Each local harness registers the server; a hosted agent gets a URL. Linking
the WhatsApp account is a separate, one-time step: npx wazap-mcp login, which
shows a QR code to scan from Settings → Linked devices → Link a device, or
prints an 8-character code with --phone +15550100.
npx wazap-mcp on its own is safe to run: it prints where you stand and what
to do next, and starts no server. When something is off, npx wazap-mcp status
is the first thing to run — and it is what tells you if the Node you have is
too old: wazap needs 22.16 or newer on the 22 line, or 24.
Every step setup takes, every client it can write, the background service and
the upgrade command are in docs/install.md.
The 20 tools
Each one in a line. What every argument means, the workflows behind them and
every error code are in docs/tools.md; the assistant
itself gets all of it by calling learn first.
Tool | Kind | What it does |
| read | The guide to every tool, id format and error code. Call it first. |
| read | Connection, sync, linked accounts, how fresh the history is, webhook delivery, versions. |
| read | Pair an account from the assistant; returns the 8-character code to type into the phone. |
| read | Conversations newest-first: |
| read | Messages in a chat, paging back into the phone's history; |
| read | "What did I miss?" across every account, in one call and within a token budget. |
| read | Messages by meaning and by words at once, narrowed by chat, sender or date. |
| read | One message in full: its quote, each reaction with who left it, poll votes, delivery and read receipts. |
| read | Who "mama", a nickname, a group name or a number means, before anything is drafted. |
| read | Participants, admins, who may post or edit, join requests, invite link. |
| read | A message's media: a voice note as its transcript, a photo as an image, any file saved to disk. |
| read | Block up to 55 s until a message arrives, then return it with a cursor for the next call. |
| local | Keep a note, tags and details about a person, on this machine only. Nothing changes on WhatsApp. |
| write | Draft a message, media, poll, location or forward — and send nothing. |
| write | Send that draft, once, after the user has seen the preview and said yes. |
| write | Edit your own message, within WhatsApp's 15-minute window. |
| write | Add or remove an emoji reaction. |
| write | Retract your own message for everyone, or delete any message for this account only. |
| write | Archive, pin, mute, mark read or unread, star, clear, delete, block. |
| write | Create, join, rename, add, remove, promote, invite links, join requests, settings. |
Voice messages become text when you switch transcription on
(docs/voice.md), and search matches meaning as well as words
when you switch semantic recall on (docs/recall.md). Both are
off by default and both can run entirely on this machine.
Security and privacy
Nothing is sent without your yes.
send_messageonly drafts: it returns the recipient and the exact text and touches no network. Onlyconfirm_sendsends, and a draft goes out at most once, even across a crash. Draft-then- confirm is a workflow, not independent proof of consent: an agent can call both tools unless the harness makes you approve the second one.Read-only is a real switch. With
WAZAP_READ_ONLY=1, orwazap config writes off, the write tools are not registered at all — the assistant never sees them, so it cannot message anyone from your number even by mistake. The Claude Desktop bundle ships read-only ticked.Who an account may message can be pinned to a list:
wazap config send allow +15550100,…, ordenyfor the reverse. The rules are checked when a message is drafted and again when it is confirmed (docs/send-rules.md).Writes are rate limited to 20 a minute per account, because sending faster than a human is how accounts get banned.
The data stays here. Credentials, messages, media and notes live in
~/.wazap,0700, with credentials0600. There is no wazap account, no server of ours and no telemetry. What does leave the machine: WhatsApp itself; the npm registry, for the version check; Hugging Face, when you ask for a transcription or embedding model; the transcription API, only if you chose theopenaiprovider instead of the local one; and your own webhook URL, if you configured one (docs/data.md).Some people can be kept out of it. Tag someone
#privateand their words stay out of everything the assistant did not ask about them by name; tag them#no-catchupand their chat is skipped entirely.What it does not do. There is no bulk send, no scheduler and no campaign tool. It never marks anything read on WhatsApp on its own. Text it sends goes out without a link preview, and nothing — not wazap, not Baileys — fetches the page.
Findings, threat model and the limits of each of these are in docs/security-audit.md.
Known limitations
The protocol is unofficial. wazap talks to WhatsApp through Baileys, a reverse-engineered implementation of the WhatsApp multi-device protocol. This is not the WhatsApp Business API, Meta does not support it, and WhatsApp can change the protocol without warning — a change can break wazap until Baileys catches up. An account that sends in bulk, or sends to people who did not ask to hear from it, can be restricted or banned, and that is not recoverable from here. What wazap does about it is the whole of the section above: sends are drafted and confirmed one at a time, writes are capped at 20 a minute per account, an account can be locked to a list of recipients or to reading only, and there is no bulk or scheduled send to reach for. None of that is a guarantee, and the risk is yours.
How a model behaves with the tools is measured on Claude only. The evaluation of how an assistant uses them (
eval/: 58 cases, each run three times, with the sends that must never happen counted apart) has been run on Claude. ChatGPT, Gemini, Cursor and Codex connect and get the same 20 tools, but nobody has measured them yet, so what the section above promises is the server's doing, not the model's. The manual protocol for ChatGPT iseval/chatgpt-protocol.md.Media keys expire. WhatsApp drops old attachments from its servers, so
get_mediaon an old message returnsMEDIA_UNAVAILABLE.History is what the phone syncs. wazap sees the history WhatsApp hands the linked device, not your full phone archive.
read_messageswithbeforeasks for more, within whatever WhatsApp still keeps.@lidids. Newer accounts are addressed by a privacy id rather than a phone number. wazap translates them back to phone numbers when it has learned the mapping, and passes the@lidthrough when it has not.Names come from the phone's address book. WhatsApp delivers it as an app state sync, and only to a connection asking for it from scratch. If contacts read as phone numbers and
get_statusshowscontacts_named: 0,find_contactasks for it once, andwazap contacts resyncasks again while no server runs.Calls are WhatsApp calls only. A call shows up as a message with
type: "call", carrying its kind, direction, outcome and duration. WhatsApp's own call log and the missed-call notices arrive on their own; a call that starts and ends while wazap is running is recorded live, so calls placed or received while it is stopped can be missing entirely. A cellular call from the phone's dialler is never visible, on any device.Your phone must stay reachable. A linked device stops receiving once the phone has been offline long enough;
get_statussays so inhint.
What 1.0 guarantees — which names, shapes and settings are promised not to move, and which are not — is in docs/stability.md.
Documentation
Every step of | |
The 20 tools in full: catching up, finding people, sending once, keeping someone private, and every error code | |
Voice messages as text: whisper.cpp here, or an OpenAI-compatible API | |
Semantic recall: | |
The data directory, the account database, | |
Several WhatsApp accounts in one wazap, and several MCP clients on one server | |
Read-only mode, per-account send rules, link previews and media processing | |
HTTP mode, systemd, Docker, tunnels, reverse-proxy trust and the OAuth server hosted agents sign in to | |
Building a product on wazap: static bearer tokens in, signed webhook events out | |
Every | |
The audit report | |
What changed, release by release |
Development
npm install
npm run typecheck
npm test # builds, then runs node --test
node test/smoke-stdio.mjs # drives the built binary over MCP stdio
npm run dev -- status # run from source with tsxnpm test needs no WhatsApp session. The stdio smoke test spawns the built
binary against a throwaway data directory and checks that an unlinked install
still answers initialize, tools/list and get_status.
AGENTS.md is the contributor's map: the layout, the rules that must never break, the release procedure and the knobs only tests use. Issues and pull requests go to github.com/razvangirgiz/wazap.
MIT licensed.
Available Tools
20 toolscatch_upCatch up on what the user missedARead-only
What the user missed, all accounts, within budget_tokens: waiting (every open ask of 14 days, whatever the window), mentions, calls, people, groups, stories. account_id narrows it to one account; get_status names them. The mark moves first; a lost answer is since: "previous". more.cursor: the rest.
| Name | Required | Description | Default |
|---|---|---|---|
| hours | No | The last N hours instead; never moves the mark | |
| since | No | "last" (default); "previous" repeats that catch-up; or an ISO date or time from the last 14 days | |
| cursor | No | more.cursor | |
| include | No | Only these sections; the mark then stays | |
| account_id | No | Account id | |
| budget_tokens | No | Answer length in tokens |
Output Schema
| Name | Required | Description |
|---|---|---|
| more | Yes | Set when entries are left: call catch_up again with more.cursor |
| notes | No | Caveats to act on or tell the user |
| direct | Yes | |
| footer | Yes | On the last page: what the entries leave out |
| groups | Yes | |
| window | Yes | |
| stories | Yes | |
| waiting | Yes | |
| accounts | Yes | |
| addressed | Yes | |
| account_id | Yes | |
| missed_calls | Yes | |
| approx_tokens | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description explains the non-idempotent behavior of moving the mark and the consequence of losing an answer (use since:'previous'), which goes beyond annotations. It also clarifies budget_tokens and cursor usage. Annotations (readOnlyHint true, destructiveHint false) are consistent, and the description adds meaningful behavioral detail without contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single run-on sentence with heavy jargon ('the mark moves first', 'a lost answer is since: previous'). It is concise in length but not well-structured or front-loaded; the core purpose is somewhat buried. The cryptic phrasing reduces readability despite the compact size.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with six optional parameters and non-trivial behavior (mark movement, pagination, token budget), the description covers the essential operational details: sections, account narrowing, cursor handling, and the token limit. The output schema exists to handle return values. It lacks error handling or edge cases, but overall it is sufficiently complete for an advanced tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Despite 100% schema description coverage, the description enriches parameter understanding: it explains 'since' options, the mark movement, and the meaning of 'more.cursor'. It also lists the sections returned, which aligns with the include parameter even though terminology differs slightly (e.g., 'mentions' vs 'addressed'). This adds value beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a clear purpose: fetching what the user missed across all accounts, listing sections like waiting, mentions, calls, people, groups, stories. It distinguishes from siblings by focusing on aggregated missed content, though it does not explicitly name alternatives. The title reinforces this, so it is not a tautology.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives some usage context, such as using account_id to narrow to one account and mentioning get_status for names, plus the mark movement behavior and cursor pagination. However, it does not explicitly state when to use this tool versus alternatives, nor does it provide exclusions or prerequisites. The guidance is implicit rather than direct.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
confirm_sendSend a drafted WhatsApp messageAIdempotent
Send a draft the user approved — this text, this recipient: the only call that sends, once per draft. A yes about something else: show the preview again and ask. Expired, missing or stale: draft again, show the new preview, ask again. SEND_OUTCOME_UNKNOWN: read_messages, never redo it unasked.
| Name | Required | Description | Default |
|---|---|---|---|
| draft_id | Yes | From send_message | |
| account_id | No | Account id |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate readOnlyHint=false, idempotentHint=true, and openWorldHint=true. The description adds valuable behavioral context beyond annotations: it clarifies the idempotency as 'once per draft,' specifies handling for stale/missing drafts, and warns 'never redo it unasked.' It also states that this is the only sending call, which is not present in annotations. No contradictions with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded: the first sentence states the core action and its exclusive nature, followed by three terse edge-case rules. Every sentence earns its place, with no filler or repetition. The structure is scannable and highly efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has no output schema, so the description must cover behavior. It addresses the main action, when not to use, and fallback actions for exceptional cases. It does not state what the tool returns on success (e.g., a message ID), but that is often implied and not critical for correct invocation. Given the edge-case richness, the description is nearly complete for an agent to decide and call it appropriately.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%: draft_id is described as 'From send_message' and account_id as 'Account id.' The description itself does not add further parameter details, but it does imply the draft carries text and recipient, which relates to draft_id. With full schema coverage, a baseline of 3 is appropriate; the description doesn't need to compensate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Send a draft the user approved' with the exact scope 'this text, this recipient.' It explicitly distinguishes from siblings by calling itself 'the only call that sends, once per draft,' which separates it from send_message and other drafting tools. The purpose is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear when-to-use guidance: only for an approved draft, and provides explicit when-not-to-use conditions: 'A yes about something else' or 'Expired, missing or stale' should trigger preview re-shows instead of sending. It also names a fallback for unknown outcomes ('read_messages'). While it doesn't enumerate all sibling tools, it gives concrete decision rules that route the agent correctly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_messageDelete a WhatsApp messageADestructiveIdempotent
Delete a message; confirm with the user first. for_everyone: true retracts it for everyone within 2 days: the account's own message, or anyone's in a group where it is admin. for_everyone: false removes any message from the linked account's devices only.
| Name | Required | Description | Default |
|---|---|---|---|
| account_id | No | Account id | |
| message_id | Yes | ||
| for_everyone | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| account_id | Yes | |
| message_id | Yes | |
| for_everyone | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructive behavior, but the description adds meaningful context: the 2-day retraction window, the admin-permission condition for group messages, and that for_everyone:false only affects the linked account's devices. This goes well beyond the structured hints and helps set expectations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three clauses with no filler; the mandatory user-confirmation is front-loaded, and the for_everyone branch is expressed compactly. Every sentence adds distinct value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With a rich behavioral description and an output schema present, the core invocation requirements are covered. The main remaining gap is that account_id's role is never explained, and there's no explicit statement of what happens if it is omitted. Still, for a destructive tool with strong annotations, this is close to complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description thoroughly explains for_everyone behavior, which the schema leaves undocumented, and indirectly clarifies message scope as 'the account's own message' or 'anyone's in a group.' However, account_id and message_id receive no real semantic help beyond the schema's minimal 'Account id' and name/minLength, so the compensation is incomplete.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb and resource ('Delete a message') and immediately clarifies the operation's scope via the for_everyone flag. The local-vs-everyone distinction separates it from siblings like edit_message and send_message even though those aren't named.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly instructs the agent to confirm with the user first, which is a clear prerequisite before invoking. It also states when for_everyone is valid (true within 2 days, own message or admin in group) versus local-only removal (false), giving condition-based guidance. It doesn't explicitly name alternative tools, but it defines the choice space.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
edit_messageEdit a WhatsApp message you sentADestructiveIdempotent
Replace the text of a message the linked account sent. WhatsApp allows it for 15 minutes after sending; later, send a correction instead.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | ||
| account_id | No | Account id | |
| message_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| text | Yes | |
| chat_id | Yes | |
| timestamp | Yes | |
| account_id | Yes | |
| message_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already signal destructiveHint=true and readOnly=false, so the description's 'replace' is consistent and not a contradiction. It adds the platform constraint of 15 minutes, but does not disclose behavioral details such as whether recipients see an edited indicator or what happens on failure. With annotations carrying the safety profile, the description contributes only moderate additional transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with no filler. The core purpose is front-loaded, and the time-limit/fallback guidance is contained in a single follow-up sentence.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the simple mutation scope, existing output schema, and annotations, the description covers the essential operational constraint (15-minute window), the ownership constraint (linked account), and the fallback path. It does not detail error semantics, but the schema and annotations fill most of the remaining context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 33%, and the description gives only implicit semantics: 'text' maps to the replacement content, 'message' to message_id, and 'linked account' to the account context. It adds some meaning beyond the schema, but does not explicitly define the relationship of account_id or the expected format of message_id.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific operation: replace the text of an existing message sent by the linked account. This clearly distinguishes it from siblings like send_message and delete_message, and the phrasing 'linked account sent' narrows the target.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states the 15-minute edit window and instructs to send a correction instead afterward. This gives a clear when-to-use and when-not-to-use condition, though it does not explicitly name the sibling tool (e.g., send_message) or list other exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
find_contactFind who the user meansARead-onlyIdempotent
Who a name, nickname, relationship ("mama"), group, number or id means, before drafting. resolved: contact.chat_id, with number, note, tags, details and, in a write session, context. ambiguous or not_found: ask the user; never send to a guess. A name on several accounts: see fix. tag: its people.
| Name | Required | Description | Default |
|---|---|---|---|
| tag | No | List everyone filed under this tag instead | |
| kind | No | any | |
| name | No | What the user calls them ("Ana", "mamei", "fotbal"), or a number or id | |
| limit | No | Ambiguous: at most 5 per account; a tag list: up to 50 | |
| qualifier | No | Tells two apart: "contabilitate", a group, the last 4 digits | |
| account_id | No | Account id | |
| include_context | No | Recent messages and the user's style, when resolved in a write session |
Output Schema
| Name | Required | Description |
|---|---|---|
| fix | No | What to do next, when not resolved |
| next | No | Resolved: how a message to them starts |
| notes | No | Caveats to act on or tell the user |
| query | Yes | |
| status | Yes | |
| closest | No | Only when not_found |
| contact | No | Only when resolved |
| context | No | Only when resolved, in a session that can write: what a draft to them is written after |
| omitted | No | Only when listed and cut by limit: how many more on each account |
| contacts | No | Only when listed: everyone filed under the tag |
| can_draft | No | Resolved in a session that cannot send |
| account_id | No | The account that answered; null when several accounts were searched and none answered alone |
| candidates | No | Only when ambiguous; best first |
| accounts_searched | No | |
| accounts_unavailable | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already supply readOnly/idempotent/non-destructive hints, and the description adds genuinely useful behavior: resolved results include chat_id plus notes/tags/details/context, ambiguity triggers a user question rather than a guessed send, tag mode returns people, and multi-account conflicts are flagged. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact, information-dense, and front-loaded with the core purpose. The telegraphic fragments and the unclear 'see fix' reference slightly hurt readability, but no sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-parameter lookup tool, the description covers the main usage flow, disambiguation behavior, tag mode, and write-session context, and an output schema exists so return values need not be spelled out. The only real gap is that the 'fix' handling for same-name-on-several-accounts is referenced but not defined.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is high (86%) and each parameter already has a meaningful description, so the main description does not need to re-document them. It adds some outcome context (what resolved means, tag mode, ambiguity limits), but not significant per-parameter meaning beyond the schema, earning the baseline 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action: resolve what a name, nickname, relationship, group, number, or ID refers to before drafting, and names the resolved output (contact.chat_id). This clearly separates contact resolution from sibling messaging/chat tools such as send_message or list_chats.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit usage timing ('before drafting') and a firm rule for ambiguous/not_found results: ask the user and never send to a guess. It does not explicitly name sibling alternatives such as search or list_chats, and the 'see fix' reference is not self-contained, so the alternative-selection guidance is slightly incomplete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_group_infoGet WhatsApp group infoARead-onlyIdempotent
A group's name, description, owner and participants (up to 500), whether the account is admin, its settings (info_locked, member_add_mode, join_approval, disappearing_seconds), its community, and the invite link for an admin. Call it before manage_group.
| Name | Required | Description | Default |
|---|---|---|---|
| group_id | Yes | <id>@g.us | |
| account_id | No | Account id |
Output Schema
| Name | Required | Description |
|---|---|---|
| name | Yes | |
| owner | Yes | |
| chat_id | Yes | |
| community | No | |
| account_id | Yes | |
| created_at | Yes | |
| i_am_admin | Yes | |
| description | Yes | |
| info_locked | Yes | |
| invite_link | No | |
| participants | Yes | |
| join_approval | Yes | |
| member_add_mode | Yes | |
| announcement_only | Yes | |
| participant_count | Yes | |
| disappearing_seconds | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds value by specifying the conditional nature of the invite link ('for an admin') and the participant limit (up to 500), which are behavioral details not captured in annotations. It does not contradict annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence that front-loads the key data returned, then appends a usage instruction. Every phrase earns its place, with no filler. It is concise yet complete.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the output schema exists and annotations cover read-only/idempotent behavior, the description covers what the tool returns, when to use it, and a sequencing note. Nothing essential is missing for an agent to correctly invoke this tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema description coverage is 100%, with both group_id and account_id documented. The description does not add extra meaning beyond the schema—it mentions group info but not parameter-specific syntax or constraints. With full schema coverage, the baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('get') and resource ('group info'), then enumerates the exact fields returned (name, description, owner, participants, admin status, settings, community, invite link). It clearly distinguishes itself from sibling tools like manage_group and get_status by listing what it retrieves and by the explicit 'Call it before manage_group' directive.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says 'Call it before manage_group,' giving a clear precondition and usage context. This directly tells an agent when to invoke this tool versus alternatives, leaving no ambiguity about sequencing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_mediaGet the media of a WhatsApp messageBRead-only
What a message's media holds: a voice note or audio as its transcript (kept once made; an API provider bills it), or with save_to its file; a photo attached as an image; any file saved at path on the machine running wazap. MEDIA_UNAVAILABLE: WhatsApp no longer has it.
| Name | Required | Description | Default |
|---|---|---|---|
| save_to | No | Absolute directory; default <data-dir>/media. A recording: its file, and no new transcript | |
| language | No | What is spoken, e.g. "ro" | |
| account_id | No | Account id | |
| message_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| mime | No | |
| path | No | |
| size | No | |
| type | Yes | |
| sender | Yes | |
| caption | Yes | |
| filename | No | The name it was saved under |
| account_id | Yes | |
| message_id | Yes | |
| transcript | No | |
| image_attached | No | The photo, or a small preview of it, is attached |
| original_filename | Yes | |
| transcript_unavailable | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds valuable behavior beyond the annotations: transcripts are 'kept once made' and 'an API provider bills it' (a cost/caching trait), save_to writes media to local disk, and MEDIA_UNAVAILABLE is described as a possible error when WhatsApp no longer retains the media. These details are not in the annotations and are context-rich. Nothing contradicts the readOnlyHint/destructiveHint flags.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is short (about 55 words) and contains no fluff, but it is structured as a dense, semicolon-packed run-on that is hard to parse quickly. The MEDIA_UNAVAILABLE sentence is a useful standalone component, yet the overall ordering muddles the main action. It is concise without being cleanly structured.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema and annotations available, the description does not need to explain return values. However, it fails to clarify the role of account_id, the meaning of message_id, or when to use language vs save_to. It does cover the media type possibilities and the MEDIA_UNAVAILABLE error, but an agent would still have to infer significant context from parameter names and external knowledge.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 75%, so the heavy lifting is done by the schema. The description adds a little context for save_to (its file) and the transcript/language relation, but the required message_id has no schema description and the description does not compensate. This is an acceptable baseline-3 case.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description explains what a message's media can hold (transcript, file, photo, saved path) but never states a clear verb phrase like 'fetches' or 'returns' – it is phrased as a noun fragment. The title 'Get the media of a WhatsApp message' is clearer than the description. It implies media retrieval but does not explicitly differentiate from siblings like get_message.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no guidance on when to use this tool versus alternatives such as get_message, read_messages, or search. No exclusions or 'instead of' notes are present; usage is only weakly implied by the resource being a message's media. With many siblings, this is a notable gap.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_messageGet one WhatsApp message in fullARead-onlyIdempotent
One message in full: the message it quotes, each reaction with who left it, poll votes and event answers by person, its media, and on the user's own messages who it reached and who read it. Without account_id the id is looked for on every account.
| Name | Required | Description | Default |
|---|---|---|---|
| account_id | No | Account id | |
| message_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| text | Yes | |
| chat_id | Yes | |
| timestamp | Yes | |
| account_id | Yes | |
| message_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide readOnlyHint=true, idempotentHint=true, and destructiveHint=false, covering safety. The description adds behavioral context beyond that: it specifies exactly what data is retrieved (reactions, poll votes, etc.) and describes the fallback behavior when account_id is omitted. It does not discuss error handling or auth requirements, but given the annotations cover the safety profile, this is sufficient.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence plus a short note. It is concise and front-loaded with the core purpose ('One message in full'). Every clause adds value, and there is no fluff. The structure is efficient and easily scannable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description is complete enough for an agent to call this tool correctly. It lists all the components of the full message, describes the account_id fallback, and the output schema exists (as indicated by 'Has output schema: true'), so the return format is covered by the schema. The only minor gap is error handling (e.g., what happens if the message is not found), but that is not critical for correct invocation. The description, combined with annotations and output schema, provides sufficient context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 50% (only account_id has a description: 'Account id'). The description adds meaningful semantics for account_id by explaining the lookup behavior when omitted. However, message_id has no description in the schema and is only implied by the tool name. The description does not provide format or syntax details for either parameter beyond the behavioral note. It partially compensates for the coverage gap but not fully.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: retrieving a single WhatsApp message in full detail. It enumerates exactly what is included (quoted message, reactions, poll votes, event answers, media, read receipts) which distinguishes it from siblings like read_messages (which likely returns multiple messages) or get_media (which only fetches media). The verb 'get' and resource 'message' are explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives a clear usage context: this is for full message details, and the note about account_id explains a key behavior ('Without account_id the id is looked for on every account'). However, it does not explicitly state when NOT to use this tool versus alternatives like read_messages or search, nor does it name any sibling tools. The context is clear but lacks explicit exclusions or alternative routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_statusGet the WhatsApp connection statusARead-onlyIdempotent
Whether the account works: status (connected, not_linked, linking with its pairing code…), sync, how fresh the history is, webhook delivery, versions. accounts lists every account, with default. Call it on NOT_CONNECTED, NOT_LINKED or SYNC_IN_PROGRESS.
| Name | Required | Description | Default |
|---|---|---|---|
| account_id | No | Account id |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds useful context about what the status includes and when to call it, but it does not disclose details like what the default account behavior is or what 'fresh' history means. It neither contradicts annotations nor adds much deeper behavioral richness.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact, front-loaded with the core purpose, and the trigger condition is placed at the end as a natural action item. The enumeration of status facets is dense but each item earns its place; no filler sentences.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple read-only tool with one optional parameter and no output schema, the description covers what the status includes and when to call it. The only real gap is that it never explicitly states what happens when account_id is omitted, though 'with default' hints at it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema documents account_id at 100% coverage, so the description does not need to repeat it. The phrase 'accounts lists every account, with default' hints at default-account behavior for the optional parameter, but it is ambiguous and adds only marginal value over the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a clear verb+resource ('get status') and enumerates the specific facets it covers: connection state, sync, history freshness, webhook delivery, versions. This differentiates it from the chat/message-oriented siblings and leaves little ambiguity about what get_status reports.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly gives conditional trigger conditions: 'Call it on NOT_CONNECTED, NOT_LINKED or SYNC_IN_PROGRESS.' It does not explicitly name sibling alternatives or exclusions, but the trigger guidance is concrete and actionable, so it is above average.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
learnLearn how to use the WhatsApp toolsARead-onlyIdempotent
The guide to these tools: ids, account_id with several accounts, the workflows, the message shape and what to do about each error code. Read it once, before the other tools; it never touches WhatsApp.
| Name | Required | Description | Default |
|---|---|---|---|
| account_id | No | Account id |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and non-destructive behavior. The description adds useful context beyond the annotations: the tool is a pure documentation read that has no effect on WhatsApp. This reinforces safety and clarifies that repeated reads are harmless.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tightly packed sentences with no wasted words. The core purpose is front-loaded, and the usage instruction is immediate and actionable. Topics are enumerated efficiently.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a documentation/guide tool, the description fully covers what the tool is, what topics it contains, when to call it, and that it has no side effects. The optional account_id parameter is the only input, and the description provides enough context for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% for the single account_id parameter, but its schema description is minimal ('Account id'). The tool description adds meaningful context by noting that account_id matters 'with several accounts,' which explains when the parameter is relevant.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a clear purpose: a guide to the WhatsApp tools covering IDs, account_id, workflows, message shape, and error codes. It also distinguishes itself from the sibling operational tools by saying it 'never touches WhatsApp' and should be read 'before the other tools.'
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly tells the agent when to use it: 'Read it once, before the other tools.' It also clarifies what it is not for by stating it never touches WhatsApp, implicitly routing operational tasks to sibling tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
link_accountLink a WhatsApp accountA
Pair wazap with the user's WhatsApp when get_status says not_linked, logged_out, session_corrupt or auth_failure. Show the user the code it returns: WhatsApp → Settings → Linked devices → Link a device → Link with phone number instead. Then poll get_status every 10 s until connected.
| Name | Required | Description | Default |
|---|---|---|---|
| phone | Yes | e.g. +15550100 | |
| account_id | No | Account id |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag this as non-read-only and non-destructive. The description adds meaningful behavior beyond that: it returns a pairing code, requires the user to complete manual steps, and instructs polling get_status every 10 seconds until connected. This is useful operational context not captured by annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences deliver the trigger condition, the manual user steps, and the polling instruction without fluff. Every sentence carries operational meaning, and the most important condition is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers trigger, procedure, expected output (a code), and post-call polling. With no output schema, it could be more explicit about the return shape of the code, but for a straightforward pairing action the guidance is largely sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents both parameters. The description adds little beyond referencing 'phone number' in the user flow; it does not explain account_id or clarify parameter semantics further. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Pair') and resource ('wazap with the user's WhatsApp'), and ties the action to explicit status conditions. It is clearly distinguishable from siblings like get_status or manage_chat because it defines the exact action and outcome.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly says when to use the tool: when get_status returns not_linked, logged_out, session_corrupt, or auth_failure. It also gives the full user-facing workflow and the polling loop, leaving no ambiguity about when or how to invoke it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_chatsList WhatsApp chatsARead-onlyIdempotent
Conversations, most recently active first: chat_id, name, type, unread count, last message, and whether archived, pinned, muted or left. Use it to find a chat_id.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| filter | No | "all" leaves out archived | all |
| account_id | No | Account id |
Output Schema
| Name | Required | Description |
|---|---|---|
| sync | Yes | |
| chats | Yes | |
| count | Yes | |
| filter | Yes | |
| account_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds behavioral context beyond the annotations by disclosing sort order ('most recently active first') and the chat states surfaced (archived, pinned, muted, left). The annotations already cover read-only, idempotent, and non-destructive behavior, lowering the burden on the description.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences with no filler: the first front-loads the key ordering and return fields, and the second gives the direct use case. Every word earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a low-complexity, read-only list tool, the combination of this description, the rich annotations, and the output schema gives an agent everything needed to call it correctly. No necessary prerequisites, return-value details, or edge behaviors are missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description itself adds little about limit, filter, or account_id. However, the schema already documents filter and account_id with descriptions, and limit has clear bounds and a default, so the parameter meaning is adequately covered without the description compensating further.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific outcome—'Conversations, most recently active first'—and enumerates the exact fields returned: chat_id, name, type, unread count, last message, and archived/pinned/muted/left state. It closes with a concrete intended use ('Use it to find a chat_id'), which clearly distinguishes it from the messaging and management siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description states a clear use case: finding a chat_id. It does not name sibling alternatives or explain when not to use it, so it stops short of full routing guidance, but the context is clear enough for an agent to select it appropriately.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
manage_chatManage a WhatsApp chatADestructive
Change a chat on WhatsApp at once, with no draft: archive, pin, mute, mark_read or mark_unread; pin_message (for everyone) or star_message on a message_id; clear or delete it for the linked account; block a person. Say what will change and wait for a yes.
| Name | Required | Description | Default |
|---|---|---|---|
| action | Yes | ||
| chat_id | Yes | Chat id, or a phone number | |
| pin_hours | No | pin_message: 168 by default | |
| account_id | No | Account id | |
| message_id | No | pin_message, star_message and their undo; in chat_id | |
| mute_hours | No | mute: 8 by default |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already signal destructive and non-idempotent behavior, so the description's job is to add context. It adds meaningful behavioral detail: actions happen 'at once, with no draft', pin_message affects 'everyone', clear/delete is scoped to 'the linked account', and user confirmation is required before changes. These are useful traits not captured in structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single efficient sentence that front-loads the action list and ends with the critical confirmation instruction. There is no filler, though the phrase 'at once, with no draft' is slightly ambiguous and could have been clearer or omitted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a multi-action, destructive tool with six parameters and no output schema, the description covers the key invocation context: what actions are available, the account scope, the need for message_id for certain operations, and the confirmation requirement. It does not describe return values or error behavior, but those are less critical given the schema already covers parameter details.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is high (83%), so the schema already documents chat_id, account_id, message_id, pin_hours, and mute_hours. The description adds some semantic clarification — pin_message applies 'for everyone', star_message operates on a message_id, and clear/delete applies to the linked account — but does not deeply enrich the parameter understanding beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific verb ('Change a chat') and enumerates the concrete actions it performs (archive, pin, mute, mark_read, etc.), which is far more specific than the title alone. It doesn't explicitly contrast itself with sibling tools like send_message or manage_group, but the action list makes the resource and scope unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context for when to use the tool: when a chat-level change is needed (archive, pin, mute, read state, message pin/star, clear/delete, block). It also includes an important process instruction — 'Say what will change and wait for a yes' — which tells the agent how to invoke it safely. It does not explicitly state when not to use it or point to alternatives, so it misses the top score.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
manage_groupManage a WhatsApp groupADestructive
Create a group, join one from an invite (preview first, then confirm: true), or administer one: members, name, description, photo, invite link, join requests, settings, leave. Most actions need admin. Every change shows to all members at once: say what will change, wait for a yes.
| Name | Required | Description | Default |
|---|---|---|---|
| url | No | set_picture: public image URL | |
| value | No | The name (create, set_subject) or description; "on"/"off"; set_add_mode "admins"/"all"; set_disappearing "off"/"24h"/"7d"/"90d" | |
| action | Yes | ||
| invite | No | join: a chat.whatsapp.com link or its code | |
| confirm | No | join: true joins, after the user said yes to the preview | |
| group_id | No | "<id>@g.us"; every action but create and join | |
| file_path | No | set_picture: local JPEG, PNG or WebP | |
| account_id | No | Account id | |
| message_id | No | join: an invite message instead | |
| participant_ids | No | create, add, remove, promote, demote, approve or reject |
Output Schema
| Name | Required | Description |
|---|---|---|
| name | No | |
| next | No | join preview: the step after the user's yes |
| action | Yes | |
| status | No | join: preview joins nothing |
| applied | No | |
| group_id | Yes | |
| account_id | Yes | |
| description | No | |
| invite_link | No | |
| participants | No | |
| join_approval | No | |
| join_requests | No | |
| profile_pic_url | No | |
| participant_count | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Although annotations already declare destructiveHint=true and readOnlyHint=false, the description adds valuable behavioral detail beyond those flags: 'Most actions need admin' and 'Every change shows to all members at once: say what will change, wait for a yes.' It also discloses the confirm-before-join flow with 'preview first, then confirm: true,' which is exactly the kind of side-effect transparency an agent needs for a social, visible mutation tool. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences with no filler. The first sentence front-loads the tool's capabilities, and the second delivers the critical behavioral warning. Every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a broad tool with 21 enum actions and 10 parameters, the description gives a high-level map of capabilities plus the essential safety/social rules. The output schema exists, so return values need no explanation. It could be slightly more complete by steering read-only group lookups to get_group_info, but the description is sufficient for an agent to use it safely.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 90%, so the schema carries most parameter meaning. The description adds important semantic context for the confirm parameter by tying it to user consent: 'preview first, then confirm: true' and 'wait for a yes.' This goes beyond the schema's bare 'join: true joins, after the user said yes to the preview' and reinforces how the parameter should be used.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses specific verbs and resources: 'Create a group, join one from an invite ... or administer one: members, name, description, photo, invite link, join requests, settings, leave.' This clearly differentiates it from siblings like manage_chat and get_group_info by scoping it to group-level administration. It is not a tautology and communicates the tool's full intent.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives practical context: 'Most actions need admin' and 'Every change shows to all members at once: say what will change, wait for a yes.' This tells the agent when it is appropriate to invoke the tool and what interaction pattern to follow. It does not explicitly name alternatives or exclusion conditions, but the group-vs-chat scope and admin caution make usage context clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
react_to_messageReact to a WhatsApp messageAIdempotent
React to a message with one emoji, or pass "" to take your reaction off.
| Name | Required | Description | Default |
|---|---|---|---|
| emoji | Yes | ||
| account_id | No | Account id | |
| message_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| emoji | Yes | |
| account_id | Yes | |
| message_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds a useful non-obvious behavior: an empty string removes the reaction. It does not, however, state whether an existing reaction is replaced or what happens when removing a reaction that does not exist, leaving part of the behavior to inference.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single, tight sentence conveys the primary operation and the important edge-case behavior with no filler. The key constraint is front-loaded and immediately actionable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple three-parameter tool with an output schema and annotations covering idempotence and non-destructiveness, the description is nearly sufficient. It explains the emoji special case and leaves message_id and account_id inferable from their names; a note on the optional account_id's default would make it fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description meaningfully clarifies the emoji parameter: exactly one emoji is allowed, and an empty string requests removal. The schema only describes account_id as 'Account id' and leaves message_id and emoji without descriptions, so the description only partially compensates for the 33% coverage; the remaining parameters rely on their names.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a concrete action ('React to a message') with an explicit constraint ('one emoji') and a distinct removal mode ('pass "" to take your reaction off'). This clearly separates it from siblings like send_message, edit_message, and delete_message.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The intended use is implied: call this when you want to add or remove an emoji reaction on a message. However, it names no sibling alternatives and gives no when-not-to-use guidance, so the agent must infer the selection context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_messagesRead messages from a WhatsApp chatARead-onlyIdempotent
Read one chat, oldest to newest: the latest messages, or older ones with before (wazap asks the phone when the local history runs out). chat_id "status" reads the stories people posted, newest first, from the last hours (at most a day); they show nowhere else.
| Name | Required | Description | Default |
|---|---|---|---|
| hours | No | "status" only: how far back, 24 by default | |
| limit | No | ||
| types | No | Only these types; limit counts them, so ["call"] gives that many calls | |
| before | No | The oldest message_id you have | |
| chat_id | Yes | Chat id from another tool, a phone number, or "status" for stories | |
| account_id | No | Account id | |
| include_previews | No | Attach a small image of each photo, up to 12 |
Output Schema
| Name | Required | Description |
|---|---|---|
| sync | Yes | |
| count | Yes | |
| hours | No | |
| notes | No | Caveats to act on or tell the user |
| older | No | before ran past the local history: the phone was asked, and sent this many |
| types | No | |
| chat_id | Yes | |
| omitted | No | Older stories left out by limit |
| messages | Yes | |
| account_id | Yes | |
| preview_count | Yes | |
| unconfirmed_sends | No | Sends WhatsApp has not echoed yet: outcome unknown, not failed |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds meaningful behavioral details: ordering (oldest to newest), the special 'status' mode behavior (newest first, limited to last hours up to a day), and the fact that it may query the phone when local history runs out. It also notes that stories appear only here, which is important context. No contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a compact two-sentence layout, front-loaded with the core behavior (read one chat oldest to newest), then covering the 'before' parameter, then the 'status' special case. Every clause adds meaning, and the structure is logical: main use, then variations. No filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (7 parameters, multiple modes, special 'status' behavior), the description covers the key usage scenarios (latest messages, older via before, status stories) and provides enough context for an agent to call it correctly. The output schema exists, so return values are already defined. Missing details like exact pagination behavior or limit default are in the schema, and the description handles the non-obvious parts.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 86%, with most parameters having descriptions (hours, types, before, chat_id, include_previews). The description adds extra meaning for key parameters: 'before' is clarified as the oldest message_id you have, 'status' chat_id is explained, and 'types' is explained with an example and the behavior that the limit counts them. Limit has no description in schema, but the description doesn't explicitly cover it, yet the overall value added is high.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it reads messages from a chat, with ordering (oldest to newest) and a special 'status' mode for stories. It distinguishes itself from siblings like get_status and get_message by covering both regular chats and the status feed, and mentions a unique capability (fetching older messages via 'before') that other tools likely lack.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear context for when to use 'status' (for stories, which 'show nowhere else') and mentions bridging local history gaps via 'before', but it doesn't explicitly state when NOT to use this tool versus alternatives like search, get_message, or wait_for_messages. It implies usage for reading messages but lacks exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
rememberRemember something about a personAIdempotent
Keep what the user says about someone, locally, never on WhatsApp: a note, tags, details find_contact matches ({"relatie": "mama"}), or handled: true for an ask dealt with elsewhere. #private keeps their words out of what you did not ask about them by name; #no-catchup keeps them out of catch_up.
| Name | Required | Description | Default |
|---|---|---|---|
| note | No | "" removes it | |
| fields | No | e.g. {"nickname": "Mișu", "role": "contabil"}; "" deletes a key | |
| chat_id | Yes | Chat id, or a phone number | |
| handled | No | Off catch_up's waiting until they write again | |
| add_tags | No | e.g. ["client"] | |
| account_id | No | Account id | |
| remove_tags | No | ||
| remove_fields | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| name | Yes | |
| note | No | |
| tags | No | |
| fields | No | |
| number | No | |
| chat_id | Yes | |
| handled | No | The ask taken off the waiting list; null when nothing was open |
| account_id | Yes | |
| is_business | No | |
| is_my_contact | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds meaningful behavioral context beyond the annotations: data is stored locally and never on WhatsApp, and the '#private' and '#no-catchup' tags control future retrieval behavior. This is genuinely useful information that the annotations alone do not convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loads the core purpose before explaining special flags. It is slightly dense and could be more readable, but every part adds meaningful information without unnecessary filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the output schema, 75% schema coverage, and annotations, the description covers the essential purpose, privacy behavior, and special handling for catch-up and private queries. The main gap is the lack of explicit differentiation from the 'learn' sibling, but the tool is still usable without that clarification.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already high at 75%, so the baseline is 3. The description adds value by giving concrete examples for 'details' ('{"relatie": "mama"}'), explaining 'handled: true' as marking an ask dealt with elsewhere, and clarifying the privacy/catch-up semantics of the special tags.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies a specific action ('Keep what the user says about someone') and resource (person-related memory), and it adds important scope with 'locally, never on WhatsApp.' It also references the 'find_contact' and 'catch_up' contexts, which helps distinguish it from those siblings, though it does not explicitly contrast it with the 'learn' sibling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides useful context for when to set 'handled: true' and how '#private' and '#no-catchup' affect behavior, but it does not explicitly explain when to prefer this tool over alternatives like 'learn' or when not to use it. Usage is implied rather than directly stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
searchSearch WhatsApp messagesARead-onlyIdempotent
Find messages by meaning and by words at once, in every chat or one: a paraphrase or another language still hits. match: "words" for exact words (a number, a URL). since, until and from narrow it; coverage and freshness say how much history was searched.
| Name | Required | Description | Default |
|---|---|---|---|
| from | No | "me", a number, an id, or a name only one person has | |
| limit | No | ||
| match | No | "words": only messages holding the words | hybrid |
| query | Yes | ||
| since | No | ISO date or time | |
| until | No | ISO date or time | |
| chat_id | No | Chat id, or a phone number | |
| account_id | No | Account id |
Output Schema
| Name | Required | Description |
|---|---|---|
| mode | Yes | keyword_fallback: meaning search could not run, see recall_unavailable |
| sync | Yes | |
| count | Yes | |
| index | No | |
| notes | No | Caveats to act on or tell the user |
| query | Yes | |
| coverage | No | null: it could not be counted |
| messages | Yes | |
| freshness | Yes | |
| account_id | Yes | |
| scan_capped | No | Older matches may be missing: narrow the search |
| from_resolved | No | |
| private_omitted | No | Matches from people tagged #private, left out: chat_id or from shows them |
| searched_back_to | No | Older messages were not searched: narrow the search |
| recall_unavailable | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and destructiveHint=false, covering safety. The description adds behavioral details: it searches semantically ('a paraphrase or another language still hits'), and it mentions 'coverage and freshness' as output indicators. This goes beyond the annotations and informs the agent about search behavior and result quality. No contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences with no filler. The core capability is front-loaded ('Find messages by meaning and by words at once'), and the parameter hints are woven in naturally. Every sentence adds value, and the structure is clear and scannable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a search tool with 8 parameters and an output schema, the description covers the main usage scenarios, including hybrid search, exact word matching, and time/person filtering. It mentions output indicators (coverage/freshness). It doesn't explain all params, but the schema handles most. The description is sufficient for an agent to invoke the tool correctly without ambiguity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 75% (6 of 8 params have descriptions). The description adds meaning to 'match' by explaining the 'words' mode, and to since/until/from by saying they 'narrow it'. It doesn't explain limit, query, chat_id, account_id, but those are reasonably self-explanatory or covered by schema. Since coverage is slightly below 80%, the description partially compensates, earning a 4.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb 'find' and the resource 'messages', and explains the hybrid semantic+literal search capability. It also mentions scope ('every chat or one'), distinguishing it from read_messages or get_message which are retrieval tools. The purpose is unambiguous and specific.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides context on when to use the tool: when you need to search by meaning or exact words, and it explains narrowing parameters (since, until, from). However, it doesn't explicitly name alternatives or state when NOT to use it. The guidance is clear but lacks explicit exclusion criteria, so a 4 is appropriate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_messageDraft a WhatsApp messageA
Drafts text, media, polls, locations, forwards; sends nothing. Call it as soon as you have recipient and text: it returns draft_id and preview (recipient, number, exact text). Show that preview; confirm_send only on a yes to this text and recipient — a send in the same request is that yes.
| Name | Required | Description | Default |
|---|---|---|---|
| as | No | Media: a plain document, a voice note, a looping GIF | |
| url | No | Media: public http(s) URL | |
| text | Yes | The message, or the caption, poll question or place name; "" for a forward, a voice note or audio | |
| address | No | Location: shown under the name | |
| chat_id | Yes | Chat id, or a phone number | |
| forward | No | Forward this message; text "" | |
| options | No | Poll answers | |
| latitude | No | ||
| reply_to | No | ||
| file_path | No | Media: absolute path on the machine running wazap | |
| longitude | No | ||
| account_id | No | Account id | |
| mention_ids | No | Chat ids to @-mention; write @<number> in text for each | |
| multi_select | No | Poll: several answers allowed |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only signal not read-only, not idempotent, and not destructive. The description adds critical behavior beyond that: no message is sent, a draft_id and preview are returned, and the preview must be shown to the user. It doesn't cover permissions or error cases, but the primary side effect and workflow are clearly disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two information-dense sentences with no filler. The first sentence front-loads the core identity ('Drafts... sends nothing') and the second packs the entire invocation workflow. Slightly dense, but every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, but the description compensates by stating the return values (draft_id and preview) and the confirmation protocol. All 14 parameters are schema-documented, and the description covers the essential call conditions and the handoff to confirm_send. Minor gaps like media URL/path constraints are already handled by the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 79%, with most parameters already well-described in the schema (text, url, as, options, address, etc.). The description maps content types to parameter groups ('media' → as/url/file_path, 'polls' → options/multi_select) but adds no per-parameter detail beyond what the schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb 'Drafts' and resource 'WhatsApp message', then enumerates the exact content types (text, media, polls, locations, forwards). The explicit phrase 'sends nothing' sharply distinguishes this from the sibling confirm_send, so an agent can tell them apart immediately.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use guidance: 'Call it as soon as you have recipient and text'. It also names the alternative tool (confirm_send) and specifies the condition for using it: only after the user confirms the exact text and recipient. The same-request send nuance is also spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
wait_for_messagesWait for new WhatsApp messagesARead-onlyIdempotent
Wait for messages from other people, up to timeout_seconds, and return them with a cursor: pass it to the next call so nothing that lands between calls is missed. addressed_to_me wakes only for direct messages, mentions and replies to the user. For agents that stay on the line.
| Name | Required | Description | Default |
|---|---|---|---|
| cursor | No | From the previous call | |
| chat_id | No | Chat id, or a phone number | |
| account_id | No | Account id | |
| addressed_to_me | No | ||
| timeout_seconds | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | |
| cursor | Yes | Pass to the next call |
| messages | Yes | |
| timed_out | Yes | |
| account_id | Yes | |
| cursor_reset | Yes | The cursor was from another run; the wait started now |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and non-destructive behavior. The description adds value beyond these by explaining cursor semantics ('nothing that lands between calls is missed') and the exact behavior of addressed_to_me (wakes only for direct messages, mentions, replies). No contradictions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the core action, no filler. Every clause contributes: the wait behavior, timeout, cursor use, filter semantics, and intended use case. Highly efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return format is not required. The description covers waiting, timeout, cursor handling, and filter behavior. An agent has everything needed to call it correctly and integrate it into a polling loop. No critical gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 60% — cursor, chat_id, and account_id have descriptions, but addressed_to_me and timeout_seconds do not. The description explicitly explains both: timeout_seconds via 'up to timeout_seconds' and addressed_to_me via its wake filter. This fully compensates for the undocumented parameters, going beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb 'wait' with resource 'messages from other people' and a timeout. It distinguishes itself from read_messages by emphasizing waiting/blocking, and mentions the cursor for continuity. The purpose is specific and unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'For agents that stay on the line' provides context for when to use this tool, and the cursor instruction implies a polling loop. However, it does not explicitly state when not to use it (e.g., for reading existing messages, use read_messages instead). The guidance is implied rather than explicit, so a 4 is appropriate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
43 tool updates
v1.0.3- Added
catch_up - Changed
confirm_send2 fields changed- changed
Input schema / properties / account_id / descriptionPrevious value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id" - changed
Input schema / properties / draft_id / descriptionPrevious value: -"The draft_id returned by a send_* tool"New value: +"From send_message"
- Removed
create_group - Changed
delete_message4 fields changed- changed
Input schema / properties / account_id / descriptionPrevious value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id" - removed
Input schema / properties / for_everyone / descriptionRemoved value: -"Required. true retracts it for everyone in the chat; false deletes it for the linked account only" - removed
Input schema / properties / message_id / descriptionRemoved value: -"Message id from read_messages / search_messages / get_message, e.g. \"false_4072...@s.whatsapp.net_3EB0...\"" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "account_id": { + "type": "string" + }, + "for_everyone": { + "type": "boolean" + }, + "message_id": { + "type": "string" + } + }, + "required": [ + "message_id", + "for_everyone", + "account_id" + ], + "type": "object" +}
- Removed
download_media - Changed
edit_message4 fields changed- changed
Input schema / properties / account_id / descriptionPrevious value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id" - removed
Input schema / properties / message_id / descriptionRemoved value: -"A message the linked account sent" - removed
Input schema / properties / text / descriptionRemoved value: -"The replacement text" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "account_id": { + "type": "string" + }, + "chat_id": { + "type": "string" + }, + "message_id": { + "type": "string" + }, + "text": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + }, + "required": [ + "message_id", + "chat_id", + "text", + "timestamp", + "account_id" + ], + "type": "object" +}
- Added
find_contact - Removed
forward_message - Removed
get_contact - Changed
get_group_info3 fields changed- changed
Input schema / properties / account_id / descriptionPrevious value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id" - changed
Input schema / properties / group_id / descriptionPrevious value: -"Group chat id (\"<id>@g.us\")"New value: +"<id>@g.us" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "account_id": { + "type": "string" + }, + "announcement_only": { + "type": "boolean" + }, + "chat_id": { + "type": "string" + }, + "community": { + "additionalProperties": false, + "properties": { + "is_community": { + "type": "boolean" + }, + "parent_group_id": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "is_community", + "parent_group_id" + ], + "type": "object" + }, + "created_at": { + "type": [ + "string", + "null" + ] + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "disappearing_seconds": { + "type": "number" + }, + "i_am_admin": { + "type": "boolean" + }, + "info_locked": { + "type": "boolean" + }, + "invite_link": { + "type": "string" + }, + "join_approval": { + "type": "boolean" + }, + "member_add_mode": { + "enum": [ + "admins", + "all" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "owner": { + "type": [ + "string", + "null" + ] + }, + "participant_count": { + "type": "number" + }, + "participants": { + "items": { + "additionalProperties": false, + "properties": { + "contact_id": { + "type": "string" + }, + "is_admin": { + "type": "boolean" + }, + "name": { + "type": "string" + } + }, + "required": [ + "contact_id", + "name", + "is_admin" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "chat_id", + "name", + "description", + "owner", + "created_at", + "participant_count", + "participants", + "announcement_only", + "i_am_admin", + "info_locked", + "member_add_mode", + "join_approval", + "disappearing_seconds", + "account_id" + ], + "type": "object" +}
- Added
get_media - Changed
get_message3 fields changed- changed
Input schema / properties / account_id / descriptionPrevious value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id" - removed
Input schema / properties / message_id / descriptionRemoved value: -"Message id from read_messages / search_messages / get_message, e.g. \"false_4072...@s.whatsapp.net_3EB0...\"" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": true, + "properties": { + "account_id": { + "type": "string" + }, + "chat_id": { + "type": "string" + }, + "message_id": { + "type": "string" + }, + "text": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + }, + "required": [ + "message_id", + "chat_id", + "text", + "timestamp", + "account_id" + ], + "type": "object" +}
- Removed
get_recent_messages - Changed
get_status1 field changed- changed
Input schema / properties / account_id / descriptionPrevious value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id"
- Removed
get_stories - Removed
get_unanswered - Removed
join_group - Changed
learn1 field changed- changed
Input schema / properties / account_id / descriptionPrevious value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id"
- Changed
link_account2 fields changed- changed
Input schema / properties / account_id / descriptionPrevious value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id" - changed
Input schema / properties / phone / descriptionPrevious value: -"International format, e.g. +15550100"New value: +"e.g. +15550100"
- Removed
list_accounts - Changed
list_chats4 fields changed- changed
Input schema / properties / account_id / descriptionPrevious value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id" - changed
Input schema / properties / filter / descriptionPrevious value: -"Which chats to list; \"all\" (default) excludes archived ones"New value: +"\"all\" leaves out archived" - removed
Input schema / properties / limit / descriptionRemoved value: -"Maximum number of chats (1-100)" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "account_id": { + "type": "string" + }, + "chats": { + "items": { + "additionalProperties": true, + "properties": { + "chat_id": { + "type": "string" + }, + "last_message": { + "anyOf": [ + { + "additionalProperties": true, + "properties": { + "private": { + "const": true, + "description": "Tagged #private: no words", + "type": "boolean" + } + }, + "type": "object" + }, + { + "type": "null" + } + ] + }, + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "unread_count": { + "type": "number" + } + }, + "required": [ + "chat_id", + "name", + "type", + "unread_count" + ], + "type": "object" + }, + "type": "array" + }, + "count": { + "type": "number" + }, + "filter": { + "type": "string" + }, + "sync": { + "type": "string" + } + }, + "required": [ + "filter", + "count", + "chats", + "sync", + "account_id" + ], + "type": "object" +}
- Changed
manage_chat6 fields changed- changed
Input schema / properties / account_id / descriptionPrevious value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id" - removed
Input schema / properties / action / descriptionRemoved value: -"What to do with the chat" - changed
Input schema / properties / chat_id / descriptionPrevious value: -"Chat id as returned by another tool (\"<digits>@s.whatsapp.net\" or \"<id>@g.us\"), or a phone number in international format"New value: +"Chat id, or a phone number" - changed
Input schema / properties / message_id / descriptionPrevious value: -"The message for pin_message, unpin_message, star_message and unstar_message; it must be in chat_id"New value: +"pin_message, star_message and their undo; in chat_id" - changed
Input schema / properties / mute_hours / descriptionPrevious value: -"Hours to mute, default 8; only used by \"mute\""New value: +"mute: 8 by default" - changed
Input schema / properties / pin_hours / descriptionPrevious value: -"How long pin_message keeps the message pinned: 24, 168 (default) or 720 hours"New value: +"pin_message: 168 by default"
- Changed
manage_group13 fields changed- changed
Input schema / properties / account_id / descriptionPrevious value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id" - removed
Input schema / properties / action / descriptionRemoved value: -"Group action to perform" - changed
Input schema / properties / action / enumPrevious value: -[ - "add", - "remove", - "promote", - "demote", - "leave", - "set_subject", - "set_description", - "set_picture", - "remove_picture", - "get_invite_link", - "revoke_invite_link", - "list_join_requests", - "approve_join_requests", - "reject_join_requests", - "set_announcement_only", - "set_info_locked", - "set_add_mode", - "set_join_approval", - "set_disappearing" -]New value: +[ + "create", + "join", + "add", + "remove", + "promote", + "demote", + "leave", + "set_subject", + "set_description", + "set_picture", + "remove_picture", + "get_invite_link", + "revoke_invite_link", + "list_join_requests", + "approve_join_requests", + "reject_join_requests", + "set_announcement_only", + "set_info_locked", + "set_add_mode", + "set_join_approval", + "set_disappearing" +] - added
Input schema / properties / confirmAdded value: +{ + "default": false, + "description": "join: true joins, after the user said yes to the preview", + "type": "boolean" +} - changed
Input schema / properties / file_path / descriptionPrevious value: -"set_picture: absolute path of a local JPEG, PNG or WebP"New value: +"set_picture: local JPEG, PNG or WebP" - changed
Input schema / properties / group_id / descriptionPrevious value: -"Group chat id (\"<id>@g.us\")"New value: +"\"<id>@g.us\"; every action but create and join" - added
Input schema / properties / inviteAdded value: +{ + "description": "join: a chat.whatsapp.com link or its code", + "maxLength": 512, + "minLength": 1, + "type": "string" +} - added
Input schema / properties / message_idAdded value: +{ + "description": "join: an invite message instead", + "minLength": 5, + "type": "string" +} - changed
Input schema / properties / participant_ids / descriptionPrevious value: -"Targets of add/remove/promote/demote/approve_join_requests/reject_join_requests"New value: +"create, add, remove, promote, demote, approve or reject" - changed
Input schema / properties / url / descriptionPrevious value: -"set_picture: public http(s) URL to fetch and use as the photo"New value: +"set_picture: public image URL" - changed
Input schema / properties / value / descriptionPrevious value: -"New subject or description; \"on\"/\"off\" for set_announcement_only, set_info_locked, set_join_approval; \"admins\"/\"all\" for set_add_mode; \"off\"/\"24h\"/\"7d\"/\"90d\" for set_disappearing"New value: +"The name (create, set_subject) or description; \"on\"/\"off\"; set_add_mode \"admins\"/\"all\"; set_disappearing \"off\"/\"24h\"/\"7d\"/\"90d\"" - changed
Input schema / requiredPrevious value: -[ - "group_id", - "action" -]New value: +[ + "action" +] - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "account_id": { + "type": "string" + }, + "action": { + "type": "string" + }, + "applied": { + "type": "string" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "group_id": { + "type": [ + "string", + "null" + ] + }, + "invite_link": { + "type": "string" + }, + "join_approval": { + "type": [ + "boolean", + "null" + ] + }, + "join_requests": { + "items": { + "additionalProperties": true, + "properties": {}, + "type": "object" + }, + "type": "array" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "next": { + "description": "join preview: the step after the user's yes", + "type": "string" + }, + "participant_count": { + "type": [ + "number", + "null" + ] + }, + "participants": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "reason": { + "type": "string" + }, + "status": { + "enum": [ + "ok", + "invite_needed", + "failed" + ], + "type": "string" + } + }, + "required": [ + "id", + "status" + ], + "type": "object" + }, + "type": "array" + }, + "profile_pic_url": { + "type": [ + "string", + "null" + ] + }, + "status": { + "description": "join: preview joins nothing", + "enum": [ + "preview", + "joined", + "pending_approval" + ], + "type": "string" + } + }, + "required": [ + "action", + "group_id", + "account_id" + ], + "type": "object" +}
- Removed
mark_handled - Changed
react_to_message4 fields changed- changed
Input schema / properties / account_id / descriptionPrevious value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id" - removed
Input schema / properties / emoji / descriptionRemoved value: -"A single emoji such as \"👍\", or \"\" to remove your reaction" - removed
Input schema / properties / message_id / descriptionRemoved value: -"Message id from read_messages / search_messages / get_message, e.g. \"false_4072...@s.whatsapp.net_3EB0...\"" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "account_id": { + "type": "string" + }, + "emoji": { + "type": "string" + }, + "message_id": { + "type": "string" + } + }, + "required": [ + "message_id", + "emoji", + "account_id" + ], + "type": "object" +}
- Changed
read_messages8 fields changed- changed
Input schema / properties / account_id / descriptionPrevious value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id" - changed
Input schema / properties / before / descriptionPrevious value: -"Return the messages immediately older than this message_id"New value: +"The oldest message_id you have" - changed
Input schema / properties / chat_id / descriptionPrevious value: -"Chat id as returned by another tool (\"<digits>@s.whatsapp.net\" or \"<id>@g.us\"), or a phone number in international format"New value: +"Chat id from another tool, a phone number, or \"status\" for stories" - added
Input schema / properties / hoursAdded value: +{ + "description": "\"status\" only: how far back, 24 by default", + "maximum": 24, + "minimum": 1, + "type": "integer" +} - changed
Input schema / properties / include_previews / descriptionPrevious value: -"Attach a small JPEG of each photo, newest first, up to 12 per call, so you can see what was sent: the preview WhatsApp shipped when there is one, otherwise the photo is downloaded once and shrunk on the machine running wazap"New value: +"Attach a small image of each photo, up to 12" - removed
Input schema / properties / limit / descriptionRemoved value: -"Maximum number of messages (1-200)" - changed
Input schema / properties / types / descriptionPrevious value: -"Keep only these message types; omit for every type. The limit counts matching messages, so [\"call\"] returns that many calls, not that many messages of which some are calls."New value: +"Only these types; limit counts them, so [\"call\"] gives that many calls" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "account_id": { + "type": "string" + }, + "chat_id": { + "type": "string" + }, + "count": { + "type": "number" + }, + "hours": { + "type": "number" + }, + "messages": { + "items": { + "additionalProperties": true, + "properties": { + "chat_id": { + "type": "string" + }, + "message_id": { + "type": "string" + }, + "private": { + "const": true, + "description": "Tagged #private: no words", + "type": "boolean" + }, + "text": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + }, + "required": [ + "message_id", + "chat_id", + "text", + "timestamp" + ], + "type": "object" + }, + "type": "array" + }, + "notes": { + "description": "Caveats to act on or tell the user", + "items": { + "type": "string" + }, + "type": "array" + }, + "older": { + "additionalProperties": false, + "description": "before ran past the local history: the phone was asked, and sent this many", + "properties": { + "asked_phone": { + "const": true, + "type": "boolean" + }, + "received": { + "type": "number" + } + }, + "required": [ + "asked_phone", + "received" + ], + "type": "object" + }, + "omitted": { + "description": "Older stories left out by limit", + "type": "number" + }, + "preview_count": { + "type": "number" + }, + "sync": { + "type": "string" + }, + "types": { + "items": { + "type": "string" + }, + "type": "array" + }, + "unconfirmed_sends": { + "description": "Sends WhatsApp has not echoed yet: outcome unknown, not failed", + "items": { + "additionalProperties": false, + "properties": { + "draft_id": { + "type": "string" + }, + "handed_at": { + "type": "string" + }, + "state": { + "const": "unknown", + "type": "string" + }, + "text": { + "type": "string" + } + }, + "required": [ + "draft_id", + "text", + "handed_at", + "state" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "chat_id", + "count", + "preview_count", + "messages", + "sync", + "account_id" + ], + "type": "object" +}
- Removed
recall - Added
remember - Removed
remove_contact - Removed
save_contact - Added
search - Removed
search_contacts - Removed
search_messages - Removed
send_location - Removed
send_media - Changed
send_message15 fields changed- changed
Input schema / properties / account_id / descriptionPrevious value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id" - added
Input schema / properties / addressAdded value: +{ + "description": "Location: shown under the name", + "maxLength": 500, + "type": "string" +} - added
Input schema / properties / asAdded value: +{ + "description": "Media: a plain document, a voice note, a looping GIF", + "enum": [ + "document", + "voice", + "gif" + ], + "type": "string" +} - changed
Input schema / properties / chat_id / descriptionPrevious value: -"Chat id as returned by another tool (\"<digits>@s.whatsapp.net\" or \"<id>@g.us\"), or a phone number in international format"New value: +"Chat id, or a phone number" - added
Input schema / properties / file_pathAdded value: +{ + "description": "Media: absolute path on the machine running wazap", + "minLength": 1, + "type": "string" +} - added
Input schema / properties / forwardAdded value: +{ + "$ref": "#/properties/reply_to", + "description": "Forward this message; text \"\"" +} - added
Input schema / properties / latitudeAdded value: +{ + "maximum": 90, + "minimum": -90, + "type": "number" +} - added
Input schema / properties / longitudeAdded value: +{ + "maximum": 180, + "minimum": -180, + "type": "number" +} - changed
Input schema / properties / mention_ids / descriptionPrevious value: -"Chat ids to @-mention; write @<number> in the text for each, or wazap adds it at the end"New value: +"Chat ids to @-mention; write @<number> in text for each" - added
Input schema / properties / multi_selectAdded value: +{ + "description": "Poll: several answers allowed", + "type": "boolean" +} - added
Input schema / properties / optionsAdded value: +{ + "description": "Poll answers", + "items": { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + "maxItems": 12, + "minItems": 2, + "type": "array" +} - removed
Input schema / properties / reply_to / descriptionRemoved value: -"Quote-reply to this message" - changed
Input schema / properties / text / descriptionPrevious value: -"The message text"New value: +"The message, or the caption, poll question or place name; \"\" for a forward, a voice note or audio" - removed
Input schema / properties / text / minLengthRemoved value: -1 - added
Input schema / properties / urlAdded value: +{ + "description": "Media: public http(s) URL", + "format": "uri", + "type": "string" +}
- Removed
send_poll - Removed
set_contact_note - Removed
set_profile_picture - Removed
sync_contacts - Removed
transcribe_audio - Removed
update_contact_details - Changed
wait_for_messages6 fields changed- changed
Input schema / properties / account_id / descriptionPrevious value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id" - removed
Input schema / properties / addressed_to_me / descriptionRemoved value: -"Only direct messages, @-mentions of the user and replies to the user's messages" - changed
Input schema / properties / chat_id / descriptionPrevious value: -"Only messages in this chat"New value: +"Chat id, or a phone number" - changed
Input schema / properties / cursor / descriptionPrevious value: -"The cursor returned by the previous call"New value: +"From the previous call" - removed
Input schema / properties / timeout_seconds / descriptionRemoved value: -"How long to wait (1-55 s)" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "account_id": { + "type": "string" + }, + "count": { + "type": "number" + }, + "cursor": { + "description": "Pass to the next call", + "type": "string" + }, + "cursor_reset": { + "description": "The cursor was from another run; the wait started now", + "type": "boolean" + }, + "messages": { + "items": { + "additionalProperties": true, + "properties": { + "chat_id": { + "type": "string" + }, + "message_id": { + "type": "string" + }, + "private": { + "const": true, + "description": "Tagged #private: no words", + "type": "boolean" + }, + "text": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + }, + "required": [ + "message_id", + "chat_id", + "text", + "timestamp" + ], + "type": "object" + }, + "type": "array" + }, + "timed_out": { + "type": "boolean" + } + }, + "required": [ + "count", + "messages", + "cursor", + "timed_out", + "cursor_reset", + "account_id" + ], + "type": "object" +}
13 tool updates
v0.21.0- Changed
delete_message3 fields changed- removed
Input schema / properties / for_everyone / defaultRemoved value: -false - changed
Input schema / properties / for_everyone / descriptionPrevious value: -"Retract for all participants (WhatsApp supports no other kind of delete here)"New value: +"Required. true retracts it for everyone in the chat; false deletes it for the linked account only" - changed
Input schema / requiredPrevious value: -[ - "message_id" -]New value: +[ + "message_id", + "for_everyone" +]
- Changed
get_recent_messages1 field changed- changed
Input schema / properties / types / items / enumPrevious value: -[ - "text", - "image", - "video", - "audio", - "voice", - "document", - "sticker", - "location", - "contact", - "poll", - "reaction", - "deleted", - "view_once", - "call", - "system", - "unknown" -]New value: +[ + "text", + "image", + "video", + "audio", + "voice", + "document", + "sticker", + "location", + "contact", + "poll", + "reaction", + "deleted", + "view_once", + "call", + "event", + "invite", + "system", + "unknown" +]
- Added
join_group - Changed
manage_chat3 fields changed- changed
Input schema / properties / action / enumPrevious value: -[ - "archive", - "unarchive", - "pin", - "unpin", - "mute", - "unmute", - "mark_read", - "mark_unread" -]New value: +[ + "archive", + "unarchive", + "pin", + "unpin", + "mute", + "unmute", + "mark_read", + "mark_unread", + "pin_message", + "unpin_message", + "star_message", + "unstar_message", + "clear", + "delete", + "block", + "unblock" +] - added
Input schema / properties / message_idAdded value: +{ + "description": "The message for pin_message, unpin_message, star_message and unstar_message; it must be in chat_id", + "minLength": 5, + "type": "string" +} - added
Input schema / properties / pin_hoursAdded value: +{ + "description": "How long pin_message keeps the message pinned: 24, 168 (default) or 720 hours", + "enum": [ + 24, + 168, + 720 + ], + "type": "number" +}
- Changed
manage_group5 fields changed- changed
Input schema / properties / action / enumPrevious value: -[ - "add", - "remove", - "promote", - "demote", - "leave", - "set_subject", - "set_description", - "get_invite_link", - "revoke_invite_link" -]New value: +[ + "add", + "remove", + "promote", + "demote", + "leave", + "set_subject", + "set_description", + "set_picture", + "remove_picture", + "get_invite_link", + "revoke_invite_link", + "list_join_requests", + "approve_join_requests", + "reject_join_requests", + "set_announcement_only", + "set_info_locked", + "set_add_mode", + "set_join_approval", + "set_disappearing" +] - added
Input schema / properties / file_pathAdded value: +{ + "description": "set_picture: absolute path of a local JPEG, PNG or WebP", + "minLength": 1, + "type": "string" +} - changed
Input schema / properties / participant_ids / descriptionPrevious value: -"Targets of add/remove/promote/demote"New value: +"Targets of add/remove/promote/demote/approve_join_requests/reject_join_requests" - added
Input schema / properties / urlAdded value: +{ + "description": "set_picture: public http(s) URL to fetch and use as the photo", + "format": "uri", + "type": "string" +} - changed
Input schema / properties / value / descriptionPrevious value: -"New subject or description"New value: +"New subject or description; \"on\"/\"off\" for set_announcement_only, set_info_locked, set_join_approval; \"admins\"/\"all\" for set_add_mode; \"off\"/\"24h\"/\"7d\"/\"90d\" for set_disappearing"
- Changed
read_messages1 field changed- changed
Input schema / properties / types / items / enumPrevious value: -[ - "text", - "image", - "video", - "audio", - "voice", - "document", - "sticker", - "location", - "contact", - "poll", - "reaction", - "deleted", - "view_once", - "call", - "system", - "unknown" -]New value: +[ + "text", + "image", + "video", + "audio", + "voice", + "document", + "sticker", + "location", + "contact", + "poll", + "reaction", + "deleted", + "view_once", + "call", + "event", + "invite", + "system", + "unknown" +]
- Added
recall - Added
remove_contact - Added
save_contact - Changed
search_contacts3 fields changed- changed
Input schema / properties / query / descriptionPrevious value: -"Name fragment or phone number (at least 2 characters)"New value: +"Name fragment, phone number, or tag/detail text (at least 2 characters). Omit with tag to list everyone carrying it." - added
Input schema / properties / tagAdded value: +{ + "description": "Only contacts filed under this tag (\"client\"); \"#\" optional", + "minLength": 1, + "type": "string" +} - removed
Input schema / requiredRemoved value: -[ - "query" -]
- Changed
search_messages1 field changed- changed
Input schema / properties / from / descriptionPrevious value: -"Only messages this person sent: \"me\", a contact id or a phone number"New value: +"Only messages this person sent: \"me\", a phone number, a contact/chat id, or a name that resolves to exactly one person (the error names the candidates when it does not)"
- Changed
send_message1 field changed- changed
Input schema / properties / mention_ids / descriptionPrevious value: -"Chat ids to @-mention; include their names in the text yourself"New value: +"Chat ids to @-mention; write @<number> in the text for each, or wazap adds it at the end"
- Added
update_contact_details
33 tool updates
v0.15.0- Added
confirm_send - Changed
create_group1 field changed- added
Input schema / properties / account_idAdded value: +{ + "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.", + "minLength": 1, + "type": "string" +}
- Changed
delete_message1 field changed- added
Input schema / properties / account_idAdded value: +{ + "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.", + "minLength": 1, + "type": "string" +}
- Changed
download_media1 field changed- added
Input schema / properties / account_idAdded value: +{ + "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.", + "minLength": 1, + "type": "string" +}
- Changed
edit_message1 field changed- added
Input schema / properties / account_idAdded value: +{ + "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.", + "minLength": 1, + "type": "string" +}
- Changed
forward_message1 field changed- added
Input schema / properties / account_idAdded value: +{ + "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.", + "minLength": 1, + "type": "string" +}
- Changed
get_contact1 field changed- added
Input schema / properties / account_idAdded value: +{ + "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.", + "minLength": 1, + "type": "string" +}
- Changed
get_group_info1 field changed- added
Input schema / properties / account_idAdded value: +{ + "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.", + "minLength": 1, + "type": "string" +}
- Changed
get_message1 field changed- added
Input schema / properties / account_idAdded value: +{ + "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.", + "minLength": 1, + "type": "string" +}
- Changed
get_recent_messages3 fields changed- added
Input schema / properties / account_idAdded value: +{ + "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.", + "minLength": 1, + "type": "string" +} - added
Input schema / properties / compactAdded value: +{ + "default": false, + "description": "Leave out media without a caption and messages with no words in them, fold what one person sent in a row into one line, and say per chat what was left out. About half the size; use it for a routine catch-up", + "type": "boolean" +} - added
Input schema / properties / include_previewsAdded value: +{ + "default": false, + "description": "Attach a small JPEG of each photo, newest first, up to 12 per call, so you can see what was sent: the preview WhatsApp shipped when there is one, otherwise the photo is downloaded once and shrunk on the machine running wazap", + "type": "boolean" +}
- Changed
get_status2 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / account_idAdded value: +{ + "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.", + "minLength": 1, + "type": "string" +}
- Added
get_stories - Added
get_unanswered - Changed
learn2 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / account_idAdded value: +{ + "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.", + "minLength": 1, + "type": "string" +}
- Added
link_account - Added
list_accounts - Changed
list_chats1 field changed- added
Input schema / properties / account_idAdded value: +{ + "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.", + "minLength": 1, + "type": "string" +}
- Changed
manage_chat1 field changed- added
Input schema / properties / account_idAdded value: +{ + "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.", + "minLength": 1, + "type": "string" +}
- Changed
manage_group1 field changed- added
Input schema / properties / account_idAdded value: +{ + "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.", + "minLength": 1, + "type": "string" +}
- Added
mark_handled - Changed
react_to_message1 field changed- added
Input schema / properties / account_idAdded value: +{ + "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.", + "minLength": 1, + "type": "string" +}
- Changed
read_messages2 fields changed- added
Input schema / properties / account_idAdded value: +{ + "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.", + "minLength": 1, + "type": "string" +} - added
Input schema / properties / include_previewsAdded value: +{ + "default": false, + "description": "Attach a small JPEG of each photo, newest first, up to 12 per call, so you can see what was sent: the preview WhatsApp shipped when there is one, otherwise the photo is downloaded once and shrunk on the machine running wazap", + "type": "boolean" +}
- Changed
search_contacts1 field changed- added
Input schema / properties / account_idAdded value: +{ + "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.", + "minLength": 1, + "type": "string" +}
- Changed
search_messages4 fields changed- added
Input schema / properties / account_idAdded value: +{ + "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.", + "minLength": 1, + "type": "string" +} - added
Input schema / properties / fromAdded value: +{ + "description": "Only messages this person sent: \"me\", a contact id or a phone number", + "minLength": 1, + "type": "string" +} - added
Input schema / properties / sinceAdded value: +{ + "description": "Only messages from this moment on: a date (\"2026-09-01\") or an ISO timestamp", + "minLength": 4, + "type": "string" +} - added
Input schema / properties / untilAdded value: +{ + "description": "Only messages up to this moment: a date or an ISO timestamp", + "minLength": 4, + "type": "string" +}
- Changed
send_location1 field changed- added
Input schema / properties / account_idAdded value: +{ + "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.", + "minLength": 1, + "type": "string" +}
- Changed
send_media2 fields changed- added
Input schema / properties / account_idAdded value: +{ + "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.", + "minLength": 1, + "type": "string" +} - added
Input schema / properties / as_gifAdded value: +{ + "default": false, + "description": "Send a .gif or an mp4 as a looping GIF, the way WhatsApp plays them", + "type": "boolean" +}
- Changed
send_message1 field changed- added
Input schema / properties / account_idAdded value: +{ + "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.", + "minLength": 1, + "type": "string" +}
- Changed
send_poll1 field changed- added
Input schema / properties / account_idAdded value: +{ + "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.", + "minLength": 1, + "type": "string" +}
- Added
set_contact_note - Added
set_profile_picture - Changed
sync_contacts2 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / account_idAdded value: +{ + "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.", + "minLength": 1, + "type": "string" +}
- Changed
transcribe_audio1 field changed- added
Input schema / properties / account_idAdded value: +{ + "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.", + "minLength": 1, + "type": "string" +}
- Added
wait_for_messages
4 tool updates
v0.10.0- Changed
get_recent_messages2 fields changed- added
Input schema / properties / include_systemAdded value: +{ + "default": false, + "description": "Include WhatsApp's own system notices, which are excluded from the bodies and the counts by default", + "type": "boolean" +} - added
Input schema / properties / typesAdded value: +{ + "description": "Keep only these message types; omit for every type. The limit counts matching messages, so [\"call\"] returns that many calls, not that many messages of which some are calls.", + "items": { + "enum": [ + "text", + "image", + "video", + "audio", + "voice", + "document", + "sticker", + "location", + "contact", + "poll", + "reaction", + "deleted", + "view_once", + "call", + "system", + "unknown" + ], + "type": "string" + }, + "type": "array" +}
- Changed
read_messages1 field changed- added
Input schema / properties / typesAdded value: +{ + "description": "Keep only these message types; omit for every type. The limit counts matching messages, so [\"call\"] returns that many calls, not that many messages of which some are calls.", + "items": { + "enum": [ + "text", + "image", + "video", + "audio", + "voice", + "document", + "sticker", + "location", + "contact", + "poll", + "reaction", + "deleted", + "view_once", + "call", + "system", + "unknown" + ], + "type": "string" + }, + "type": "array" +}
- Added
sync_contacts - Added
transcribe_audio
22 tool updates
v0.9.3- First observed
create_group - First observed
delete_message - First observed
download_media - First observed
edit_message - First observed
forward_message - First observed
get_contact - First observed
get_group_info - First observed
get_message - First observed
get_recent_messages - First observed
get_status - First observed
learn - First observed
list_chats - First observed
manage_chat - First observed
manage_group - First observed
react_to_message - First observed
read_messages - First observed
search_contacts - First observed
search_messages - First observed
send_location - First observed
send_media - First observed
send_message - First observed
send_poll
TDQS
Scored across 20 tools
Most tools have clearly distinct purposes (e.g., send_message vs. confirm_send vs. edit_message vs. delete_message are well-separated by lifecycle stage). However, manage_chat and manage_group both handle 'manage' actions across different resources, and get_message vs. read_messages could cause minor confusion despite different scopes.
The naming is predominantly verb_noun (get_status, list_chats, read_messages, send_message, edit_message, delete_message, find_contact, get_group_info, get_media). Minor deviations: 'learn', 'catch_up', 'remember', 'wait_for_messages' are less pattern-consistent but still readable and purposeful.
20 tools is on the higher end but justified for a WhatsApp integration covering accounts, chats, groups, messages, media, contacts, and search. Each tool addresses a distinct operation, though a few could potentially be consolidated (e.g., manage_chat and manage_group are broad).
The tool surface covers the full messaging lifecycle: linking accounts, listing/reading/searching messages, drafting/sending/editing/reacting/deleting, chat and group management, contact resolution, media retrieval, and catch-up. The inclusion of learn, get_status, and wait_for_messages fills operational gaps that agents would otherwise hit.
Maintenance
Related MCP Connectors
WhatsMCP connects Claude and other MCP-compatible AI agents directly to WhatsApp. Send and receive text, images, documents, and voice notes; manage groups (create, add/remove members, promote admins); look up contacts and profiles; follow channels; and read call and message history — all through a standard MCP interface. For voice use cases, WhatsMCP offers SIP-based calling plans (inbound-only, or full inbound/outbound) so AI voice agents can answer and place WhatsApp calls, plus low-latency WebSocket integrations with voice agent providers like ElevenLabs. Multiple WhatsApp accounts can be paired and managed per workspace, with webhook support for real-time inbound message delivery to your own infrastructure.
Drive WhatsApp from any MCP client: pair devices, send text and media, manage contacts and groups.
Your own WhatsApp as an MCP server: read, search and send from any MCP client.
MCP server connecting AI agents to 100+ apps (Gmail, Slack, Notion, GitHub) via one-click OAuth.
Related MCP Servers
- FlicenseNot gradedqualityBmaintenanceWhatsApp MCP server that exposes messaging, groups, contacts, and profile management as tools and resources for AI agents, supporting Baileys and Meta Cloud API.23-
- AlicenseNot gradedqualityAmaintenanceA self-hosted WhatsApp bridge that exposes a stdio MCP server with ~20 tools for reading conversations, sending messages, managing groups, contacts, and aliases, enabling AI agents to operate WhatsApp directly.3MIT
- AlicenseNot gradedqualityCmaintenanceMCP server that connects AI agents to WhatsApp using the multi-device API, enabling messaging, group management, and more as a regular user.10 npmMIT
- AlicenseNot gradedqualityBmaintenanceA native MCP server for SocialMate that gives your AI a WhatsApp, enabling it to send and read messages, manage contacts and groups, and more through 44 tools.14 npm1MIT