WhatsApp MCP Server

WhatsApp MCP Server

Enables Claude to read and send WhatsApp messages, including media and call history, via a local bridge.

Category
访问服务器

README

WhatsApp MCP Server

CI License: MIT Python 3.11+ Go 1.24+

A Model Context Protocol (MCP) server for WhatsApp, enabling Claude to read and send WhatsApp messages.

Originally created by Luke Harries. Maintained by Very Good Plugins.

Features

  • Message Management: Search and read personal WhatsApp messages (text, images, videos, documents, audio)
  • Contact Search: Search contacts by name or phone number with sender_display format ("Name (phone)")
  • Send Messages: Send text messages to individuals or groups
  • Media Support: Send and download images, videos, documents, and voice messages
  • Call History: Capture incoming voice/video calls into a local SQLite table (live, 1:1 and group)
  • Webhook Integration: Forward incoming messages to external services
  • Local Storage: All messages stored locally in SQLite - only sent to Claude when you allow it

Installation

Prerequisites

  • Go 1.24+
  • Python 3.11+
  • uv package manager
  • Claude Desktop or Cursor
  • FFmpeg (optional, for voice message conversion)

Quick Start

  1. Clone the repository

    git clone https://github.com/verygoodplugins/whatsapp-mcp.git
    cd whatsapp-mcp
    
  2. Start the WhatsApp bridge

    cd whatsapp-bridge
    go run .
    

    Scan the QR code with WhatsApp on your phone to authenticate.

  3. Configure Claude Desktop

    Add to ~/Library/Application Support/Claude/claude_desktop_config.json:

    {
      "mcpServers": {
        "whatsapp": {
          "command": "whatsapp-mcp"
        }
      }
    }
    

    The whatsapp-mcp console script is installed by pip install -e . (or pipx install .) from the repo root. If you'd rather not install editable, you can call the module directly:

    {
      "mcpServers": {
        "whatsapp": {
          "command": "python",
          "args": ["-m", "whatsapp_mcp"],
          "cwd": "/path/to/whatsapp-mcp"
        }
      }
    }
    

    Replace /path/to/whatsapp-mcp with your actual repo path.

  4. Restart Claude Desktop

Updating

Pull the latest changes, then refresh whichever components moved:

git pull
You changed What to do
Bridge code (whatsapp-bridge/*.go) and you run go run . Nothing — go run recompiles each launch. Just restart the bridge.
Bridge code and you run a built binary cd whatsapp-bridge && go build -o whatsapp-bridge && ./whatsapp-bridge
MCP server (src/whatsapp_mcp/*.py, pyproject.toml) Restart Claude Desktop / Cursor. If you installed with -e, edits are picked up immediately; otherwise re-run pip install -e . to refresh the entry point.

Updates do not require re-pairing or deleting whatsapp.db — your session and message history are preserved. Re-pairing is only needed when explicitly requesting full history (see Requesting full history).

Cursor IDE Configuration

Add to your Cursor MCP settings (~/.cursor/mcp.json):

{
  "mcp": {
    "servers": {
      "whatsapp": {
        "command": "whatsapp-mcp"
      }
    }
  }
}

Tools

Messages include sender_display showing "Name (phone)" format for easy identification by agents.

Contact Operations

search_contacts

Search contacts by name or phone number.

Parameters:

  • query (required): Name or phone number to search

Natural Language Examples:

  • "Find contacts named John"
  • "Search for phone number 555-1234"
  • "Who has the phone number starting with +1?"

get_contact

Resolve a WhatsApp contact name from a phone number, LID, or full JID.

Parameters:

  • identifier (required): Phone number, LID, or full JID (aliases: phone_number, phone)
    • Examples: 12025551234, 184125298348272, 12025551234@s.whatsapp.net, 184125298348272@lid

Natural Language Examples:

  • "What's the name for phone number 5551234567?"
  • "Look up who owns this number"
  • "Who is 184125298348272@lid?"

Message Operations

list_messages

Get messages with filters, date ranges, and sorting.

Parameters:

  • chat_jid (optional): Filter by specific chat JID
  • limit (optional): Number of messages (default 50, max 500)
  • before_date (optional): Messages before this date (YYYY-MM-DD)
  • after_date (optional): Messages after this date (YYYY-MM-DD)
  • sort_by (optional): "newest" or "oldest" (default "newest")

Natural Language Examples:

  • "Show me the last 100 messages from today"
  • "Get messages from the family group chat"
  • "Find messages from last week"

send_message

Send a text message to a contact or group.

Parameters:

  • recipient (required): Phone number or group JID
  • message (required): Text content to send

Natural Language Examples:

  • "Send 'Hello!' to +1234567890"
  • "Message the team group saying 'Meeting at 3pm'"

send_file

Send a media file (image, video, document).

Parameters:

  • recipient (required): Phone number or group JID
  • file_path (required): Path to the file
  • caption (optional): Caption for the media

send_audio_message

Send a voice message (automatically converts to Opus .ogg format).

Parameters:

  • recipient (required): Phone number or group JID
  • file_path (required): Path to audio file

download_media

Download media from a received message.

Parameters:

  • message_id (required): ID of the message with media
  • chat_jid (required): JID of the chat containing the message

Chat Operations

list_chats

List all chats with metadata.

Parameters:

  • limit (optional): Number of chats (default 50, max 200)

get_chat

Get specific chat metadata by JID.

Parameters:

  • jid (required): Chat JID

get_direct_chat_by_contact

Find a direct message chat with a contact.

Parameters:

  • phone (required): Phone number of the contact

get_contact_chats

List all chats involving a specific contact.

Parameters:

  • phone (required): Phone number of the contact

get_last_interaction

Get the last message exchanged with a contact.

Parameters:

  • phone (required): Phone number of the contact

get_message_context

Get messages around a specific message for context.

Parameters:

  • message_id (required): ID of the target message
  • chat_jid (required): JID of the chat
  • before (optional): Number of messages before (default 5)
  • after (optional): Number of messages after (default 5)

Configuration

Copy .env.example to .env and configure as needed:

Variable Default Description
WHATSAPP_BRIDGE_PORT 8080 Port for Go bridge REST API
WEBHOOK_URL http://localhost:8769/whatsapp/webhook Webhook for incoming messages
FORWARD_SELF false Forward messages sent by self
WHATSAPP_DB_PATH ../whatsapp-bridge/store/messages.db Path to SQLite database
WHATSMEOW_DB_PATH ../whatsapp-bridge/store/whatsapp.db whatsmeow DB used for LID ↔ phone resolution
WHATSAPP_API_URL http://localhost:8080/api Go bridge REST API URL

CLI flags (Go bridge)

Flag Default Description
--full-history-pair false Request full history at pair time. Only takes effect on a fresh pair (no existing whatsapp.db); no-op for already-paired sessions. The phone ultimately decides the actual history window sent — see Requesting full history below.

Requesting full history

whatsmeow's default pairing asks for "recent sync" — roughly the last 3 months, with the exact window decided by the phone. If you want to pull more history at pair time:

# Stop the bridge
launchctl bootout gui/$UID/com.whatsapp-bridge    # or however you manage it

# Back up, then remove the auth session (keeps messages.db intact)
cp whatsapp-bridge/store/whatsapp.db{,.bak}
rm whatsapp-bridge/store/whatsapp.db

# Re-pair with the flag
cd whatsapp-bridge
./whatsapp-bridge --full-history-pair
# Scan the QR with WhatsApp → Settings → Linked Devices → Link a Device
# Wait for "History sync complete" in the logs (can take 10-30 minutes)
# Ctrl+C when sync has quiesced, then restart under your normal process manager

Caveats:

  • The phone decides the actual cap. The flag requests up to 10 years / 100 GB, but WhatsApp's iOS primary device enforces its own retention policy. iPad companion is documented at ~1 year max; other linked devices appear to follow similar logic.
  • Only effective on a fresh pair. With whatsapp.db already present, no new pair handshake fires and the flag is a no-op.
  • Messages the phone has deleted are not recoverable — auto-expire, low-storage cleanup, and manual delete all leave no trace for the phone to share.

Call History

The bridge captures incoming WhatsApp voice and video calls live into a dedicated calls table in messages.db. When a 1:1 call arrives (CallOffer) or a group call is announced (CallOfferNotice), a row is inserted with result='in_progress'. Subsequent CallAccept / CallReject / CallTerminate events update the row — final result becomes answered, rejected, missed, or ended depending on the event sequence. See the state-machine comment above StoreCallOffer in main.go for the exact transitions.

Schema

CREATE TABLE calls (
    call_id TEXT,
    chat_jid TEXT,          -- group JID for group calls, call creator JID for 1:1
    from_jid TEXT,          -- JID of whoever started the call
    timestamp TIMESTAMP,    -- call start time
    is_from_me BOOLEAN,
    call_type TEXT,         -- 'voice' or 'video'
    is_group BOOLEAN,
    result TEXT,            -- 'in_progress' | 'answered' | 'ended' |
                            --   'missed' | 'rejected'
    duration_sec INTEGER,   -- computed when the call terminates
    ended_at TIMESTAMP,
    reason TEXT,            -- terminate reason string from whatsmeow
    PRIMARY KEY (call_id, chat_jid)
);

Caveats

  • Outbound calls are not captured. WhatsApp's primary device handles calls it initiates without notifying linked devices, so the bridge never sees an event for them.
  • Call results only reflect what the bridge saw. If the bridge is offline when a call happens, the events are lost.
  • 1:1 calls default to call_type='voice'. CallOffer events don't expose media type directly (it's buried in the binary call data). Group calls via CallOfferNotice include a Media field and are recorded accurately as voice or video.

Architecture

flowchart TB
    subgraph Clients["AI Clients"]
        CD[Claude Desktop]
        CU[Cursor IDE]
        CC[Claude Code]
    end

    subgraph MCP["MCP Layer"]
        PY[Python MCP Server<br/>FastMCP]
    end

    subgraph Bridge["WhatsApp Bridge"]
        GO[Go Bridge<br/>whatsmeow]
        DB[(SQLite<br/>messages.db)]
        WH[Webhook Handler]
    end

    subgraph External["External Services"]
        WA[WhatsApp Web API]
        EXT[External Webhook<br/>Receiver]
    end

    CD & CU & CC -->|MCP Protocol| PY
    PY -->|REST API| GO
    PY -->|Read| DB
    GO -->|Store| DB
    GO <-->|WebSocket| WA
    GO -->|Forward Messages| WH
    WH -->|POST| EXT

Component Details

flowchart LR
    subgraph GoAPI["Go Bridge REST API"]
        direction TB
        SEND["/api/send"]
        DOWN["/api/download"]
        TYPE["/api/typing"]
        HEALTH["/api/health"]
    end

    subgraph MCPTools["MCP Tools (14 total)"]
        direction TB
        CONT["Contact Tools<br/>search_contacts, get_contact"]
        MSG["Message Tools<br/>list_messages, send_message, etc."]
        CHAT["Chat Tools<br/>list_chats, get_chat, etc."]
        MEDIA["Media Tools<br/>send_file, download_media, etc."]
    end

    MCPTools -->|HTTP Requests| GoAPI

Data Flow

sequenceDiagram
    participant User as User
    participant Claude as Claude Desktop
    participant MCP as Python MCP Server
    participant Bridge as Go Bridge
    participant WA as WhatsApp

    User->>Claude: "Send 'Hello' to Mom"
    Claude->>MCP: send_message(recipient, message)
    MCP->>Bridge: POST /api/send
    Bridge->>WA: Send via WebSocket
    WA-->>Bridge: Delivery confirmation
    Bridge-->>MCP: Success response
    MCP-->>Claude: Message sent
    Claude-->>User: "Message sent to Mom"

Incoming Message Flow

sequenceDiagram
    participant WA as WhatsApp
    participant Bridge as Go Bridge
    participant DB as SQLite
    participant WH as Webhook
    participant EXT as External Service

    WA->>Bridge: New message
    Bridge->>DB: Store message
    Bridge->>Bridge: Auto-download media
    Bridge->>WH: Forward to webhook
    WH->>EXT: POST with message data
    Note over EXT: Process incoming message

Development

Running Tests

pip install -e ".[dev]"
pytest -m "not integration"

Linting

# Python
ruff check .
ruff format .
mypy src

# Go
cd whatsapp-bridge
golangci-lint run

Building

# Go bridge
cd whatsapp-bridge
go build -o whatsapp-bridge

# Run the binary
./whatsapp-bridge

# During development (avoids stale binaries)
go run .

Releasing (Maintainers)

Releases use Release Please automation; maintainer steps and fallback procedures are documented in docs/RELEASING.md.

Troubleshooting

Authentication Issues

  • QR Code Not Displaying: Restart the bridge. Check terminal QR code support.
  • Device Limit Reached: Remove a linked device from WhatsApp Settings > Linked Devices.
  • No Messages Loading: Initial sync can take several minutes for large chat histories.
  • Out of Sync: Delete whatsapp-bridge/store/*.db files and re-authenticate.

Windows

Windows requires CGO for go-sqlite3. Install MSYS2 and enable CGO:

go env -w CGO_ENABLED=1
go run .

Security Notice

Caution: As with many MCP servers, this is subject to the lethal trifecta. Prompt injection could lead to private data exfiltration. Use with awareness.

License

MIT License - see LICENSE for details.

Credits & History

This project is a maintained fork of lharries/whatsapp-mcp, originally created by Luke Harries.

Why we forked: The original repository hasn't been updated since April 2025. We needed continued maintenance, bug fixes, and new features for production use.

Highlights since the fork:

  • /api/typing, /api/health, and webhook forwarding (with reply context + image media)
  • Auto-download of incoming media with collision-safe filenames
  • get_contact tool, sender_display field, and LID ↔ phone resolution via the whatsmeow store
  • Live capture of incoming voice/video calls into a calls table
  • --full-history-pair flag to request extended history at pair time
  • Resilience: recovers from StreamReplaced session conflicts; pinned anyio to dodge a cancel-scope regression
  • CI/CD with GitHub Actions, Release Please for automated versioning, and Dependabot

The full release-by-release list lives in CHANGELOG.md.

Recent contributors (huge thanks):

  • @edmenendez — call capture (#39), full-history flag (#37), caption surfacing (#42), media filename collisions (#40), download race fix (#41), LID matching (#43), contact resolution via whatsmeow store (#30)
  • @davidsimoes — StreamReplaced recovery (#27)
  • @davidggphy — LID → phone JID consistency (#12)
  • @maikol-solis — bridge run command fix (#23)
  • @DeetBot — anyio cancel-scope pin (#44)

And to Luke for creating the original project. See CONTRIBUTING.md if you'd like to join in.

Links

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选