Skip to main content
Glama
WAHA WhatsApp MCP Server

WAHA WhatsApp MCP Server

by Maheidem

WAHA WhatsApp MCP Server

npm License: MIT Node.js

A TypeScript Model Context Protocol stdio server for WhatsApp through a unified WAHA backend. It exposes 28 tools for messages, contacts, media, transcription, speech generation, automatic voice-note replies, message-store search, and per-conversation media automation.

Architecture

MCP client → this package → unified backend /api (:8200)
                                  ├─ PostgreSQL message store
                                  ├─ WAHA live proxy
                                  ├─ transcription and TTS providers
                                  └─ media analysis/archive worker

The MCP server only talks to the authenticated /api facade. It does not connect directly to WAHA, databases, Nextcloud, or model providers. LAN-only management routes for archive review and LLM provider administration are intentionally excluded.

This release targets waha-backend commit 46acc32 or a compatible newer build.

Related MCP server: WhatsApp MCP Server

Install

Claude Code

claude mcp add waha-whatsapp -- \
  env WAHA_API_URL=http://your-server:8200/api \
      WAHA_API_KEY=your-backend-api-key \
  npx -y @marcos-heidemann/waha-mcp-server

MCP JSON configuration

{
  "mcpServers": {
    "waha-whatsapp": {
      "command": "npx",
      "args": ["-y", "@marcos-heidemann/waha-mcp-server"],
      "env": {
        "WAHA_API_URL": "http://your-server:8200/api",
        "WAHA_API_KEY": "your-backend-api-key"
      }
    }
  }
}

Configuration

Variable

Required

Default

Description

WAHA_API_URL

no

http://localhost:8200/api

Unified backend API URL

WAHA_API_KEY

yes

—

Value sent as X-API-Key

WAHA_SESSION

no

default

WAHA session name

WAHA_SEND_DELAY_MS

no

1000

Minimum delay between outbound sends; non-negative integer

Older WAHA_STORE_* and WAHA_TRANSCRIPTION_* variables are no longer used. Those services are configured behind the unified backend.

Contact identifiers

Chat-targeting tools use a stable contactId:

  • Person: phone digits with country code, such as 5521999999999.

  • Group: the stable group JID ending in @g.us.

  • Legacy @c.us and @lid aliases remain accepted on routes where the backend supports them.

  • Imported chat IDs ending in @import work with message read/search, but not with the backend chat-summary route.

Use whatsapp_list_contacts to discover identifiers.

Tools (28)

Area

Tool

Purpose

Session

whatsapp_session_status

Connection and account presence

Session

whatsapp_account_info

Authenticated WhatsApp identity

Chats

whatsapp_list_chats

Live chat overview with previews

Chats

whatsapp_read_messages

Persistent history with live fallback and optional mark-read

Messaging

whatsapp_send_text

Rate-limited text send

Messaging

whatsapp_react

Add or remove a reaction

Messaging

whatsapp_edit_message

Edit an outgoing text message

Messaging

whatsapp_delete_message

Unsend a message

Messaging

whatsapp_forward_message

Copy stored text into another chat

Media

whatsapp_download_media

Return images/audio up to 10 MiB inline; save larger/other files in /tmp

Media

whatsapp_transcribe_audio

Transcribe with language and prompt hints

Media

whatsapp_generate_speech

Generate inline TTS audio; does not send it to WhatsApp

Contacts

whatsapp_check_number

Check whether a phone is registered

Contacts

whatsapp_list_contacts

Unified people and groups address book

Contacts

whatsapp_get_contact

Person or group detail

Store

whatsapp_search_messages

Search text plus indexed captions, OCR, summaries, tags, and documents

Store

whatsapp_contact_graph

Shared groups and mutual contacts

Store

whatsapp_chat_summary

Recent readable history, up to 100 messages

Store

whatsapp_stats

Activity totals and top chats/contacts

Store

whatsapp_import_chat

Import a local .zip/.txt WhatsApp export, up to 100 MiB

Auto-reply

whatsapp_auto_reply_enable

Enable person/group voice-note replies; optional contextual mode

Auto-reply

whatsapp_auto_reply_disable

Disable automatic voice-note replies

Auto-reply

whatsapp_auto_reply_status

Check enabled/found state

Auto-reply

whatsapp_auto_reply_list

List enabled people and groups

Automation

whatsapp_media_settings_get

Read per-conversation media policy

Automation

whatsapp_media_settings_update

Partially update capture/analysis/reply/archive policy

Automation

whatsapp_media_settings_disable

Turn every media automation flag off for a conversation

Automation

whatsapp_automation_health

Combined backend/listener/media/worker diagnostics

Media automation settings

whatsapp_media_settings_update supports:

  • captureEnabled

  • analyzeImages

  • analyzeDocuments

  • whatsappReplyEnabled

  • includeMediaInRecap

  • archiveMode: off, review, or auto

  • fixedNextcloudFolderId: integer or null

  • archiveConfirmationEnabled

  • allowSensitiveProcessing

  • askOnReview

Conversation settings are combined with backend-wide kill switches. Always inspect returned warnings or call whatsapp_automation_health before assuming a feature is active. The current public health/warning contract does not expose the global gates for recap inclusion or review questions.

Current backend limitations

  • Manual quote replies are not implemented by the public backend send route. Supplying replyTo returns an MCP error and sends nothing.

  • whatsapp_forward_message re-sends stored text. It does not preserve media, sender attribution, or WhatsApp's Forwarded label.

  • Some current GOWS media is still exposed as stored type chat; type filters may miss it until the backend public API switches to normalized_type.

  • Public chat summaries are not fully @lid alias-aware. Read/search are the safer choices for migrated histories.

  • Imported sender identities are history-only and are omitted from whatsapp_list_contacts; imported *@import chats support read/search but not live read receipts or chat summaries.

  • Durable staged-media preview, Nextcloud folder discovery, archive review/actions, and Motor/LLM configuration remain operator-only management functions.

Development and verification

npm ci
npm test                  # hermetic unit + backend-contract tests
npm run build
npm pack --dry-run

Releases are deployed by pushing a tag that exactly matches the package version, for example v2.4.0. The publish workflow repeats unit tests and the build before publishing to npm with the repository secret.

Live tests require WAHA_API_URL and WAHA_API_KEY:

npm run test:live                         # read-only suites
WAHA_TEST_LEVEL=2 npm run test:live       # includes self-chat writes
WAHA_TEST_LEVEL=3 npm run test:live       # includes configured contact writes

The default test and CI paths never contact WhatsApp.

Security

  • Treat the backend API key as a password; never commit it.

  • Sending through an unofficial WhatsApp API can trigger anti-abuse controls. Keep automation narrow and rate-limited.

  • Media and chat exports can contain sensitive data. Review automation policy before enabling analysis, replies, or archival.

  • Rotate any credential that has previously appeared in Git history.

License

MIT

Available Tools

22 tools
whatsapp_account_infoWhatsApp Account InfoA
Read-onlyIdempotent

Get information about the authenticated WhatsApp account.

Returns the phone number, display name, and WhatsApp ID of the connected account. Use this to verify which account is connected.

No parameters required.

Inputs: no named parameters.

whatsapp_auto_reply_disableDisable Auto-Reply TranscriptionA
Idempotent

Disable auto-reply with audio transcription for a contact.

Args:

  • phone: Phone number digits only, no @, no spaces (e.g., "5521986910666").

Returns:

  • status: "ok"

  • phone: the canonical phone

  • enabled: false

Inputs: phone (required).

whatsapp_auto_reply_enableEnable Auto-Reply TranscriptionA
Idempotent

Enable auto-reply with audio transcription for a contact.

When the contact sends a voice note, the transcription is sent back as a quoted reply automatically. DM only — voice notes in groups are never auto-replied even if a member is flagged.

The flag is contact/phone-scoped, so it follows the contact across WhatsApp's @c.us → @lid JID transitions automatically — no need to re-flag when WhatsApp migrates the JID.

Args:

  • phone: Phone number digits only, no @, no spaces (e.g., "5521986910666"). Look up via whatsapp_list_contacts first if you only know the name.

Returns:

  • status: "ok" on success

  • phone: the canonical phone

  • enabled: true

Inputs: phone (required).

whatsapp_auto_reply_listList Contacts with Auto-Reply EnabledA
Read-onlyIdempotent

List every contact that currently has auto-reply transcription enabled, with display names from Google Contacts (when matched) or WhatsApp push name fallback.

Returns:

  • contacts: array of { phone, display_name, person_name, push_name }

Inputs: no named parameters.

whatsapp_chat_summaryChat SummaryA
Read-onlyIdempotent

Get a readable summary of recent messages in a WhatsApp chat, including sender names and timestamps.

This is optimized for readability — use whatsapp_read_messages for structured data with filtering, or whatsapp_search_messages for full-text search.

Args:

  • contactId: Phone digits for a person, or "*@g.us" for a group

  • limit: Number of recent messages to include (1-200, default 50)

Returns:

  • chat: Name, type, message count, date range

  • messages: Recent messages with sender name, body, timestamp, type

Inputs: contactId (required), limit.

whatsapp_check_numberCheck WhatsApp NumberA
Read-onlyIdempotent

Check if a phone number is registered on WhatsApp.

Use this before sending a message to a number not yet in your address book.

Args:

  • phone: Phone number with country code, no spaces or dashes (e.g., "5511999999999")

Returns:

  • numberExists: true if registered on WhatsApp

  • contactId: The id to use as contactId in other tools (the same phone digits)

Inputs: phone (required).

whatsapp_contact_graphContact Social GraphA
Read-onlyIdempotent

Get social graph for a WhatsApp contact — shared groups, mutual connections.

Args:

  • phone: Phone number with country code (e.g., "5524999160115")

Returns:

  • groups: Groups this contact is in, with message counts

  • mutualContacts: Other contacts who share groups with this person

Inputs: phone (required).

whatsapp_delete_messageDelete WhatsApp MessageA
Destructive

Delete (unsend) a message from a contact's chat.

Removes the message for everyone. WhatsApp shows "This message was deleted" in its place.

Args:

  • contactId: Contact id: phone digits for a person (e.g. "5521986910666"; survives @c.us↔@lid flips), or a group JID "*@g.us". Look up via whatsapp_list_contacts.

  • messageId: Message ID to delete

Returns confirmation of deletion.

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

whatsapp_download_mediaDownload WhatsApp MediaA
Read-onlyIdempotent

Download media (image, audio, video, document) from a WhatsApp message.

Fetches the media attached to a specific message and returns it directly:

  • Images: returned inline so Claude can see them

  • Audio: returned inline so Claude can process them

  • Video/documents: saved to /tmp/whatsapp-media/ and path returned

Use whatsapp_read_messages first to find messages with hasMedia=true, then pass the contactId and messageId here.

Note: Old media (weeks+) may no longer be available on WhatsApp's servers.

Args:

  • contactId: Phone digits or "*@g.us" — the contact whose chat contains the message

  • messageId: Message ID with media to download (from whatsapp_read_messages)

Returns:

  • For images: the image content directly (Claude can see it)

  • For audio: the audio content directly

  • For other files: file path where it was saved + metadata

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

whatsapp_edit_messageEdit WhatsApp MessageA
Idempotent

Edit a previously sent text message.

Only works on messages you sent (fromMe=true). WhatsApp shows an "edited" label on the message after editing.

Args:

  • contactId: Contact id: phone digits for a person (e.g. "5521986910666"; survives @c.us↔@lid flips), or a group JID "*@g.us". Look up via whatsapp_list_contacts.

  • messageId: Message ID to edit (must be your own message)

  • text: New text content

Returns confirmation with the edited message ID.

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

whatsapp_forward_messageForward WhatsApp MessageA

Forward a message from one chat to another contact.

The forwarded message shows a "Forwarded" label in WhatsApp and preserves the original sender attribution.

Args:

  • contactId: Contact id: phone digits for a person (e.g. "5521986910666"; survives @c.us↔@lid flips), or a group JID "*@g.us". Look up via whatsapp_list_contacts. — destination

  • messageId: Message ID to forward (get from whatsapp_read_messages)

Returns confirmation with forwarded message ID.

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

whatsapp_get_contactGet Contact Detail (person or group)A
Read-onlyIdempotent

Detail for a single contact — person OR group, by stable id.

Returns shape depends on kind:

  • Person: contact (phone, names, email, org), all chats they appear in, all JID variants, message stats.

  • Group: chat (group metadata), members with display names, member_count.

Args:

  • contactId: phone digits (person; "5521986910666"), or "*@g.us" (group). Look up via whatsapp_list_contacts.

Inputs: contactId (required).

whatsapp_import_chatImport WhatsApp Chat ExportA
Idempotent

Import a WhatsApp chat export file (ZIP or TXT) into the message store.

Use this to backfill historical messages from WhatsApp's "Export Chat" feature. Only inserts new messages — won't overwrite or duplicate existing data.

The file should be a WhatsApp chat export:

  • ZIP file containing a .txt (standard WhatsApp export format)

  • Or a plain .txt file

The chat name is extracted from the filename (e.g., "Conversa do WhatsApp com NAME.zip"). You can override it with the chatName parameter.

Messages are matched to existing contacts by name. If a contact doesn't exist, it's created. If the chat already exists in the store (by name), messages are added to it.

Args:

  • filePath: Absolute path to the ZIP or TXT file on the server

  • chatName: Optional override for the chat name (extracted from filename if omitted)

Returns:

  • chat_name: Resolved chat name

  • total_parsed: Number of messages found in file

  • inserted: New messages added

  • skipped_duplicates: Messages already in store

  • senders: List of sender names found

Inputs: filePath (required), chatName.

whatsapp_list_chatsList WhatsApp ChatsA
Read-onlyIdempotent

List recent WhatsApp chats with last message preview and profile pictures.

Returns chat IDs, names, profile picture URLs, and a preview of the last message. Use the chat ID from results to read messages with whatsapp_read_messages.

Args:

  • limit: Number of chats to return (1-100, default 20)

  • offset: Pagination offset (default 0)

Returns array of chats with:

  • id: Chat ID (use this in other tools)

  • name: Contact or group name

  • picture: Profile picture URL (may expire)

  • lastMessage: Preview with body, from, fromMe, hasMedia, timestamp

  • lastMessageAt: ISO timestamp of last message

Inputs: limit, offset.

whatsapp_list_contactsList WhatsApp Contacts (people + groups)A
Read-onlyIdempotent

Unified address book — lists people you DM and groups you're in.

Use the returned 'id' as contactId in any chat-targeting tool (send_text, read_messages, etc.):

  • Person: id = phone digits (universal — survives @c.us↔@lid flips)

  • Group: id = group JID (e.g. "120363...@g.us")

Args:

  • kind: "person" | "group" | "all" (default "all")

  • search: Filter by name or id (optional)

  • limit: Maximum rows to return (1-100, default 20)

  • offset: Pagination offset for the persons section (default 0)

Returns array of contacts with:

  • kind: "person" | "group"

  • id: phone digits or group JID — pass to other tools

  • name: display name (Google Contact name → push name → phone/jid fallback)

  • messageCount, lastMessageAt: activity stats

  • For persons: pushName, googleName, email, organization

  • For groups: memberCount

Inputs: kind, search, limit, offset.

whatsapp_reactReact to WhatsApp MessageA
Idempotent

React to a WhatsApp message with an emoji.

Use an empty string for the reaction to remove an existing reaction.

Args:

  • contactId: Contact id: phone digits for a person (e.g. "5521986910666"; survives @c.us↔@lid flips), or a group JID "*@g.us". Look up via whatsapp_list_contacts.

  • messageId: Message ID to react to (get from whatsapp_read_messages)

  • reaction: Emoji to react with (e.g., "👍", "❤️", "😂"). Empty string removes reaction.

Returns confirmation of the reaction.

Inputs: contactId (required), messageId (required), reaction (required).

whatsapp_read_messagesRead WhatsApp MessagesA

Read messages from a specific WhatsApp chat.

Returns messages with sender, text content, timestamp, and message ID. Use the message ID from results for whatsapp_react or reply_to in whatsapp_send_text.

Powered by Message Store — persistent full history with full-text search and sender filtering.

Args:

  • contactId: Phone digits for a person ("5521986910666"; survives @c.us↔@lid flips), or group JID "*@g.us". Look up via whatsapp_list_contacts.

  • limit: Number of messages to return (1-100, default 20)

  • offset: Skip N messages for pagination (default 0)

  • search: Full-text search within this chat's messages (optional)

  • sender: Filter by sender name or JID (optional)

  • type: Filter by message type: chat, image, album (optional)

  • since: ISO date — messages after this date (optional)

  • until: ISO date — messages before this date (optional)

  • fromMe: Filter sent (true) or received (false) messages (optional)

  • downloadMedia: Include media download URLs when falling back to live (default false)

  • markAsRead: Mark messages as read after fetching (default false)

Returns:

  • messages: Array with id, sender, body, timestamp, type, fromMe, hasMedia

  • total: Total matching messages

  • hasMore: Whether more results exist

Inputs: contactId (required), limit, offset, search, +7 more.

whatsapp_search_messagesSearch WhatsApp MessagesA
Read-onlyIdempotent

Search across all WhatsApp message history. Supports full-text search, date ranges, sender filtering, and message type filtering.

Args:

  • search: Text to search for (case insensitive, supports Portuguese/unicode)

  • contactId: Scope search to one contact (phone digits or "*@g.us") (optional)

  • sender: Filter by sender name or JID (optional)

  • since: ISO date string — messages after this date (optional)

  • until: ISO date string — messages before this date (optional)

  • type: Message type filter: chat, image, album, e2e_notification (optional)

  • fromMe: Filter sent (true) or received (false) messages (optional)

  • limit: Results per page (1-100, default 20)

  • offset: Pagination offset (default 0)

Returns:

  • messages: Array with id, chatJid, senderName, body, timestamp, messageType, fromMe

  • total: Total matching messages

  • has_more: Whether more results exist

Note: sender_name may be null for some messages.

Inputs: search (required), contactId, sender, since, +5 more.

whatsapp_send_textSend WhatsApp Text MessageA

Send a text message to a contact (person or group).

CORE tier supports text messages only (no images, video, audio, or documents). A rate limit delay is enforced between sends to avoid WhatsApp detection.

Args:

  • contactId: Contact id: phone digits for a person (e.g. "5521986910666"; survives @c.us↔@lid flips), or a group JID "*@g.us". Look up via whatsapp_list_contacts.

  • text: Message text to send

  • replyTo: Optional message ID to quote-reply to (get from whatsapp_read_messages)

Returns:

  • status: "sent"

  • messageId: The sent message's ID

  • contactId: Where it was sent

Inputs: contactId (required), text (required), replyTo.

whatsapp_session_statusWhatsApp Session StatusA
Read-onlyIdempotent

Check if the WhatsApp session is connected and working.

Returns the session status (WORKING, STOPPED, etc.), the connected phone number, and display name. Use this to verify connectivity before sending messages.

No parameters required.

Returns:

  • name: Session name

  • status: "WORKING" if connected, "STOPPED" if disconnected

  • phone: Connected phone number (if authenticated)

  • pushName: Display name on WhatsApp

Inputs: no named parameters.

whatsapp_statsWhatsApp StatsA
Read-onlyIdempotent

Overview dashboard of WhatsApp activity — message totals, top chats, top contacts, and group/DM breakdown.

No arguments needed. Returns:

  • Totals: messages, contacts, chats, groups, DMs

  • Activity: messages today, this week

  • Top 5 chats by message count (name may be null for groups — use whatsapp_get_contact to look up)

  • Top 5 contacts by message count

Inputs: no named parameters.

whatsapp_transcribe_audioTranscribe WhatsApp AudioA

Transcribe a WhatsApp voice message or audio to text.

Server-side transcription via Speaches (Whisper). Optionally replies to the original message with the transcription text.

Args:

  • contactId: Phone digits or "*@g.us" — the contact whose chat contains the audio

  • messageId: Message ID of the audio to transcribe

  • replyWithTranscription: If true, sends the transcription as a WhatsApp reply to the audio message (default false)

Returns:

  • transcription: The transcribed text

  • language: Detected language (if available)

  • replyMessageId: ID of the reply message (if replyWithTranscription=true)

Inputs: contactId (required), messageId (required), replyWithTranscription.

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    A4.2/5.0

    Scored across 22 tools

    Disambiguation5/5

    Each tool has a clearly distinct purpose, from account info to message operations to auto-reply management. No two tools appear to do the same thing, and descriptions clarify boundaries (e.g., chat_summary vs read_messages vs search_messages).

    Naming Consistency4/5

    All tools share the 'whatsapp_' prefix and mostly follow a verb_noun pattern (e.g., delete_message, send_text). A few deviate slightly (e.g., account_info, stats, session_status are noun_noun or noun only), but the overall pattern is clear and consistent.

    Tool Count4/5

    With 22 tools, the count is slightly above the ideal range but still well-scoped for a comprehensive WhatsApp server. Each tool covers a distinct operation, and none feel redundant or excessive.

    Completeness4/5

    The tool set covers most core WhatsApp operations: account management, contacts, chats, messages (send, read, edit, delete, forward, react, download media, transcribe), and auto-reply. Notable gaps include sending media (images, files) and group management, but the core workflow is well-supported.

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables Claude to read and send WhatsApp messages through a self-hosted REST API, supporting multi-user sessions, media, groups, contacts, and webhooks.
      4 npm
      MIT
    • F
      license
      Not graded
      quality
      A
      maintenance
      Enables a Claude Code session to send and receive WhatsApp messages from a linked personal account or the official Cloud API, including photos, voice notes and documents, with local voice transcription and allowlist-based access control. It also lets users approve or deny Claude's tool requests remotely by emoji reaction and keeps per-chat personalities, cron jobs and conversation context across restarts.
      -