Skip to main content
Glama
razvangirgiz

wazap-mcp

by razvangirgiz
╭───────────────╮
│        ▄██▀   │   ██╗    ██╗ █████╗ ███████╗ █████╗ ██████╗
│      ▄██▀     │   ██║    ██║██╔══██╗╚══███╔╝██╔══██╗██╔══██╗
│    ▄███████▀  │   ██║ █╗ ██║███████║  ███╔╝ ███████║██████╔╝
│       ▄██▀    │   ██║███╗██║██╔══██║ ███╔╝  ██╔══██║██╔═══╝
│     ▄█▀       │   ╚███╔███╔╝██║  ██║███████╗██║  ██║██║
╰─╮╭────────────╯    ╚══╝╚══╝ ╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝╚═╝
  ╰╯                WhatsApp for your AI agent.

npm License: MIT M8ven Score

wazap is an MCP server for your own WhatsApp account. It links as a device, the way WhatsApp Web does, keeps what it sees on your machine, and gives any MCP client — Claude, ChatGPT, Gemini, Cursor, Codex — 23 tools over your chats, messages, media, contacts and groups.

You stop opening WhatsApp to find things and ask instead:

  • "What did I miss on WhatsApp today?" — one answer across every linked account: who is waiting on you, mentions, missed calls, busy 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 notes come back as text.

  • "Tell Ana I'll be twenty minutes late." — you see the recipient and the exact words first. Nothing leaves until you say yes.

No browser, no business account, no third-party service. There is no wazap cloud: it runs where you run it.

Get started

You need Node.js 22.16+ on the 22 line, or 24+, and a phone with WhatsApp.

npx wazap-mcp setup

setup links your account, finds the MCP clients installed on this machine (Claude Code, Claude Desktop, Cursor, Codex, Gemini CLI), writes their config, installs the five skills where the client reads them, and tells you what to restart. Then ask your assistant: "what did I miss on WhatsApp today?"

Rather let your agent do it? Paste this into it:

Set up WhatsApp for me: run npx wazap-mcp setup --agent and follow what it prints.

npx wazap-mcp on its own, in a terminal, starts nothing: it prints where you stand and the next command. When something is off, npx wazap-mcp status is the first thing to run; it prints a fix next to anything broken.

Per client

Client

Fastest path

Claude Code

/plugin marketplace add razvangirgiz/wazap, then /plugin install wazap@wazap

Claude Desktop

download wazap-<version>.mcpb from Releases and double-click it

Cursor

the badge below, then npx wazap-mcp skills install cursor

Codex CLI

npx wazap-mcp connect codex, then npx wazap-mcp skills install codex

Gemini CLI

npx wazap-mcp connect gemini

claude.ai, ChatGPT, other hosted agents

a URL they sign in to with OAuth: see Remote access

Anything else

command npx -y wazap-mcp, transport stdio

Install in Cursor

The hand-written entry, for any client that takes the usual JSON:

{
  "mcpServers": {
    "whatsapp": { "command": "npx", "args": ["-y", "wazap-mcp"] }
  }
}

Every step setup takes, each file connect writes, and upgrading are in docs/install.md.

Related MCP server: wa-bridge

Linking your account

Linking is a one-time step. setup does it for you; on its own it is:

npx wazap-mcp login                      # QR code: Settings → Linked devices → Link a device
npx wazap-mcp login --phone +15550100    # pairing code instead, no camera needed

With --phone, wazap prints an 8-character code. On the phone, go to WhatsApp → Settings → Linked devices → Link a device → Link with phone number instead and type it in. The pairing code works over SSH and on a headless server, where a QR is impractical.

An assistant can link the account itself, too: the link_account tool returns the same code, so a Claude Desktop user never needs a terminal.

Several WhatsApp accounts can live in one wazap (wazap account add <id>, then wazap login --account <id>); see docs/accounts.md.

The 23 tools

What every argument means, and every error code, is in docs/tools.md. The assistant gets all of it by calling learn.

Tool

Kind

What it does

learn

read

The guide to every tool, id format, workflow and error code. Call it first.

get_status

read

Connection, sync, linked accounts, how fresh the history is, webhook delivery, versions.

link_account

read

Link an account from the assistant; returns the 8-character code to type into the phone.

list_chats

read

Conversations newest-first: all, unread, groups, individual or archived.

read_messages

read

One chat, paging back into the phone's history; chat_id: "status" reads the stories.

catch_up

read

"What did I miss?" across every account, in one call and within a token budget.

search

read

Messages by meaning and by words at once, narrowed by chat, sender or date.

get_message

read

One message in full: its quote, reactions and who left them, poll votes, delivery and read receipts.

find_contact

read

Who "mama", a nickname, a group name or a number means, before anything is drafted.

list_contacts

read

The phone's address book a page at a time: saved name, number, when you last talked.

get_group_info

read

Participants, admins, group settings, the invite link for an admin.

get_media

read

A voice note as its transcript, a photo as an image, any file saved to disk; served from the copy kept on arrival first.

wait_for_messages

read

Block up to 55 s until a message arrives, with a cursor so nothing is missed between calls.

remember

local

A note, tags or details about a person, kept on this machine. Nothing changes on WhatsApp.

send_message

write

Draft a message, media, poll, location or forward — and send nothing. send_at drafts it for a later time.

confirm_send

write

Send that draft, once, after the user has seen the preview and said yes; a draft for later is scheduled.

edit_message

write

Edit your own message, within WhatsApp's 15-minute window.

react_to_message

write

Add or remove an emoji reaction.

delete_message

write

Delete for everyone (your own message, or anyone's in a group you admin), or only on this account.

manage_chat

write

Archive, pin, mute, mark read or unread, star, clear, delete, block.

manage_group

write

Create, join, rename, add, remove, promote, invite links, join requests, settings, leave.

scheduled_messages

write

List the scheduled messages (sent, missed, failed too) or cancel one before it goes.

reminder

local

"Remind me if Ana has not answered in 2 days": set, list or cancel; posted to your webhook when due.

Scheduled messages and reminders. send_message with send_at ("tomorrow at 9" as 2026-10-12T09:00 in Europe/Bucharest) drafts a message for later; the user's yes to that preview, time included, schedules it, and every send check runs again when it goes. One wazap could not send within 15 minutes of its time is reported as missed, never sent late. reminder keeps "remind me if Ana has not answered in 2 days" and posts it to your webhook when due. Both survive restarts; see Scheduling a message and Reminders.

Two features are off by default and can run entirely on your machine: voice transcription with whisper.cpp (docs/voice.md) and semantic recall, so search matches meaning and not only words (docs/recall.md). Turn them on with wazap config transcribe local and wazap config recall local.

Skills

Tools say what is possible; the five Agent Skills in skills/ say how to do the job well.

Skill

What the agent does

whatsapp-inbox

Triage: needs you / FYI / noise, plus replies you forgot. Read-only.

whatsapp-recall

Find an address, an invoice, a photo, a thing someone said. Read-only.

whatsapp-groups

Catch up on a busy group: decisions, dates, what is asked of you. Read-only.

whatsapp-send

Find who you mean, draft in the chat's own tone, show it, send on a yes.

wazap-setup

Diagnose, link or repair the connection.

setup installs them for Claude Code, Codex and Cursor (npx wazap-mcp skills install <harness> does it by hand). Every other client gets the same five as MCP prompts from the server, with nothing to install.

Transports

stdio is the default: the client starts npx -y wazap-mcp and talks to it over stdin/stdout. Nothing listens on the network.

HTTP (Streamable HTTP) is for a server that outlives the client, or one another machine reaches:

npx wazap-mcp serve --http                 # http://127.0.0.1:8766/mcp, health at /healthz

--host/--port (or WAZAP_HOST/WAZAP_PORT) move it. wazap refuses to bind anything but loopback without WAZAP_READ_TOKEN. Clients authenticate with a static bearer token (WAZAP_READ_TOKEN, plus WAZAP_WRITE_TOKEN for the write tools) or with OAuth 2.1, which wazap serves itself. Details in docs/self-host.md.

Remote access

Two commands keep wazap running and reachable from hosted agents:

npx wazap-mcp service install   # a launchd agent (macOS) or systemd user unit (Linux)
npx wazap-mcp expose            # a public https URL through Tailscale Funnel or Cloudflare Tunnel

expose prints the URL and a consent password. Give the agent only the URL; it registers itself, and the consent page asks you for the password and whether that agent may only read or also send. See Keep it running.

The service recovers by itself: a dropped link is retried with backoff, a watchdog replaces a socket that went dead across a sleep or stopped answering, and when reconnecting keeps failing wazap exits so launchd or systemd starts it fresh. The linked session is never deleted for any of that; only WhatsApp unlinking the device needs a new link. Set WAZAP_WEBHOOK_EVENTS to include alert to be told when the link has been down for 5 minutes, when it is back, and when it needs linking again (Link alerts); get_status shows the same under link.

Deployment

On a server of your own, the session never leaves it. With Docker (images for amd64 and arm64 at ghcr.io/razvangirgiz/wazap):

mkdir wazap && cd wazap
curl -fsSLO https://raw.githubusercontent.com/razvangirgiz/wazap/main/docker-compose.yml
printf 'WAZAP_READ_TOKEN=%s\nWAZAP_WRITE_TOKEN=%s\n' $(openssl rand -hex 32) $(openssl rand -hex 32) > .env
docker compose run --rm wazap login --phone +15550100   # once; the session lands in the volume
docker compose up -d
curl -s http://127.0.0.1:8766/healthz

The container publishes port 8766 on loopback only; put TLS in front (deploy/Caddyfile is two lines). A systemd unit is in deploy/wazap.service. Both setups, reverse-proxy trust and the OAuth server are in docs/self-host.md. Calling wazap from your own product, and receiving signed webhooks for incoming messages, is in docs/api-and-webhooks.md.

Configuration

Every setting is optional. They are environment variables, read from the process or from ~/.wazap/.env (a real environment variable wins, a flag wins over both). You rarely edit them by hand: wazap config shows the effective settings and changes one.

Setting

Default

What it does

WAZAP_DATA_DIR

~/.wazap

Where credentials, databases and models live (--data-dir too).

WAZAP_READ_ONLY

unset

1 does not register the write tools at all. wazap config writes on|off.

WAZAP_PERSIST_HISTORY

1

0 keeps no messages on disk across restarts.

WAZAP_HOST / WAZAP_PORT

127.0.0.1 / 8766

Where serve --http listens.

WAZAP_READ_TOKEN / WAZAP_WRITE_TOKEN

unset

Static bearer tokens for HTTP; only the write token gets the write tools.

WAZAP_PUBLIC_URL / WAZAP_OAUTH_PASSWORD

unset

Both together turn on OAuth for hosted agents. wazap expose sets them.

WAZAP_TRANSCRIBE

off

local (whisper.cpp) or openai (an OpenAI-compatible API).

WAZAP_RECALL

off

local turns on semantic search with a local embedding model.

WAZAP_WEBHOOK

off

on posts incoming messages to WAZAP_WEBHOOK_URL, signed with WAZAP_WEBHOOK_SECRET.

WAZAP_MEDIA_KEEP

unmuted

Which chats' media is downloaded on arrival and kept, so get_media outlives WhatsApp's copy: unmuted, all, chats or off. Limits: WAZAP_MEDIA_KEEP_MAX_MB, WAZAP_MEDIA_KEEP_QUOTA_MB, WAZAP_MEDIA_KEEP_DAYS.

The full list, including the webhook filters, kept-media limits, retention and proxy trust, is in docs/settings.md; .env.example is the same list as a commented file.

Security and privacy

  • Nothing is sent without a yes. send_message only drafts: it returns the recipient and the exact text and touches no network. Only confirm_send sends, and a draft goes out at most once, even across a crash. Draft-then- confirm is a workflow, not proof of consent: an agent can call both tools unless your client makes you approve the second one.

  • Read-only is a real switch. With WAZAP_READ_ONLY=1, --read-only or wazap config writes off, the write tools are not registered, so the assistant cannot message anyone even by mistake. The Claude Desktop bundle ships with read-only ticked.

  • Recipients can be pinned. wazap config send allow +15550100,… limits an account to a list, deny refuses the ones named; both are checked at draft and again at send (docs/send-rules.md).

  • Writes are rate limited, 20 a minute per account by default, because sending faster than a human is how numbers get banned.

  • Your data stays on your machine. Credentials, messages, media and notes live in ~/.wazap (0700, credential files 0600). No account, no telemetry. What leaves the machine: WhatsApp traffic; the npm registry, for the version check; Hugging Face, when you download a transcription or embedding model; a transcription API, only if you chose openai; your own webhook, if you set one (docs/data.md).

  • Some people can be kept out. Tag a contact #private and their words stay out of everything the assistant did not ask about them by name, and out of the webhook. #no-catchup keeps their chat out of catch_up.

  • What it does not do. No bulk send, no scheduler, no campaigns. It never marks anything read on its own, and sends text without link previews, so nothing fetches the pages you link.

Threat model, findings and the limits of each of these: docs/security-audit.md.

Known limitations

  • The protocol is unofficial. wazap is built on Baileys, a reverse-engineered implementation of WhatsApp's multi-device protocol. It is not the WhatsApp Business API and Meta does not support it. A protocol change can break wazap until Baileys catches up, and an account that sends in bulk or to people who did not ask can be restricted or banned. The safeguards above reduce that risk; they do not remove it, and the risk is yours.

  • Model behaviour is measured on Claude only. The evaluation in eval/ (58 cases, each run three times) has been run on Claude. Other clients get the same tools and the same server-side guards, but nobody has measured how their models use them. The manual protocol for ChatGPT is eval/chatgpt-protocol.md.

  • History is what the phone syncs to a linked device, not your whole archive. read_messages with before asks the phone for more, within what WhatsApp still keeps.

  • Old media expires. WhatsApp drops old attachments from its servers; get_media then returns MEDIA_UNAVAILABLE, unless wazap kept a copy when it arrived. By default it keeps the photos, voice notes, audio and documents of unmuted chats, up to 16 MB each, 1 GB in all and 90 days, while wazap serve runs; media that arrived and expired while nothing was keeping it cannot be brought back.

  • Names come from the phone's address book, which WhatsApp only sends to a fresh connection. If contacts read as numbers (contacts_named: 0 in get_status), wazap contacts resync asks again while no server runs.

  • @lid ids. Newer accounts are addressed by a privacy id; wazap maps it back to a number when it has learned the mapping.

  • Calls are WhatsApp calls only, and a call that starts and ends while wazap is stopped may be missing. Cellular calls are never visible.

  • The phone must stay reachable. A linked device stops receiving once the phone has been offline too long; get_status says so.

What the 1.x line promises not to break is in docs/stability.md.

Documentation

docs/install.md

setup step by step, each client, the background service, expose, upgrading, skills

docs/tools.md

The 23 tools in full, the workflows, every error code

docs/accounts.md

Several WhatsApp accounts, several MCP clients on one server

docs/voice.md

Voice notes as text: whisper.cpp locally, or an OpenAI-compatible API

docs/recall.md

Semantic search with a local embedding model

docs/data.md

The data directory, wazap backup, retention, deleted and disappearing messages

docs/send-rules.md

Read-only mode, per-account send rules, rate limits

docs/self-host.md

HTTP mode, systemd, Docker, tunnels, proxy trust, OAuth

docs/api-and-webhooks.md

Static tokens in, signed webhook events out

docs/settings.md

Every WAZAP_* setting and its default

docs/security-audit.md

The security audit

docs/stability.md

What 1.0 promises to keep stable

CHANGELOG.md

Release by release

Contributing

git clone https://github.com/razvangirgiz/wazap && cd wazap
npm ci
npm run check                  # lint, typecheck, then build and test
node test/smoke-stdio.mjs      # drives the built binary over MCP stdio
npm run dev -- status          # run from source with tsx

The tests need no WhatsApp account. CLAUDE.md is the contributor's map: layout, the rules that must never break, and the release procedure. Issues and pull requests are welcome at github.com/razvangirgiz/wazap.

License

MIT © Răzvan Girgiz

Available Tools

23 tools
catch_upCatch up on what the user missedA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
hoursNoThe last N hours instead; never moves the mark
sinceNo"last" (default); "previous" repeats that catch-up; or an ISO date or time from the last 14 days
cursorNomore.cursor
includeNoOnly these sections; the mark then stays
account_idNoAccount id
budget_tokensNoAnswer length in tokens

Output Schema

ParametersJSON Schema
NameRequiredDescription
moreYesSet when entries are left: call catch_up again with more.cursor
notesNoCaveats to act on or tell the user
directYes
footerYesOn the last page: what the entries leave out
groupsYes
windowYes
storiesYes
waitingYes
accountsYes
addressedYes
account_idYes
missed_callsYes
approx_tokensYes

TDQS

A3.6/5.0
Behavior4/5

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.

Conciseness2/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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 messageA
Idempotent

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
draft_idYesFrom send_message; one with send_at is scheduled, not sent
account_idNoAccount id

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare write/idempotent/non-destructive, so the bar is lower, but the description still adds real value: the once-per-draft guarantee, the 'never redo it unasked' rule, and the outcome-unknown recovery path. It stops short of disclosing auth needs or the concrete response payload, keeping it from a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four dense, front-loaded sentences each carrying distinct actionable content with no filler. The telegraphic fragments ('A yes about something else:', 'Expired, missing or stale:') are efficient but slightly terse to parse.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a write tool with no output schema, the definition covers the critical edge cases an agent would otherwise mishandle: stale drafts, re-previewing before resend, and the unknown-outcome branch. Little is missing given the annotations already cover the safety profile.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and both parameters are documented there, including the scheduled-vs-sent nuance on draft_id. The description adds only the loose framing 'this text, this recipient' for what a draft binds, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Send a draft the user approved') with the exact scope ('this text, this recipient') and explicitly claims exclusivity ('the only call that sends, once per draft'), which separates it from send_message and scheduled_messages. An agent can identify the tool's role without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use (user approved this draft), when-not ('A yes about something else: show the preview again and ask'), and recovery paths for expired/missing/stale drafts plus the SEND_OUTCOME_UNKNOWN branch pointing to read_messages. Alternatives and preconditions are named rather than inferred.

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 messageA
DestructiveIdempotent

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
account_idNoAccount id
message_idYes
for_everyoneYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
account_idYes
message_idYes
for_everyoneYes

TDQS

A4.4/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 sentA
DestructiveIdempotent

Replace the text of a message the linked account sent. WhatsApp allows it for 15 minutes after sending; later, send a correction instead.

ParametersJSON Schema
NameRequiredDescriptionDefault
textYes
account_idNoAccount id
message_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
textYes
chat_idYes
timestampYes
account_idYes
message_idYes

TDQS

A4/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 meansA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagNoList everyone filed under this tag instead
kindNoany
nameNoWhat the user calls them ("Ana", "mamei", "fotbal"), or a number or id
limitNoAmbiguous: at most 5 per account; a tag list: up to 50
qualifierNoTells two apart: "contabilitate", a group, the last 4 digits
account_idNoAccount id
include_contextNoRecent messages and the user's style, when resolved in a write session

Output Schema

ParametersJSON Schema
NameRequiredDescription
fixNoWhat to do next, when not resolved
nextNoResolved: how a message to them starts
notesNoCaveats to act on or tell the user
queryYes
statusYes
closestNoOnly when not_found
contactNoOnly when resolved
contextNoOnly when resolved, in a session that can write: what a draft to them is written after
omittedNoOnly when listed and cut by limit: how many more on each account
contactsNoOnly when listed: everyone filed under the tag
can_draftNoResolved in a session that cannot send
account_idNoThe account that answered; null when several accounts were searched and none answered alone
candidatesNoOnly when ambiguous; best first
accounts_searchedNo
accounts_unavailableNo

TDQS

A4.3/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 infoA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
group_idYes<id>@g.us
account_idNoAccount id

Output Schema

ParametersJSON Schema
NameRequiredDescription
nameYes
ownerYes
chat_idYes
communityNo
account_idYes
created_atYes
i_am_adminYes
descriptionYes
info_lockedYes
invite_linkNo
participantsYes
join_approvalYes
member_add_modeYes
announcement_onlyYes
participant_countYes
disappearing_secondsYes

TDQS

A4.5/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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 messageC
Read-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; a copy kept on arrival answers first. MEDIA_UNAVAILABLE: gone, none kept.

ParametersJSON Schema
NameRequiredDescriptionDefault
save_toNoAbsolute directory; default <data-dir>/media. A recording: its file, and no new transcript
languageNoWhat is spoken, e.g. "ro"
account_idNoAccount id
message_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
mimeNo
pathNo
sizeNo
typeYes
senderYes
sourceNokept: the copy wazap kept when it arrived; whatsapp: downloaded now
captionYes
filenameNoThe name it was saved under
account_idYes
message_idYes
transcriptNo
image_attachedNoThe photo, or a small preview of it, is attached
original_filenameYes
transcript_unavailableNo

TDQS

C2.3/5.0
Behavior1/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare readOnlyHint=true, meaning the tool should not modify its environment. The description explicitly says files can be saved to disk via save_to ('any file saved at path on the machine running wazap') and that transcripts are created and billed ('kept once made; an API provider bills it'), which are environment-modifying side effects. This directly contradicts the readOnlyHint annotation. Although the description does add useful error context (MEDIA_UNAVAILABLE), the contradiction forces a score of 1.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a dense, run-on sentence with semicolons that reads like internal shorthand rather than structured documentation. It is not front-loaded with a clear purpose statement, and the parenthetical asides make it hard to parse. While not excessively long, its structure impedes quick comprehension.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has an output schema, so return values need not be described. The description covers some behavioral details (transcript caching/billing, save_to effects, MEDIA_UNAVAILABLE error), but it is incomplete for a 4-parameter tool with no usage guidance, and its behavioral claims conflict with the readOnlyHint annotation. It leaves key questions unanswered, such as account_id semantics and whether saving files affects the annotation contract.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 75%, so the schema already documents most parameters (save_to, language, account_id). The description adds marginal behavioral context for save_to ('its file, and no new transcript') and indirectly for language (transcript generation), but does not explain message_id or account_id. With high schema coverage, baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose3/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description conveys that the tool returns media content (transcripts, files, images) for a message, but it does so in a convoluted, note-like way rather than stating a clear verb+resource. The title supplies the missing 'Get the media of a WhatsApp message' framing, yet the description does not explicitly differentiate this from sibling tools like get_message or read_messages.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no explicit guidance on when to use this tool versus alternatives. The description implies usage (when a message has media) but never states conditions, prerequisites, or when to prefer get_message/read_messages instead. An agent must infer that this is the media-retrieval counterpart to text retrieval.

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 fullA
Read-onlyIdempotent

One message in full, its words never cut: 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.

ParametersJSON Schema
NameRequiredDescriptionDefault
account_idNoAccount id
message_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
textYes
chat_idYes
timestampYes
account_idYes
message_idYes

TDQS

A3.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish read-only, idempotent, non-destructive, open-world behavior, and the description goes beyond them by disclosing the cross-account lookup fallback when account_id is absent and by characterizing the rich payload returned. It omits any mention of permissions, rate limits, or cost of that multi-account scan, keeping it from a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is a single long, dense sentence, front-loaded with the core claim 'One message in full,' which is good. However, much of the enumeration (reactions, poll votes, media, read receipts) restates what the output schema already provides, so several clauses do not fully earn their place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With annotations covering the safety profile and an output schema covering return values, the return-content enumeration is largely redundant and the real gaps remain: no guidance on when to use this versus read_messages or search. The account_id fallback is the one piece of essential context supplied.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 50%: account_id has a bare 'Account id' string while message_id is undocumented. The sentence 'Without account_id the id is looked for on every account' genuinely adds semantics for account_id, but message_id (the only required param) gets nothing beyond the schema, so compensation is only partial.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The resource is unambiguous ('one WhatsApp message in full') and the description enumerates exactly what 'in full' means: quoted message, reactions with authors, poll votes, media, and read receipts. The verb is only implied (the name/title supply 'get'), and no sibling such as search or read_messages is named to sharpen the distinction, so it lands short of a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied rather than stated: an agent can infer 'call this when you have a specific message_id and need the complete message.' The one real guideline is the account_id fallback ('the id is looked for on every account'), but there is no when-not-to-use or pointer to alternative retrieval tools.

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 statusA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
account_idNoAccount id
include_pictureNoAdd picture_url, the account's own profile photo (the link expires)

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive/closed-world, so the safety profile is covered. The description adds real behavioral context beyond them: it enumerates the diagnostic fields returned (sudo state codes, sync progress, history freshness, webhook delivery, versions) and notes that accounts includes the default.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Dense and front-loaded — it leads with what the tool reveals, then the trigger states. It reads as a stack of fragments and the trailing ellipsis in 'linking with its pairing code…' is sloppy, but every clause carries information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the burden of explaining the return payload and does so reasonably: state, sync, history freshness, webhook status, versions, accounts. It omits response structure and whether account_id defaults to the default account, but the essentials for calling and interpreting it are present.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and both parameters (account_id, include_picture with its link-expiry note) are documented in the schema itself. The description adds no parameter semantics beyond the structured fields, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific resource and enumerates exactly what the status covers: connection state, sync, history freshness, webhook delivery, versions, and the accounts list. No sibling tool in the set overlaps with this, so explicit differentiation is unnecessary, though no sibling is named either.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit trigger condition: 'Call it on NOT_CONNECTED, NOT_LINKED or SYNC_IN_PROGRESS.' That is clear when-to-call guidance tied to concrete state names, but it names no alternative tool or when-not-to-call scenario.

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 toolsA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
account_idNoAccount id

TDQS

A4.7/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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.

list_chatsList WhatsApp chatsA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
cursorNoOpaque next_cursor from the preceding page; keep the same filter
filterNo"all" leaves out archivedall
account_idNoAccount id
include_picturesNoAdd picture_url, each chat's profile photo (links expire)

Output Schema

ParametersJSON Schema
NameRequiredDescription
syncYes
chatsYes
countYes
filterYes
account_idYes
next_cursorNo

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, non-destructive and openWorld, so the safety profile is covered. The description adds one genuinely new behavioral fact — that results are ordered most-recently-active-first — but omits pagination behavior, and its field inventory duplicates the output schema. One added trait over the annotations lands it at 3.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences with the resource and ordering front-loaded and no filler. The field inventory is mildly redundant given the output schema exists, but it is short enough that nothing dominates.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the description needn't explain return values, and annotations cover the safety profile; purpose, usage and ordering are all stated. Only minor gaps remain (no mention of pagination or the filter option), so it is close to complete for a 5-param list tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 80% (cursor, filter and include_pictures are documented), so the schema carries the parameter burden. The description mentions archiving only in passing ('whether archived') and never explains limit, cursor paging, or the filter enum, so it adds no meaning beyond the schema — the baseline 3 for high coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description makes clear this enumerates conversations and names the identifying fields (chat_id, name, type, unread count, last message, state flags). The verb is implied rather than stated ('Conversations...'), and it doesn't explicitly distinguish itself from the sibling list_contacts, but an agent can tell it retrieves chats, not contacts.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Use it to find a chat_id' gives a concrete reason to reach for this tool, which is the main entry point before message-level tools. It stops short of naming exclusions or alternatives (e.g. search, list_contacts, read_messages) when a chat_id is already known, which keeps it from a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_contactsList the phone's address bookA
Read-onlyIdempotent

The phone's address book on one account, a page at a time: saved name, phone (E.164), chat_id, contact_id, and when the last direct message was and its direction. No message words; #private people left out. address_book_synced false: not arrived yet.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
orderNorecent: latest direct chat first, then the rest in address book orderrecent
cursorNonext from the previous page
account_idNoAccount id

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, non-destructive, open-world, so the safety profile is covered. The description goes beyond them by disclosing filtering behavior ('No message words; #private people left out') and an edge case ('address_book_synced false: not arrived yet'), which materially inform result contents.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose and returned fields are front-loaded in the first sentence, with filtering and the sync caveat appended tersely. The fragmentary phrasing ('address_book_synced false: not arrived yet') is dense but earns its place as an edge-case note; no redundant sentences.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description usefully explains what each row contains and the privacy/status caveats, which is the key missing structured information. Minor gaps remain around account_id acquisition and ordering semantics, but the core call-and-interpret picture is complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 75%, with order and cursor carrying their own descriptions, so the schema does most of the work. The description only loosely reinforces account scoping ('one account') and pagination ('a page at a time') and adds no format or default detail for limit/order beyond the schema, so a baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb (list) and resource (the phone's address book / contacts), and it enumerates the returned fields (name, phone, chat_id, contact_id, last DM time and direction), which makes the resource unambiguous. It does not explicitly name or contrast with siblings such as find_contact or list_chats, so it stops short of a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'a page at a time' implies paginated browsing and 'on one account' implies account scoping, so usage is inferable. However, there is no explicit when-to-use / when-not-to-use guidance versus find_contact (lookup) or list_chats, leaving the agent to infer routing.

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 chatA
Destructive

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
actionYes
chat_idYesChat id, or a phone number
pin_hoursNopin_message: 168 by default
account_idNoAccount id
message_idNopin_message, star_message and their undo; in chat_id
mute_hoursNomute: 8 by default

TDQS

A3.9/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines4/5

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 groupA
Destructive

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlNoset_picture: public image URL
valueNoThe name (create, set_subject) or description; "on"/"off"; set_add_mode "admins"/"all"; set_disappearing "off"/"24h"/"7d"/"90d"
actionYes
inviteNojoin: a chat.whatsapp.com link or its code
confirmNojoin: true joins, after the user said yes to the preview
group_idNo"<id>@g.us"; every action but create and join
file_pathNoset_picture: local JPEG, PNG or WebP
account_idNoAccount id
message_idNojoin: an invite message instead
participant_idsNocreate, add, remove, promote, demote, approve or reject

Output Schema

ParametersJSON Schema
NameRequiredDescription
nameNo
nextNojoin preview: the step after the user's yes
actionYes
statusNojoin: preview joins nothing
appliedNo
group_idYes
account_idYes
descriptionNo
invite_linkNo
participantsNo
join_approvalNo
join_requestsNo
profile_pic_urlNo
participant_countNo

TDQS

A4.6/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 messageA
Idempotent

React to a message with one emoji, or pass "" to take your reaction off.

ParametersJSON Schema
NameRequiredDescriptionDefault
emojiYes
account_idNoAccount id
message_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
emojiYes
account_idYes
message_idYes

TDQS

A3.8/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines3/5

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 chatA
Read-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). Long texts are cut unless full_text. chat_id "status" reads the stories people posted, newest first, from the last hours (at most a day); they show nowhere else.

ParametersJSON Schema
NameRequiredDescriptionDefault
hoursNo"status" only: how far back, 24 by default
limitNo
typesNoOnly these types; limit counts them, so ["call"] gives that many calls
beforeNoThe oldest message_id you have
chat_idYesChat id from another tool, a phone number, or "status" for stories
full_textNoEach message's text whole; a list cuts long ones otherwise
account_idNoAccount id
include_previewsNoAttach a small image of each photo, up to 12

Output Schema

ParametersJSON Schema
NameRequiredDescription
syncYes
countYes
hoursNo
notesNoCaveats to act on or tell the user
olderNobefore ran past the local history: the phone was asked, and sent this many
typesNo
chat_idYes
omittedNoOlder stories left out by limit
messagesYes
account_idYes
preview_countYes
unconfirmed_sendsNoSends WhatsApp has not echoed yet: outcome unknown, not failed

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover read-only/idempotent safety, so the bar is lower, yet the description adds real behavioral context: backfilling from the phone when local history runs out, truncation of long texts unless full_text, and that stories appear nowhere else. Default limit and account scoping are left to the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Dense but front-loaded: read scope first, then pagination, then the status special case. The parenthetical about wazap asking the phone is slightly digressive but earns its place by explaining an observable latency/backfill behavior.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be described, and annotations cover the safety profile. The description adequately covers the tool's oddities (status mode, backfill, truncation) for an 8-param reader, though it omits the default limit of 20 and the types/limit interaction wording.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 88%, so the baseline is 3, but the description adds genuinely new meaning: the fallback behavior of 'before', the 'status' value for chat_id and its hours window, and the full_text truncation toggle. Only limit/account_id add nothing beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb+resource ('Read one chat') with ordering and scope stated up front ('oldest to newest'), which tells an agent this is a single-chat reader rather than a global search. Sibling differentiation is implicit (no sibling named) but the 'chat_id "status"' carve-out usefully separates it from get_status/stories semantics.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives pagination context ('or older ones with before') and hints at the status mode ('from the last hours, at most a day'), but never says when to prefer this over get_message, search, catch_up, or list_chats. Usage is implied rather than stated.

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 personA
Idempotent

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
noteNo"" removes it
fieldsNoe.g. {"nickname": "Mișu", "role": "contabil"}; "" deletes a key
chat_idYesChat id, or a phone number
handledNoOff catch_up's waiting until they write again
add_tagsNoe.g. ["client"]
account_idNoAccount id
remove_tagsNo
remove_fieldsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
nameYes
noteNo
tagsNo
fieldsNo
numberNo
chat_idYes
handledNoThe ask taken off the waiting list; null when nothing was open
account_idYes
is_businessNo
is_my_contactNo

TDQS

A3.8/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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.

reminderSet, list or cancel a reminder about a chatA

The user's reminders about a chat, kept locally and posted to their webhook when due: create (chat_id, note, after_hours or due_at); condition "no_reply" fires only if nobody wrote there since ("if Ana has not answered in 2 days"). list, cancel. Nothing goes to WhatsApp.

ParametersJSON Schema
NameRequiredDescriptionDefault
noteNocreate: what to remind the user of
limitNo
actionNolist
due_atNocreate: due then, "2026-10-14T09:00" in time_zone, or with an offset
chat_idNocreate: the chat it is about
conditionNono_reply: skipped if someone wrote in the chat after it was setalways
time_zoneNoIANA zone for due_at; the server's by default
account_idNoAccount id
after_hoursNocreate: due this many hours from now
reminder_idNocancel: from create or list
include_closedNolist: the week's fired, skipped and cancelled ones too

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYes
notesNoCaveats to act on or tell the user
actionYes
cancelledNo
remindersYes
account_idYes

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare the generic safety profile (not read-only, not idempotent, not destructive, closed-world). The description adds real behavior beyond that: reminders are stored locally and delivered to the user's webhook when due, the no_reply condition is skipped if someone replied, and nothing is sent to WhatsApp. Storage/delivery semantics are exactly the kind of context annotations cannot carry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core identity is front-loaded in the first clause, then it moves through create, condition, and the list/cancel actions with no filler. The telegraphic fragments ('list, cancel.') and stacked parentheticals are dense but every element carries information for an 11-parameter multi-action tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return values need no explanation, and the description still covers all three actions, storage location, delivery mechanism, the condition enum, and the no-WhatsApp guarantee. Only minor gaps remain, such as whether list scopes by account_id and what cancel does to already-fired reminders.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 82%, so the baseline is 3, but the description adds meaning the schema does not encode: after_hours and due_at are alternatives for the same due time, and condition=no_reply means the reminder is suppressed if someone wrote after it was set. It also clarifies reminder_id comes from create or list.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names the resource (the user's reminders about a chat), the lifecycle operations (create/list/cancel), and the three create inputs, so an agent knows exactly what this tool manipulates. The closing line 'Nothing goes to WhatsApp' implicitly separates it from messaging siblings like scheduled_messages, though it never names that sibling outright.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear per-action context: create takes chat_id, note and either after_hours or due_at; the no_reply condition fires only if nobody wrote since; list and cancel are named. The 'Nothing goes to WhatsApp' clause signals when not to expect messaging behavior, but no alternative tool is named explicitly, so this stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

scheduled_messagesList or cancel scheduled WhatsApp messagesA
Idempotent

The account's scheduled messages: list (waiting ones soonest first, then the week's sent, missed, failed and cancelled ones) or cancel one by schedule_id before it goes. To schedule one, send_message with send_at, then confirm_send. Tell the user about every missed or failed one.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
actionNolist
account_idNoAccount id
schedule_idNocancel: from the list or confirm_send
include_closedNolist: the week's sent, missed, failed and cancelled ones too

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYes
actionYes
cancelledNo
scheduledYes
account_idYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=false, idempotentHint=true, destructiveHint=false, so the safe/idempotent profile is covered. The description adds genuine context beyond that: list ordering (waiting soonest first, then the week's sent/missed/failed/cancelled) and the recency window, plus an explicit directive to surface missed/failed messages. It stops short of stating permission requirements or what happens if the cancel window has passed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two dense sentences front-load the primary action, and the closing instruction ('Tell the user about every missed or failed one') is a behavioral requirement an agent genuinely needs. No filler or restatement of the title.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return values need not be explained, and the description adequately covers both the list and cancel branches of the enum action. Minor gaps remain around the limit parameter and error behavior for a cancel attempted too late, but nothing essential to correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 60%, and the description reinforces schedule_id's origin (from the list or confirm_send) and the meaning of the closed-message set, which matches the schema's own include_closed description. The limit parameter (default 50, max 100) is never mentioned, so the description does not fully compensate for the coverage gap. Baseline 3 is appropriate when the schema carries most parameter meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific resource (the account's scheduled messages) and two concrete verbs (list, cancel), and it explicitly distinguishes itself from the sibling tools send_message and confirm_send that handle scheduling. An agent can identify this tool's role without inspecting the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It names the alternative workflow for scheduling (send_message with send_at, then confirm_send) and the condition that selects it, plus the constraint that cancellation must happen 'before it goes.' Use vs. alternative is unambiguous.

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
asNoMedia: a plain document, a voice note, a looping GIF
urlNoMedia: public http(s) URL
textYesThe message, or the caption, poll question or place name; "" for a forward, a voice note or audio
addressNoLocation: shown under the name
chat_idYesChat id, or a phone number
forwardNoForward this message; text ""
optionsNoPoll answers
send_atNoSend later: "2026-10-12T09:00" in time_zone, or with an offset; 1 minute to 365 days ahead
latitudeNo
reply_toNo
file_pathNoMedia: absolute path on the machine running wazap
longitudeNo
time_zoneNoIANA zone for send_at, e.g. "Europe/Bucharest"; the server's by default
account_idNoAccount id
mention_idsNoChat ids to @-mention; write @<number> in text for each
multi_selectNoPoll: several answers allowed

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare this as a non-destructive write (readOnlyHint=false, destructiveHint=false), so the safety profile is covered; the description adds the genuinely behavioral facts that nothing is sent, that it returns draft_id and preview, and that a confirmation gate exists. It stops short of disclosing draft persistence/expiry or auth requirements, so it is strong but not exhaustive.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Roughly two-and-a-half sentences with zero waste: the draft/send distinction and the required inputs lead, and the confirm protocol follows. Every clause carries operational weight, and the preview-then-confirm flow is front-loaded where an agent needs it.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 16-parameter tool with no output schema, the description correctly compensates by explaining what comes back (draft_id, preview contents) and how the two-phase draft/confirm workflow proceeds. The remaining parameter surface (send_at, time_zone, mention_ids, account_id) is documented in the schema, though the description never signals scheduling or mentions at all.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is high at 81%, so the schema already carries most parameter meaning; the description's mention of media, polls, locations and forwards loosely maps to the as/options/latitude/forward groups but adds no syntax or format detail. It reinforces the required recipient+text pair but does not go beyond the structured fields.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (drafts) plus the full range of content it can produce (text, media, polls, locations, forwards) and immediately resolves the name's ambiguity with "sends nothing." It distinguishes itself from confirm_send, which is the sibling that actually sends, so an agent can tell the two apart without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit trigger ("call it as soon as you have recipient and text") and explicit routing to the alternative ("confirm_send only on a yes to this text and recipient"), including an edge case that a send in the same request counts as that yes. Nothing about when versus when-not is left to inference.

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 messagesA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
cursorNoFrom the previous call
chat_idNoChat id, or a phone number
account_idNoAccount id
addressed_to_meNo
timeout_secondsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYes
cursorYesPass to the next call
messagesYes
timed_outYes
account_idYes
cursor_resetYesThe cursor was from another run; the wait started now

TDQS

A4.8/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters5/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

  1. 1 tool updatev1.4.2
    • Changedlist_chats2 fields changed
      • addedInput schema / properties / cursor
        Added value: +{
        +  "description": "Opaque next_cursor from the preceding page; keep the same filter",
        +  "maxLength": 512,
        +  "type": "string"
        +}
      • addedOutput schema / properties / next_cursor
        Added value: +{
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
  2. 9 tool updatesv1.4.0
    • Changedconfirm_send1 field changed
      • changedInput schema / properties / draft_id / description
        Previous value: -"From send_message"New value: +"From send_message; one with send_at is scheduled, not sent"
    • Changedget_media1 field changed
      • addedOutput schema / properties / source
        Added value: +{
        +  "description": "kept: the copy wazap kept when it arrived; whatsapp: downloaded now",
        +  "enum": [
        +    "kept",
        +    "whatsapp"
        +  ],
        +  "type": "string"
        +}
    • Changedget_status1 field changed
      • addedInput schema / properties / include_picture
        Added value: +{
        +  "default": false,
        +  "description": "Add picture_url, the account's own profile photo (the link expires)",
        +  "type": "boolean"
        +}
    • Changedlist_chats1 field changed
      • addedInput schema / properties / include_pictures
        Added value: +{
        +  "default": false,
        +  "description": "Add picture_url, each chat's profile photo (links expire)",
        +  "type": "boolean"
        +}
    • Changedread_messages1 field changed
      • addedInput schema / properties / full_text
        Added value: +{
        +  "description": "Each message's text whole; a list cuts long ones otherwise",
        +  "type": "boolean"
        +}
    • Addedreminder
    • Addedscheduled_messages
    • Changedsearch1 field changed
      • addedInput schema / properties / full_text
        Added value: +{
        +  "description": "Each message's text whole; a list cuts long ones otherwise",
        +  "type": "boolean"
        +}
    • Changedsend_message2 fields changed
      • addedInput schema / properties / send_at
        Added value: +{
        +  "description": "Send later: \"2026-10-12T09:00\" in time_zone, or with an offset; 1 minute to 365 days ahead",
        +  "maxLength": 40,
        +  "minLength": 10,
        +  "type": "string"
        +}
      • addedInput schema / properties / time_zone
        Added value: +{
        +  "description": "IANA zone for send_at, e.g. \"Europe/Bucharest\"; the server's by default",
        +  "maxLength": 64,
        +  "minLength": 1,
        +  "type": "string"
        +}
  3. 1 tool updatev1.2.0
    • Addedlist_contacts
  4. 43 tool updatesv1.0.3
    • Addedcatch_up
    • Changedconfirm_send2 fields changed
      • changedInput schema / properties / account_id / description
        Previous value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id"
      • changedInput schema / properties / draft_id / description
        Previous value: -"The draft_id returned by a send_* tool"New value: +"From send_message"
    • Removedcreate_group
    • Changeddelete_message4 fields changed
      • changedInput schema / properties / account_id / description
        Previous value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id"
      • removedInput schema / properties / for_everyone / description
        Removed value: -"Required. true retracts it for everyone in the chat; false deletes it for the linked account only"
      • removedInput schema / properties / message_id / description
        Removed value: -"Message id from read_messages / search_messages / get_message, e.g. \"false_4072...@s.whatsapp.net_3EB0...\""
      • changedOutput 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"
        +}
    • Removeddownload_media
    • Changededit_message4 fields changed
      • changedInput schema / properties / account_id / description
        Previous value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id"
      • removedInput schema / properties / message_id / description
        Removed value: -"A message the linked account sent"
      • removedInput schema / properties / text / description
        Removed value: -"The replacement text"
      • changedOutput 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"
        +}
    • Addedfind_contact
    • Removedforward_message
    • Removedget_contact
    • Changedget_group_info3 fields changed
      • changedInput schema / properties / account_id / description
        Previous value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id"
      • changedInput schema / properties / group_id / description
        Previous value: -"Group chat id (\"<id>@g.us\")"New value: +"<id>@g.us"
      • changedOutput 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"
        +}
    • Addedget_media
    • Changedget_message3 fields changed
      • changedInput schema / properties / account_id / description
        Previous value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id"
      • removedInput schema / properties / message_id / description
        Removed value: -"Message id from read_messages / search_messages / get_message, e.g. \"false_4072...@s.whatsapp.net_3EB0...\""
      • changedOutput 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"
        +}
    • Removedget_recent_messages
    • Changedget_status1 field changed
      • changedInput schema / properties / account_id / description
        Previous value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id"
    • Removedget_stories
    • Removedget_unanswered
    • Removedjoin_group
    • Changedlearn1 field changed
      • changedInput schema / properties / account_id / description
        Previous value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id"
    • Changedlink_account2 fields changed
      • changedInput schema / properties / account_id / description
        Previous value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id"
      • changedInput schema / properties / phone / description
        Previous value: -"International format, e.g. +15550100"New value: +"e.g. +15550100"
    • Removedlist_accounts
    • Changedlist_chats4 fields changed
      • changedInput schema / properties / account_id / description
        Previous value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id"
      • changedInput schema / properties / filter / description
        Previous value: -"Which chats to list; \"all\" (default) excludes archived ones"New value: +"\"all\" leaves out archived"
      • removedInput schema / properties / limit / description
        Removed value: -"Maximum number of chats (1-100)"
      • changedOutput 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"
        +}
    • Changedmanage_chat6 fields changed
      • changedInput schema / properties / account_id / description
        Previous value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id"
      • removedInput schema / properties / action / description
        Removed value: -"What to do with the chat"
      • changedInput schema / properties / chat_id / description
        Previous 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"
      • changedInput schema / properties / message_id / description
        Previous 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"
      • changedInput schema / properties / mute_hours / description
        Previous value: -"Hours to mute, default 8; only used by \"mute\""New value: +"mute: 8 by default"
      • changedInput schema / properties / pin_hours / description
        Previous value: -"How long pin_message keeps the message pinned: 24, 168 (default) or 720 hours"New value: +"pin_message: 168 by default"
    • Changedmanage_group13 fields changed
      • changedInput schema / properties / account_id / description
        Previous value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id"
      • removedInput schema / properties / action / description
        Removed value: -"Group action to perform"
      • changedInput schema / properties / action / enum
        Previous 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"
        +]
      • addedInput schema / properties / confirm
        Added value: +{
        +  "default": false,
        +  "description": "join: true joins, after the user said yes to the preview",
        +  "type": "boolean"
        +}
      • changedInput schema / properties / file_path / description
        Previous value: -"set_picture: absolute path of a local JPEG, PNG or WebP"New value: +"set_picture: local JPEG, PNG or WebP"
      • changedInput schema / properties / group_id / description
        Previous value: -"Group chat id (\"<id>@g.us\")"New value: +"\"<id>@g.us\"; every action but create and join"
      • addedInput schema / properties / invite
        Added value: +{
        +  "description": "join: a chat.whatsapp.com link or its code",
        +  "maxLength": 512,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / message_id
        Added value: +{
        +  "description": "join: an invite message instead",
        +  "minLength": 5,
        +  "type": "string"
        +}
      • changedInput schema / properties / participant_ids / description
        Previous value: -"Targets of add/remove/promote/demote/approve_join_requests/reject_join_requests"New value: +"create, add, remove, promote, demote, approve or reject"
      • changedInput schema / properties / url / description
        Previous value: -"set_picture: public http(s) URL to fetch and use as the photo"New value: +"set_picture: public image URL"
      • changedInput schema / properties / value / description
        Previous 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\""
      • changedInput schema / required
        Previous value: -[
        -  "group_id",
        -  "action"
        -]New value: +[
        +  "action"
        +]
      • changedOutput 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"
        +}
    • Removedmark_handled
    • Changedreact_to_message4 fields changed
      • changedInput schema / properties / account_id / description
        Previous value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id"
      • removedInput schema / properties / emoji / description
        Removed value: -"A single emoji such as \"👍\", or \"\" to remove your reaction"
      • removedInput schema / properties / message_id / description
        Removed value: -"Message id from read_messages / search_messages / get_message, e.g. \"false_4072...@s.whatsapp.net_3EB0...\""
      • changedOutput 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"
        +}
    • Changedread_messages8 fields changed
      • changedInput schema / properties / account_id / description
        Previous value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id"
      • changedInput schema / properties / before / description
        Previous value: -"Return the messages immediately older than this message_id"New value: +"The oldest message_id you have"
      • changedInput schema / properties / chat_id / description
        Previous 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"
      • addedInput schema / properties / hours
        Added value: +{
        +  "description": "\"status\" only: how far back, 24 by default",
        +  "maximum": 24,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • changedInput schema / properties / include_previews / description
        Previous 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"
      • removedInput schema / properties / limit / description
        Removed value: -"Maximum number of messages (1-200)"
      • changedInput schema / properties / types / description
        Previous 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"
      • changedOutput 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"
        +}
    • Removedrecall
    • Addedremember
    • Removedremove_contact
    • Removedsave_contact
    • Addedsearch
    • Removedsearch_contacts
    • Removedsearch_messages
    • Removedsend_location
    • Removedsend_media
    • Changedsend_message15 fields changed
      • changedInput schema / properties / account_id / description
        Previous value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id"
      • addedInput schema / properties / address
        Added value: +{
        +  "description": "Location: shown under the name",
        +  "maxLength": 500,
        +  "type": "string"
        +}
      • addedInput schema / properties / as
        Added value: +{
        +  "description": "Media: a plain document, a voice note, a looping GIF",
        +  "enum": [
        +    "document",
        +    "voice",
        +    "gif"
        +  ],
        +  "type": "string"
        +}
      • changedInput schema / properties / chat_id / description
        Previous 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"
      • addedInput schema / properties / file_path
        Added value: +{
        +  "description": "Media: absolute path on the machine running wazap",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / forward
        Added value: +{
        +  "$ref": "#/properties/reply_to",
        +  "description": "Forward this message; text \"\""
        +}
      • addedInput schema / properties / latitude
        Added value: +{
        +  "maximum": 90,
        +  "minimum": -90,
        +  "type": "number"
        +}
      • addedInput schema / properties / longitude
        Added value: +{
        +  "maximum": 180,
        +  "minimum": -180,
        +  "type": "number"
        +}
      • changedInput schema / properties / mention_ids / description
        Previous 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"
      • addedInput schema / properties / multi_select
        Added value: +{
        +  "description": "Poll: several answers allowed",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / options
        Added value: +{
        +  "description": "Poll answers",
        +  "items": {
        +    "maxLength": 100,
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "maxItems": 12,
        +  "minItems": 2,
        +  "type": "array"
        +}
      • removedInput schema / properties / reply_to / description
        Removed value: -"Quote-reply to this message"
      • changedInput schema / properties / text / description
        Previous value: -"The message text"New value: +"The message, or the caption, poll question or place name; \"\" for a forward, a voice note or audio"
      • removedInput schema / properties / text / minLength
        Removed value: -1
      • addedInput schema / properties / url
        Added value: +{
        +  "description": "Media: public http(s) URL",
        +  "format": "uri",
        +  "type": "string"
        +}
    • Removedsend_poll
    • Removedset_contact_note
    • Removedset_profile_picture
    • Removedsync_contacts
    • Removedtranscribe_audio
    • Removedupdate_contact_details
    • Changedwait_for_messages6 fields changed
      • changedInput schema / properties / account_id / description
        Previous value: -"Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account."New value: +"Account id"
      • removedInput schema / properties / addressed_to_me / description
        Removed value: -"Only direct messages, @-mentions of the user and replies to the user's messages"
      • changedInput schema / properties / chat_id / description
        Previous value: -"Only messages in this chat"New value: +"Chat id, or a phone number"
      • changedInput schema / properties / cursor / description
        Previous value: -"The cursor returned by the previous call"New value: +"From the previous call"
      • removedInput schema / properties / timeout_seconds / description
        Removed value: -"How long to wait (1-55 s)"
      • changedOutput 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"
        +}
  5. 13 tool updatesv0.21.0
    • Changeddelete_message3 fields changed
      • removedInput schema / properties / for_everyone / default
        Removed value: -false
      • changedInput schema / properties / for_everyone / description
        Previous 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"
      • changedInput schema / required
        Previous value: -[
        -  "message_id"
        -]New value: +[
        +  "message_id",
        +  "for_everyone"
        +]
    • Changedget_recent_messages1 field changed
      • changedInput schema / properties / types / items / enum
        Previous 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"
        +]
    • Addedjoin_group
    • Changedmanage_chat3 fields changed
      • changedInput schema / properties / action / enum
        Previous 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"
        +]
      • addedInput schema / properties / message_id
        Added value: +{
        +  "description": "The message for pin_message, unpin_message, star_message and unstar_message; it must be in chat_id",
        +  "minLength": 5,
        +  "type": "string"
        +}
      • addedInput schema / properties / pin_hours
        Added value: +{
        +  "description": "How long pin_message keeps the message pinned: 24, 168 (default) or 720 hours",
        +  "enum": [
        +    24,
        +    168,
        +    720
        +  ],
        +  "type": "number"
        +}
    • Changedmanage_group5 fields changed
      • changedInput schema / properties / action / enum
        Previous 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"
        +]
      • addedInput schema / properties / file_path
        Added value: +{
        +  "description": "set_picture: absolute path of a local JPEG, PNG or WebP",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • changedInput schema / properties / participant_ids / description
        Previous value: -"Targets of add/remove/promote/demote"New value: +"Targets of add/remove/promote/demote/approve_join_requests/reject_join_requests"
      • addedInput schema / properties / url
        Added value: +{
        +  "description": "set_picture: public http(s) URL to fetch and use as the photo",
        +  "format": "uri",
        +  "type": "string"
        +}
      • changedInput schema / properties / value / description
        Previous 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"
    • Changedread_messages1 field changed
      • changedInput schema / properties / types / items / enum
        Previous 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"
        +]
    • Addedrecall
    • Addedremove_contact
    • Addedsave_contact
    • Changedsearch_contacts3 fields changed
      • changedInput schema / properties / query / description
        Previous 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."
      • addedInput schema / properties / tag
        Added value: +{
        +  "description": "Only contacts filed under this tag (\"client\"); \"#\" optional",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • removedInput schema / required
        Removed value: -[
        -  "query"
        -]
    • Changedsearch_messages1 field changed
      • changedInput schema / properties / from / description
        Previous 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)"
    • Changedsend_message1 field changed
      • changedInput schema / properties / mention_ids / description
        Previous 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"
    • Addedupdate_contact_details
  6. 33 tool updatesv0.15.0
    • Addedconfirm_send
    • Changedcreate_group1 field changed
      • addedInput schema / properties / account_id
        Added value: +{
        +  "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.",
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Changeddelete_message1 field changed
      • addedInput schema / properties / account_id
        Added value: +{
        +  "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.",
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Changeddownload_media1 field changed
      • addedInput schema / properties / account_id
        Added value: +{
        +  "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.",
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Changededit_message1 field changed
      • addedInput schema / properties / account_id
        Added value: +{
        +  "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.",
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Changedforward_message1 field changed
      • addedInput schema / properties / account_id
        Added value: +{
        +  "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.",
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Changedget_contact1 field changed
      • addedInput schema / properties / account_id
        Added value: +{
        +  "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.",
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Changedget_group_info1 field changed
      • addedInput schema / properties / account_id
        Added value: +{
        +  "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.",
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Changedget_message1 field changed
      • addedInput schema / properties / account_id
        Added value: +{
        +  "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.",
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Changedget_recent_messages3 fields changed
      • addedInput schema / properties / account_id
        Added value: +{
        +  "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / compact
        Added 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"
        +}
      • addedInput schema / properties / include_previews
        Added 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"
        +}
    • Changedget_status2 fields changed
      • addedInput schema / additionalProperties
        Added value: +false
      • addedInput schema / properties / account_id
        Added value: +{
        +  "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.",
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Addedget_stories
    • Addedget_unanswered
    • Changedlearn2 fields changed
      • addedInput schema / additionalProperties
        Added value: +false
      • addedInput schema / properties / account_id
        Added value: +{
        +  "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.",
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Addedlink_account
    • Addedlist_accounts
    • Changedlist_chats1 field changed
      • addedInput schema / properties / account_id
        Added value: +{
        +  "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.",
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Changedmanage_chat1 field changed
      • addedInput schema / properties / account_id
        Added value: +{
        +  "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.",
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Changedmanage_group1 field changed
      • addedInput schema / properties / account_id
        Added value: +{
        +  "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.",
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Addedmark_handled
    • Changedreact_to_message1 field changed
      • addedInput schema / properties / account_id
        Added value: +{
        +  "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.",
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Changedread_messages2 fields changed
      • addedInput schema / properties / account_id
        Added value: +{
        +  "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / include_previews
        Added 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"
        +}
    • Changedsearch_contacts1 field changed
      • addedInput schema / properties / account_id
        Added value: +{
        +  "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.",
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Changedsearch_messages4 fields changed
      • addedInput schema / properties / account_id
        Added value: +{
        +  "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / from
        Added value: +{
        +  "description": "Only messages this person sent: \"me\", a contact id or a phone number",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / since
        Added value: +{
        +  "description": "Only messages from this moment on: a date (\"2026-09-01\") or an ISO timestamp",
        +  "minLength": 4,
        +  "type": "string"
        +}
      • addedInput schema / properties / until
        Added value: +{
        +  "description": "Only messages up to this moment: a date or an ISO timestamp",
        +  "minLength": 4,
        +  "type": "string"
        +}
    • Changedsend_location1 field changed
      • addedInput schema / properties / account_id
        Added value: +{
        +  "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.",
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Changedsend_media2 fields changed
      • addedInput schema / properties / account_id
        Added value: +{
        +  "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / as_gif
        Added value: +{
        +  "default": false,
        +  "description": "Send a .gif or an mp4 as a looping GIF, the way WhatsApp plays them",
        +  "type": "boolean"
        +}
    • Changedsend_message1 field changed
      • addedInput schema / properties / account_id
        Added value: +{
        +  "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.",
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Changedsend_poll1 field changed
      • addedInput schema / properties / account_id
        Added value: +{
        +  "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.",
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Addedset_contact_note
    • Addedset_profile_picture
    • Changedsync_contacts2 fields changed
      • addedInput schema / additionalProperties
        Added value: +false
      • addedInput schema / properties / account_id
        Added value: +{
        +  "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.",
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Changedtranscribe_audio1 field changed
      • addedInput schema / properties / account_id
        Added value: +{
        +  "description": "Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account.",
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Addedwait_for_messages
  7. 4 tool updatesv0.10.0
    • Changedget_recent_messages2 fields changed
      • addedInput schema / properties / include_system
        Added value: +{
        +  "default": false,
        +  "description": "Include WhatsApp's own system notices, which are excluded from the bodies and the counts by default",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / types
        Added 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"
        +}
    • Changedread_messages1 field changed
      • addedInput schema / properties / types
        Added 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"
        +}
    • Addedsync_contacts
    • Addedtranscribe_audio
  8. 22 tool updatesv0.9.3
    • First observedcreate_group
    • First observeddelete_message
    • First observeddownload_media
    • First observededit_message
    • First observedforward_message
    • First observedget_contact
    • First observedget_group_info
    • First observedget_message
    • First observedget_recent_messages
    • First observedget_status
    • First observedlearn
    • First observedlist_chats
    • First observedmanage_chat
    • First observedmanage_group
    • First observedreact_to_message
    • First observedread_messages
    • First observedsearch_contacts
    • First observedsearch_messages
    • First observedsend_location
    • First observedsend_media
    • First observedsend_message
    • First observedsend_poll

TDQS

B3.4/5.0

Scored across 23 tools

Disambiguation4/5

Most tools target a distinct action (send_message vs confirm_send vs edit_message clearly separated; find_contact vs list_contacts distinct). The message-reading cluster (read_messages, get_message, search, catch_up, wait_for_messages) risks overlap, but the very detailed descriptions draw clear boundaries. One or two could still be confused at a glance.

Naming Consistency3/5

Casing is uniformly snake_case, which is good, but the verb_noun pattern is not maintained: get_/list_/read_/manage_/find_ sit alongside bare nouns and verbs (learn, reminder, remember, search, catch_up, scheduled_messages, wait_for_messages). Readable overall, but the verb choice for reading tools (get_status, list_chats, read_messages) is inconsistent.

Tool Count3/5

23 tools is on the heavy side for an agent surface and lands in the 16-25 range. The WhatsApp domain is genuinely broad (messages, chats, groups, contacts, media, scheduling, reminders, status), so each tool is defensible, but the set is large enough that navigation costs are real.

Completeness4/5

Coverage is strong: linking, status, read/search/get, draft-confirm send lifecycle, edit, delete, react, chat and group administration, contacts, media, scheduling, reminders, memory and catch-up are all present. Only minor gaps remain (e.g. no dedicated forward/poll-creation tool, though both are folded into send_message).

Maintenance

ActivityActive
ResponsivenessSlow

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

  • A
    license
    Not graded
    quality
    A
    maintenance
    WhatsApp MCP server that exposes messaging, groups, contacts, and profile management as tools and resources for AI agents, supporting Baileys and Meta Cloud API.
    25
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    A 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.
    4
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    MCP server that connects AI agents to WhatsApp using the multi-device API, enabling messaging, group management, and more as a regular user.
    6 npm
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    A 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.
    16 npm
    1
    MIT