io.github.razvangirgiz/wazap
NPM · WAZAP-MCP · SCANNED SEP 20
WhatsApp for your agent: chats, messages, media, contacts and groups behind MCP tools.
Available components
How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. How we score → Why this is hard to score →
Supply Chain Security98
- No malware found by supply-chain analysis.Pass
- No known CVEs affecting this package version or its production dependencies.Pass
- No install/post-install scripts declared.Pass
- 83 of 268 dependencies flagged as unhealthy. View diagnostics → Partial
Provenance & Transparency97
- Source repository is publicly reachable at the declared URL. View diagnostics → Pass
- Cryptographically verified build provenance (signed, bound to razvangirgiz/wazap). View diagnostics → Pass
- Clear OSI-approved license (MIT).Pass
- Actively maintained (last published 3 days ago).Pass
- Disclosure check failed: no security disclosure policy was found in the source repository. See how to fix → Fail
Schema Quality & AI Usability79
- 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).Pass
- AI-judged instruction clarity (excellent).Pass
- Context-footprint check failed: tool/resource definitions use about 9733 tokens (~256/item across 38 items; 38 tools + 0 resources), over budget; trim descriptions and params. See how to fix → Fail
- Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management91
- Stability check failed: the tool surface changed between 0.10.0 and 0.23.1: 0 tool removals, 1 breaking changes, 14 additions. See how to fix → Fail
Tool Coverage100
- 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
- 100% of tool parameters carry a description.Pass
Tool Safety100
- No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.Pass
- All 7 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation.Pass
- An AI judge read all 39 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
- Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.Pass
How do I install the io.github.razvangirgiz/wazap MCP server?
io.github.razvangirgiz/wazap runs locally as an npm package, launched with npx -y wazap-mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.
npm · wazap-mcp
claude mcp add razvangirgiz-wazap -- npx -y wazap-mcp
{
"mcpServers": {
"razvangirgiz-wazap": {
"command": "npx",
"args": [
"-y",
"wazap-mcp"
]
}
}
} {
"servers": {
"razvangirgiz-wazap": {
"command": "npx",
"args": [
"-y",
"wazap-mcp"
]
}
}
} codex mcp add razvangirgiz-wazap -- npx -y wazap-mcp
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"razvangirgiz-wazap": {
"type": "local",
"command": [
"npx",
"-y",
"wazap-mcp"
],
"enabled": true
}
}
} openclaw mcp add razvangirgiz-wazap --command npx --arg -y --arg wazap-mcp
mcp_servers:
razvangirgiz-wazap:
command: "npx"
args: ["-y", "wazap-mcp"] {
"McpServers": {
"razvangirgiz-wazap": {
"Transport": "stdio",
"Command": "npx",
"Arguments": [
"-y",
"wazap-mcp"
]
}
}
} assistant mcp add razvangirgiz-wazap -t stdio -c npx -a -y wazap-mcp
{
"mcpServers": {
"razvangirgiz-wazap": {
"command": "npx",
"args": [
"-y",
"wazap-mcp"
]
}
}
} Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.
- 20 Sept 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 88 to 91.
- 18 Sept 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 81 to 85.
- 17 Sept 26 0
- Stability: fail → unverified ▼ security
- Known CVEs: pass → unverified ▼ security
- Tool safety: pass → unverified ▼ security
- Capabilities: pass → unverified ▼ functional
- Dependency health: 0.85 → unverified ▼ functional
- Tool coverage: 100 → unverified ▼ functional
- Schema quality: 100 → unverified ▼ functional
- Package version: 0.22.0 → 0.23.1 functional
- Package version: 0.22.0 → 0.23.0 functional
- 16 Sept 26 +26
- Stability: fail → unverified ▼ security
- Tool safety: pass → unverified ▼ security
- CVE-2026-82417 no longer affects this package ▲ security
- CVE-2026-82562 no longer affects this package ▲ security
- Malware scan: unverified → pass ▲ security
- Known CVEs: unverified → pass ▲ security
- Capabilities: pass → unverified ▼ functional
- Tool coverage: 100 → unverified ▼ functional
- Schema quality: 100 → unverified ▼ functional
- Dependency health: unverified → 0.85 ▲ functional
- Package version: 0.20.2 → 0.22.0 functional
- Package version: 0.20.2 → 0.21.0 functional
- 15 Sept 26 −14
- Known CVEs: fail → unverified ▼ security
- Malware scan: pass → unverified ▼ security
- Stability: 0.73 → fail ▼ security
- CVE-2026-82562 no longer affects this package ▲ security
- CVE-2026-82417 no longer affects this package ▲ security
- Provenance: fail → pass ▲ security
- Known CVEs: fail → pass ▲ security
- The attested source repository moved: razvangirgiz/wazap security
- Schema quality: 113 → 248 ▼ functional
- Schema quality: 113 → 228 ▼ functional
- Schema quality: 113 → 227 ▼ functional
- Dependency health: 0.84 → unverified ▼ functional
- First check of Schema quality: 100 functional
- Package version: 0.10.0 → 0.20.2 functional
- Package version: 0.10.0 → 0.20.1 functional
- Package version: 0.10.0 → 0.20.0 functional
- Package version: 0.10.0 → 0.19.1 functional
- Package version: 0.10.0 → 0.18.6 functional
- 14 Sept 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 70 to 73. That category is still filling its 30-day observation window: 21 days of observed history at the previous scan, 22 at this one. The score rises as the window fills, whether or not the server changes.
- 12 Sept 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 63 to 67. That category is still filling its 30-day observation window: 19 days of observed history at the previous scan, 20 at this one. The score rises as the window fills, whether or not the server changes.
- 10 Sept 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 57 to 60. That category is still filling its 30-day observation window: 17 days of observed history at the previous scan, 18 at this one. The score rises as the window fills, whether or not the server changes.
Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.
Captured 20 Sept 2026 · Analysed npm/wazap-mcp@0.23.1
Provenance Verified
A signed build attestation was found and verified, binding this exact artifact to the source repository it claims to come from.
| Result | Verified |
|---|---|
| Ecosystem | npm |
| Reason | Verified |
| Discovered via | Registry attestation endpoint |
| Source repo | razvangirgiz/wazap |
| Certificate issuer | https://token.actions.githubusercontent.com |
| Certificate SAN | https://github.com/razvangirgiz/wazap/.github/workflows/publish.yml@refs/tags/v0.23.1 |
| Rekor log index | 2872280605 |
| Predicate type | https://slsa.dev/provenance/v1 |
| Subject digest | sha512:edef4ddff64c3a2c47c2098125efc34078cd8788e62d2ecc131d77911da02eb91b4f3a0d59caf68db0b3775efec1da562544ee6bb3bda02befe580c2b |
Background: How many MCP packages publish verified provenance →
Dependencies 268 packages
| Packages resolved | 268 |
|---|---|
| Stale | 83 |
| Tree resolution | Complete |
Background: SBOMs and build attestations, explained →
The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →
confirm_send Send a drafted WhatsApp message ~199
Send a draft created by send_message, send_media, send_poll, send_location or forward_message. This is the only call that reaches WhatsApp, and it sends a draft at most once: confirming it again answers the same receipt with already_sent: true. Only the MCP session that created the draft may confirm it. After reinitializing or reconnecting with a new session, draft again and obtain fresh user approval. A missing or expired draft_id also means draft again and show the new preview before calling this. SEND_OUTCOME_UNKNOWN means WhatsApp may have the message: check the chat with read_messages before anything else, and never draft it again without asking the user.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| draft_id | string | yes | The draft_id returned by a send_* tool |
No output schema declared.
No examples provided.
create_group Create a WhatsApp group ~112
Create a group with the given name and participants; the linked account becomes the owner. Each participant comes back with a status: ok, invite_needed (their privacy settings require an invite link) or failed.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| name | string | yes | Group name |
| participant_ids | array | yes | Chat ids or phone numbers to add (1-256) |
No output schema declared.
No examples provided.
delete_message Delete a WhatsApp message ~243
Delete a message. DESTRUCTIVE — confirm with the user first. for_everyone is required, and picks one of two different deletes; tell the user which: - for_everyone: true retracts it for everyone in the chat. Works on messages the linked account sent, within 2 days of sending. In a group where the linked account is an admin it also takes someone else's message, deleted as an admin; anywhere else that is NOT_OWN_MESSAGE. - for_everyone: false removes it from the linked account's own devices only: anyone's message, at any age. Nobody else sees a change.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| for_everyone | boolean | yes | Required. true retracts it for everyone in the chat; false deletes it for the linked account only |
| message_id | string | yes | Message id from read_messages / search_messages / get_message, e.g. "false_4072...@s.whatsapp.net_3EB0..." |
No output schema declared.
No examples provided.
download_media Download media from a WhatsApp message ~384
Download the photo/video/audio/document attached to a message and save it to disk on the machine running wazap. The file at `path` is already decrypted — open or process it as is; nothing else is needed. Images of 1 MB or less are also returned inline so you can look at them. The structured result carries: `path` (the saved file), `mime`, `size` (bytes), `filename` (the name it was saved under — a timestamped name wazap made, not the sender's), `original_filename` (the name the sender's file had, or null when the envelope carried none), `caption` (the text the sender wrote under the media, or null — audio and voice notes cannot carry one), `message_id` and `sender` (the same identity fields as search_messages — is_saved, contact_name, pushname, name_source — or null when even the message can no longer be read back). The id resolves in its raw form too: `false_<lid>@lid_<stanza>` works whether or not the chat's number was ever learned — when it was, the lid spelling finds the same message filed under the paired number. An unresolved sender never blocks the file. Without `account_id` the same lookup walks every linked account's store in turn before failing, and the result's `account_id` names the one that served the file. Fails with MEDIA_UNAVAILABLE when WhatsApp has expired the file.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| message_id | string | yes | A message with has_media=true |
| save_to | string | – | Absolute directory to save into (default: <data-dir>/media) |
No output schema declared.
No examples provided.
edit_message Edit a WhatsApp message you sent ~96
Replace the text of a message the linked account sent. WhatsApp only allows this within 15 minutes of sending; after that send a correction instead.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| message_id | string | yes | A message the linked account sent |
| text | string | yes | The replacement text |
No output schema declared.
No examples provided.
forward_message Draft a forwarded WhatsApp message ~131
Draft a forward of an existing message to another chat. Does not send. The recipient will see it marked as forwarded. Show the preview; after the user says yes, call confirm_send.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| message_id | string | yes | Message id from read_messages / search_messages / get_message, e.g. "false_4072...@s.whatsapp.net_3EB0..." |
| to_chat_id | string | yes | Destination chat |
No output schema declared.
No examples provided.
get_contact Get WhatsApp contact details ~148
Full details for one contact: name, number, about text, profile picture URL, whether they are a saved contact, a business, or blocked. `name_source` says where the shown name comes from — "contact" when it is the saved address-book name (is_my_contact), "pushname" when it is a name the person publishes, or "none" when there is no usable name.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| contact_id | string | yes | Contact id from search_contacts / list_chats, or a phone number |
No output schema declared.
No examples provided.
get_group_info Get WhatsApp group info ~198
Details of a group: name, description, owner, creation date, whether only admins may post, whether the linked account is an admin, and the participant list (up to 500; participant_count is always the true total). The invite link is included only when the linked account is an admin. The settings come too: info_locked (only admins edit the name, description and photo), member_add_mode ("admins" or "all"), join_approval, disappearing_seconds (0 when off), and community ({is_community, parent_group_id}) when the group is a community or belongs to one. Call this before manage_group: most group actions need admin rights.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| group_id | string | yes | Group chat id ("<id>@g.us") |
No output schema declared.
No examples provided.
get_message Get one WhatsApp message in full ~472
The complete message behind a message_id, including the quoted message it replies to, each reaction with who left it, who chose each option of a poll or answered an event, and its media metadata. Use it after search_messages or read_messages when you need the context around a single message. On the user's own messages, `delivery.status` says how far it got ("sent", "delivered", "read", "played", "pending" or "error"), and in a group `read_by` and `delivered_to` name who, with the time. It stops at "delivered" or is missing when read receipts are off on either side, and large groups may send none. The id also resolves in its raw form: `false_<lid>@lid_<stanza>` works even when the chat's number was never learned, and an id that names the same message under the lid or the paired number finds it either way. With several accounts linked and no `account_id`, an id the resolved account cannot find is tried on each of the others in turn before MESSAGE_NOT_FOUND comes back, and the answer's `account_id` names the one that had it; pass `account_id` to keep the lookup on one account. The `sender` carries the same identity fields as search_messages: `id` (the canonical jid — a `…@lid` only while WhatsApp has never revealed the paired number), `phone` (the number, or null for an unresolved lid), `is_saved` (whether the sender is in the user's address book), `contact_name` (the name saved there, or null), `pushname` (the name the sender publishes, when that is the name `name` shows) and `name_source` ("contact", "pushname" or "none" — which of those `name` came from).
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| message_id | string | yes | Message id from read_messages / search_messages / get_message, e.g. "false_4072...@s.whatsapp.net_3EB0..." |
No output schema declared.
No examples provided.
get_recent_messages Get every WhatsApp conversation from the last N hours ~343
Everything that happened recently, grouped by chat. This is the catch-up tool: one call instead of list_chats plus a read_messages per chat. WhatsApp's own notices — device linking, group membership changes, encryption notices — are left out so the counts are conversation; pass include_system to see them. A chat lists at most its newest 2,000 messages of the window.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| compact | boolean | – | 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 c… |
| filter | string | – | Restrict to unread chats, groups, or one-to-one chats |
| hours | integer | – | Look-back window in hours (1-168) |
| include_previews | boolean | – | 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… |
| include_system | boolean | – | Include WhatsApp's own system notices, which are excluded from the bodies and the counts by default |
| types | array | – | 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. |
No output schema declared.
No examples provided.
get_status Get the WhatsApp connection status ~309
Check the session: connection status ("connected" means the tools work, "not_linked" means the user must run `npx wazap-mcp login`), whether the initial history sync has finished, which account is linked, how fresh the local history is — `history` shows when a message last arrived and flags `stale` when the phone has been quiet for a day while connected — the versions and data directory in use, and how many contacts carry a name from the phone's address book (contacts_named: 0 means it never arrived). `webhook.delivery` counts the account's webhook events: delivered (last 7 days), failed and cancelled (last 30), pending; a non-zero `consecutive_failures` or `retrying` means the receiver is refusing or unreachable right now, and `last_failure` says how. Call this whenever another tool reports NOT_CONNECTED, NOT_LINKED or SYNC_IN_PROGRESS, or to confirm which account you are about to send from. Without account_id the top-level fields are the default account, plus `accounts` listing every live one. While a link is in progress the status is "linking" and `pairing` carries the code the user still has to type into their phone.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
No output schema declared.
No examples provided.
get_stories See the stories people posted ~219
The stories (status updates) the linked account has received in the last N hours, newest first, each with its author, its text or caption and its time. WhatsApp keeps a story for a day and so does wazap; nothing older is held. With include_previews the photos come as small images, and download_media works on a story's message_id like on any message. Stories never appear in chats, catch-ups or waits; this is the only place they show.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| hours | integer | – | Look-back window in hours (1-24) |
| include_previews | boolean | – | 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… |
No output schema declared.
No examples provided.
get_unanswered Find who is waiting on the user ~307
Chats where the last word is theirs and it asks for something: a question, a request ("poți", "te rog", "can you", "when"…), or a voice note nobody has heard yet. A conversation that ended in "ok, thanks" is not listed, and neither is an ask older than max_age_hours (two weeks by default): that one was abandoned, not left waiting. Groups count only when the user was @-mentioned or replied to after their own last message. A [business] account's ask is often an automatic reply; weigh it accordingly. People come first, then the oldest wait. Each entry quotes the ask, says how many of their messages arrived since the user's last one, and how long they have been waiting. This is the follow-up half of an inbox triage; use get_recent_messages for what happened, and this for who is still waiting.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| limit | integer | – | Maximum number of chats (1-50) |
| max_age_hours | number | – | Ignore asks older than this; an ask left for two weeks (the default) is abandoned, not waiting |
| min_age_hours | number | – | Only asks at least this old, e.g. 48 for people the user forgot for two days |
No output schema declared.
No examples provided.
join_group Join a WhatsApp group from an invite ~239
Join a group from an invite: a link (https://chat.whatsapp.com/<code>, or the code alone) as invite, or the message_id of an invite message someone sent (type "invite"). Exactly one of invite / message_id. Without confirm: true it joins nothing and returns the group's name, description, member count and whether an admin must approve new members. Show that to the user and wait for an explicit yes, then call again with the same invite or message_id and confirm: true. Every member sees the account join. The answer is the group's chat_id, or pending_approval when an admin must let the account in first.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| confirm | boolean | – | true joins, only after the user said yes to the preview; omit to preview |
| invite | string | – | A https://chat.whatsapp.com/ link, or its code |
| message_id | string | – | An invite message (type "invite") from read_messages |
No output schema declared.
No examples provided.
learn Learn how to use the WhatsApp tools ~90
Read this FIRST, before any other WhatsApp tool. Returns the guide to the tools, the id formats, the recommended workflows, the message shape and every error code with what to do about it. Takes no arguments and never touches WhatsApp.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
No output schema declared.
No examples provided.
link_account Link a WhatsApp account ~217
Pair this wazap with the user's WhatsApp when get_status says not_linked, logged_out, session_corrupt or auth_failure. Ask the user for their phone number in international format, call this, and show them the code it returns with these exact steps: WhatsApp → Settings → Linked devices → Link a device → Link with phone number instead → enter the code. Then call get_status every 10 seconds until it says connected (up to 3 minutes). The code expires; call this again for a fresh one if get_status goes back to not_linked with an error. The account must already exist (`wazap account add`). Pass account_id when more than one is configured. An unknown id is ACCOUNT_NOT_FOUND. Never call this when the account is already linked.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| phone | string | yes | International format, e.g. +15550100 |
No output schema declared.
No examples provided.
list_accounts List WhatsApp accounts on this server ~105
List every configured WhatsApp account: id, name, connection status, masked phone, owner name, and whether that account allows writes. Call this first when more than one account is linked, then pass account_id on the other tools. Takes no arguments besides the optional account_id (ignored for the listing).
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
No output schema declared.
No examples provided.
list_chats List WhatsApp chats ~141
List conversations, most recently active first. Use it to discover the chat_id values the other tools need. Each chat has: chat_id, name, type, unread_count, last_message {text, timestamp, from_me}, archived, pinned, muted_until, and left (groups you are no longer in).
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| filter | string | – | Which chats to list; "all" (default) excludes archived ones |
| limit | integer | – | Maximum number of chats (1-100) |
No output schema declared.
No examples provided.
manage_chat Manage a WhatsApp chat ~385
Change a chat, or a message in it. Actions: - archive / unarchive, pin / unpin (the chat), mute / unmute (mute_hours defaults to 8), mark_read (sends read receipts) / mark_unread - pin_message / unpin_message — need message_id; pins it for everyone in the chat, for pin_hours 24, 168 (default) or 720 - star_message / unstar_message — need message_id; the star is the linked account's own - clear — DESTRUCTIVE, empties the chat for the linked account only - delete — DESTRUCTIVE, deletes the chat for the linked account only - block / unblock — a person's chat only; a blocked person can no longer message or call the account A message_id must belong to chat_id. Every action hits WhatsApp at once and there is no draft: say what will change and wait for a yes before calling it.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| action | string | yes | What to do with the chat |
| chat_id | string | yes | Chat id as returned by another tool ("<digits>@s.whatsapp.net" or "<id>@g.us"), or a phone number in international format |
| message_id | string | – | The message for pin_message, unpin_message, star_message and unstar_message; it must be in chat_id |
| mute_hours | integer | – | Hours to mute, default 8; only used by "mute" |
| pin_hours | number | – | How long pin_message keeps the message pinned: 24, 168 (default) or 720 hours |
No output schema declared.
No examples provided.
manage_group Manage a WhatsApp group ~501
Administer a group. Actions: - add / remove / promote / demote — need participant_ids; each participant comes back with status ok, invite_needed or failed - leave — DESTRUCTIVE, rejoining needs an invite - set_subject / set_description — need value - set_picture — needs exactly one of file_path / url: JPEG, PNG or WebP, at most 10 MB. Every member sees it at once and there is no draft: show the image and wait for a yes first - remove_picture — takes the group photo down; ask first the same way - get_invite_link / revoke_invite_link - list_join_requests — who is waiting for approval, with when and how they asked - approve_join_requests / reject_join_requests — need participant_ids from list_join_requests; each comes back with status ok or failed - set_announcement_only / set_info_locked / set_join_approval — value "on" or "off" - set_add_mode — value "admins" or "all" - set_disappearing — value "off", "24h", "7d" or "90d" Everything except leave requires the linked account to be a group admin; call get_group_info first to check. Every change is visible to all members at once: say what will change and wait for a yes before calling it.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| action | string | yes | Group action to perform |
| file_path | string | – | set_picture: absolute path of a local JPEG, PNG or WebP |
| group_id | string | yes | Group chat id ("<id>@g.us") |
| participant_ids | array | – | Targets of add/remove/promote/demote/approve_join_requests/reject_join_requests |
| url | string | – | set_picture: public http(s) URL to fetch and use as the photo |
| value | string | – | 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 |
No output schema declared.
No examples provided.
mark_handled Take a chat off the waiting list ~169
The user dealt with what this chat was asking, outside WhatsApp or by a reply wazap did not see: a phone call, a meeting, a decision. The open ask is remembered as handled and the chat leaves get_unanswered. The next message from the other side makes a new ask and the chat comes back on its own. Kept on this machine only; nothing is sent or marked read on WhatsApp.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| chat_id | string | yes | Chat id as returned by another tool ("<digits>@s.whatsapp.net" or "<id>@g.us"), or a phone number in international format |
No output schema declared.
No examples provided.
react_to_message React to a WhatsApp message ~119
Add an emoji reaction to a message, or pass an empty string to remove your reaction.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| emoji | string | yes | A single emoji such as "👍", or "" to remove your reaction |
| message_id | string | yes | Message id from read_messages / search_messages / get_message, e.g. "false_4072...@s.whatsapp.net_3EB0..." |
No output schema declared.
No examples provided.
read_messages Read messages from a WhatsApp chat ~274
Read messages from one chat, oldest to newest. Without `before` you get the most recent messages. Pass `before` (the oldest message_id you already have) to page further back; wazap asks the phone for older history when the local store runs out, which takes a few seconds.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| before | string | – | Return the messages immediately older than this message_id |
| chat_id | string | yes | Chat id as returned by another tool ("<digits>@s.whatsapp.net" or "<id>@g.us"), or a phone number in international format |
| include_previews | boolean | – | 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… |
| limit | integer | – | Maximum number of messages (1-200) |
| types | array | – | 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. |
No output schema declared.
No examples provided.
recall Semantically search WhatsApp history ~637
Search by meaning and by words at once over the whole WhatsApp history — answers "the invoice Dan mentioned", "the address Ana sent", "what did they say about the trip". A paraphrase or another language still hits through its meaning, and a short or foreign-language question still hits through its words; the two rankings are fused. A match found by meaning weighs a little less with age (85% a month on, never under 70%), so the fresher of two close matches comes first but a clearly closer old one still does; one chat takes at most three leading places before other chats' hits, and a near-duplicate trails the list. For an exact string — an id, a phone number, a URL — search_messages is the better tool. Each result carries its date, a fused score, `matched` ("words", "meaning" or "both") and the cosine `similarity` when its meaning ranked it. chat_id, since, until and from narrow the search exactly like search_messages — including a name that resolves to exactly one person. A hit marked "index only" is a message wazap holds only as text: quote its words; get_message returns them, but download_media has nothing to open and it cannot be replied to or forwarded. A hit found only by meaning must clear the similarity floor, so a question with no answer comes back empty; when only weak meaning matches survive, the output says so — do not present them as found facts. When semantic recall is off or its embedding setup is missing, the tool does not dead-end: it falls back to a keyword search over the local history, marked `mode: "keyword_fallback"`, and `recall_unavailable.fix` names the command that turns semantic recall on. An error remains only when even the fallback cannot run. Each hit's `sender` carries the same identity fields as search_messages, and `freshness` says whether the local history may be partial or stale. Every answer also declares its window: the semantic path reports how many messages the index covers, and a keyword fallback carries the same `coverage`…
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| chat_id | string | – | Restrict the search to this chat |
| from | string | – | 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) |
| limit | integer | – | Maximum number of results (1-50) |
| query | string | yes | What to find, said any way — the meaning is what matches |
| since | string | – | Only messages from this moment on: a date ("2026-09-01") or an ISO timestamp |
| until | string | – | Only messages up to this moment: a date or an ISO timestamp |
No output schema declared.
No examples provided.
remove_contact Remove a WhatsApp contact ~97
Take a person out of the account's WhatsApp contacts: the saved entry and its name go, the chat and its history stay. Nothing is sent to the contact.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| contact_id | string | yes | Contact id from search_contacts / get_contact, or a phone number |
No output schema declared.
No examples provided.
save_contact Add or rename a WhatsApp contact ~206
Save a person in the account's WhatsApp contacts: a new entry for a phone number, or a new name for an existing one. The name syncs to every linked device, and with save_on_phone (default) also into the phone's own address book. WhatsApp keeps no other fields — email, "my accountant" and the like go to set_contact_note, which stays on this machine.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| contact_id | string | yes | Contact id from search_contacts / get_contact, or a phone number |
| first_name | string | – | First name, when it differs from the full name |
| name | string | yes | Full name to save the contact under |
| save_on_phone | boolean | – | Also write the contact into the phone's address book; false keeps it inside WhatsApp |
No output schema declared.
No examples provided.
search_contacts Search WhatsApp contacts ~183
Find contacts by name, phone number, tag or detail: a substring match on the name, a digit match on the number, or a word from a local tag or detail — so "contabil" finds the person filed under role: contabil by update_contact_details. With only tag it lists everyone carrying that tag. Returns contact_id values usable as chat_id.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| limit | integer | – | Maximum number of results (1-50) |
| query | string | – | Name fragment, phone number, or tag/detail text (at least 2 characters). Omit with tag to list everyone carrying it. |
| tag | string | – | Only contacts filed under this tag ("client"); "#" optional |
No output schema declared.
No examples provided.
search_messages Search WhatsApp messages ~685
Substring search over the messages wazap holds locally — all chats, or one chat, including history synced on first link. Case and diacritics are ignored ("sedinta" finds "ședință"). Every message the phone synced to this device is kept and searched; there is no per-chat window. It cannot reach messages the phone never synced to this device. Every answer declares the window it searched: `coverage.searched` counts the held messages in scope (the chat scope and time filters applied) and `coverage.oldest_at`/`newest_at` bound that window, so "no messages found" always says how much history was searched. `coverage.per_chat_cap` is null: no chat is capped. A query so short or so common that the search reaches its scan limit answers `scan_capped: true` and `searched_back_to`: messages older than that were not searched, so narrow it (chat_id, since/until, a longer query) before concluding nothing exists. `from` accepts "me", a phone number, a contact/chat id, or a name: a name must resolve to exactly one person — it matches contact names, notify names and last-seen pushnames, then one-to-one chat display names — or the error lists the candidates it found. Every message's `sender` carries `id` (the canonical jid — a `…@lid` only while WhatsApp has never revealed the paired number), `phone` (the number, or null for an unresolved lid), `is_saved` (the sender is in the user's address book — when false, treat the shown name as claimed, not known), `contact_name` (the name saved there, or null), `pushname` (the name the sender publishes, when that is the name `name` shows; null for saved contacts and unnamed senders) and `name_source` ("contact", "pushname" or "none" — which of those `name` came from). A sender wazap knows nothing about reads "unknown (lid …1234)" — never bare lid digits, which look like a phone number and are not one. `freshness` says whether the history this searched may be partial (sync still running) or stale (nothing inbound for 24h while connected); on…
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| chat_id | string | – | Restrict the search to this chat |
| from | string | – | 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) |
| limit | integer | – | Maximum number of results (1-50) |
| query | string | yes | Text to search for |
| since | string | – | Only messages from this moment on: a date ("2026-09-01") or an ISO timestamp |
| until | string | – | Only messages up to this moment: a date or an ISO timestamp |
No output schema declared.
No examples provided.
send_location Draft a WhatsApp location ~160
Draft a map pin, optionally labelled with a place name and address. Does not send. Show the preview; after the user says yes, call confirm_send.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| address | string | – | Street address shown under the name |
| chat_id | string | yes | Chat id as returned by another tool ("<digits>@s.whatsapp.net" or "<id>@g.us"), or a phone number in international format |
| latitude | number | yes | Latitude in decimal degrees |
| longitude | number | yes | Longitude in decimal degrees |
| name | string | – | Place name shown on the pin |
No output schema declared.
No examples provided.
send_media Draft a WhatsApp media message ~286
Draft an image, video, audio file, document or GIF, from a local path on the machine running wazap or from a public URL. Does not send. Exactly one of file_path / url. Maximum 100 MB. Show the preview; after the user says yes, call confirm_send. A GIF is sent with as_gif: an mp4 goes out looping, a .gif is converted to mp4 first (needs ffmpeg on the machine running wazap).
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| as_document | boolean | – | Send as a plain document instead of rendered media |
| as_gif | boolean | – | Send a .gif or an mp4 as a looping GIF, the way WhatsApp plays them |
| as_voice | boolean | – | Send an audio file as a voice note (push-to-talk) |
| caption | string | – | Text shown under the media |
| chat_id | string | yes | Chat id as returned by another tool ("<digits>@s.whatsapp.net" or "<id>@g.us"), or a phone number in international format |
| file_path | string | – | Absolute path of a local file to send |
| url | string | – | Public http(s) URL to fetch and send |
No output schema declared.
No examples provided.
send_message Draft a WhatsApp text message ~247
Draft a text message. Does not send. Returns a draft_id and a preview of the recipient and exact text. Show that preview to the user; after they say yes, call confirm_send. A draft lasts 15 minutes. To @-mention people, pass mention_ids and write @<number> in the text where each mention belongs, the digits of their id (@40722123456). A mention the text lacks gets its @<number> added at the end, so the preview is the text that goes out.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| chat_id | string | yes | Chat id as returned by another tool ("<digits>@s.whatsapp.net" or "<id>@g.us"), or a phone number in international format |
| mention_ids | array | – | Chat ids to @-mention; write @<number> in the text for each, or wazap adds it at the end |
| reply_to | string | – | Quote-reply to this message |
| text | string | yes | The message text |
No output schema declared.
No examples provided.
send_poll Draft a WhatsApp poll ~171
Draft a poll. Does not send. Participants vote in WhatsApp, and their votes show on the poll message: read_messages counts them and get_message says who chose each option. Show the preview; after the user says yes, call confirm_send.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| chat_id | string | yes | Chat id as returned by another tool ("<digits>@s.whatsapp.net" or "<id>@g.us"), or a phone number in international format |
| multi_select | boolean | – | Allow voters to pick more than one option |
| options | array | yes | Answer options (2-12) |
| question | string | yes | The poll question |
No output schema declared.
No examples provided.
set_contact_note Note something about a contact ~149
Remember something about a person, on this machine only: "Hermi, my own agent", "the accountant", "always answers late". The note then rides along wherever the contact shows: list_chats, search_contacts, get_contact, get_recent_messages and get_unanswered. Nothing is sent to WhatsApp and the contact never sees it. An empty note removes it.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| contact_id | string | yes | Contact id or phone number |
| note | string | yes | What to remember, or "" to remove the note |
No output schema declared.
No examples provided.
set_profile_picture Set the linked WhatsApp profile picture ~160
Set the linked WhatsApp account's own profile picture from a local path on the machine running wazap or from a public URL. Exactly one of file_path / url. JPEG, PNG or WebP only, at most 10 MB. DESTRUCTIVE and visible to every contact. Show the image and wait for a yes first. This call hits WhatsApp immediately; there is no draft.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| file_path | string | – | Absolute path of a local JPEG, PNG or WebP |
| url | string | – | Public http(s) URL to fetch and use as the photo |
No output schema declared.
No examples provided.
sync_contacts Fetch the phone's address book again ~149
Ask WhatsApp to send the linked phone's address book from scratch, and wait up to 15 seconds for it. Nothing on WhatsApp changes: this only refills wazap's own contact list. Use it when get_status reports contacts_named: 0, or when senders in a group read as phone numbers for people you know are saved on the phone. Returns named_before and named_after so you can tell whether it helped; if both are 0 the phone has no saved contacts for these people.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
No output schema declared.
No examples provided.
transcribe_audio Transcribe a WhatsApp voice message ~260
Turn a voice note or an audio message into text. The transcript is cached, so a second call on the same message costs nothing, and from then on the message reads as [voice message · 0:42] "what was said" in read_messages, get_recent_messages and get_message, and its words become searchable through search_messages. What it costs depends on how the user set transcription up: the local provider (whisper.cpp) is free and the audio never leaves the machine, while the API provider uploads the audio to a third-party service and is billed per minute. Either way this is capped at 10 calls a minute. TRANSCRIBE_UNAVAILABLE means transcription is off or unfinished on this machine; the fix names the command the user has to run. Do not retry it.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| language | string | – | ISO 639-1 code of what is spoken, e.g. "ro"; "auto" detects it. Omit to use the configured default. |
| message_id | string | yes | A message whose type is voice or audio |
No output schema declared.
No examples provided.
update_contact_details Tag and annotate a contact ~262
File local, searchable details on a person: tags like "client" or "echipa", and key-value fields like {"role": "contabil", "oras": "Cluj"}. This is how "the accountant" or "all suppliers" resolve later — search_contacts matches tag and field text, and its tag filter lists everyone carrying one. Nothing is sent to WhatsApp: the contact never sees it and the phone is unchanged. A field set to "" is deleted; remove_tags / remove_fields take keys away. Pass at least one of the four edits. The person need not be a saved contact.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| add_tags | array | – | Tags to file under, e.g. ["client", "echipa"]; lowercase tokens, "#" optional |
| contact_id | string | yes | Contact id or phone number |
| fields | object | – | Details to set, e.g. {"role": "contabil"}; an empty value deletes the key |
| remove_fields | array | – | Detail keys to delete |
| remove_tags | array | – | Tags to take off |
No output schema declared.
No examples provided.
wait_for_messages Wait for new WhatsApp messages ~292
Block until a message arrives, then return it, or return empty when the timeout passes. This is how an agent stays on the line without polling: call it in a loop, and pass the cursor it returns into the next call so nothing that landed between two calls is missed. The first matching message starts a one-second settle so a burst comes back together. Only messages from other people are returned, never the user's own, and never WhatsApp's system notices. With addressed_to_me, only direct messages, group messages that @-mention the user, and replies to the user's own messages wake the wait; everything else in a group is ignored. A cursor from a previous run of wazap cannot be honoured: the wait then starts from now and says cursor_reset. The timeout is capped at 55 seconds because MCP clients give up at 60.
| Name | Type | Req | Description |
|---|---|---|---|
| account_id | string | – | Registry account id (default, work, …). Omit to resolve from chat_id or message_id, or the default account. |
| addressed_to_me | boolean | – | Only direct messages, @-mentions of the user and replies to the user's messages |
| chat_id | string | – | Only messages in this chat |
| cursor | string | – | The cursor returned by the previous call |
| timeout_seconds | integer | – | How long to wait (1-55 s) |
No output schema declared.
No examples provided.
What is the io.github.razvangirgiz/wazap MCP server?
io.github.razvangirgiz/wazap is an MCP server listed in the public MCP registry as io.github.razvangirgiz/wazap. WhatsApp for your agent: chats, messages, media, contacts and groups behind MCP tools. This page covers its npm package (wazap-mcp).
Is the io.github.razvangirgiz/wazap MCP server safe to use?
io.github.razvangirgiz/wazap scores 94 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 20 September 2026. It declares no install or post-install scripts. Its build provenance is signed and verified. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.
What tools does the io.github.razvangirgiz/wazap MCP server expose?
io.github.razvangirgiz/wazap exposes 38 tools: learn, get_status, list_accounts, link_account, list_chats, and 33 more. Their descriptions and schemas cost roughly 9,345 tokens of context every time the server is loaded.
Is the io.github.razvangirgiz/wazap MCP server still maintained?
io.github.razvangirgiz/wazap is still listed as active in the MCP registry. We last reached this channel on 20 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.
What licence is the io.github.razvangirgiz/wazap MCP server under?
io.github.razvangirgiz/wazap declares the MIT licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.