WhatsApp MCP Server

WhatsApp MCP Server

Connects WhatsApp group chats to Claude, enabling reading, searching, exporting, replying, and AI-powered intelligence processing of conversations.

Category
Visit Server

README

WhatsApp MCP Server

Your WhatsApp groups are a live intelligence network. This server lets Claude read them.

An open-source MCP server that connects WhatsApp group chats to Claude (and any MCP-compatible AI client). It exposes seven tools for reading, searching, exporting, and replying to group conversations — plus a chat intelligence processor that extracts themes, opportunities, and actionable briefings from hundreds of messages.

I built this because I'm in a dozen professional WhatsApp groups — practitioners, investors, founders — where the information density is remarkable and the retrieval rate is abysmal. WhatsApp is optimized for conversation, not comprehension. This server fixes that.


What It Does

Seven MCP tools give Claude (or any MCP client) structured access to your WhatsApp groups:

Tool What It Does
whatsapp_list_groups Every group you belong to, sorted by recent activity
whatsapp_get_messages Pull messages from any group with date range filtering
whatsapp_group_info Metadata, participants, descriptions
whatsapp_search_messages Keyword search across all groups or scoped to one
whatsapp_export_chat Full export in WhatsApp's native .txt format
whatsapp_send_message Send a message to any group (fuzzy name matching)
whatsapp_reply_to_message Reply to a specific message as a quoted reply

All tools support fuzzy group name matching — say "Book Club" and it finds "Book Club — Monthly Reads" using Levenshtein distance + substring matching. Nobody remembers exact group names. The system shouldn't require you to.

A chat intelligence processor turns raw messages into structured briefings:

  • Themes — recurring topics tagged as hot, important, or emerging
  • Big ideas — intellectually interesting or actionable, flagged by relevance to your work
  • Opportunities — collaboration, speaking, partnerships, content ideas, business leads
  • Participation analysis — what you engage with vs. skip, where you're visible vs. silent
  • Live threads — active conversations worth jumping into, with suggested messages
  • Notable quotes — standout lines worth saving or citing
  • Cross-group synthesis — amplified signals, network nodes, compounding opportunities that only appear when you look across groups

The intelligence processor was inspired by Scott Walker (Founder & CEO, UpShift Collective), who built the Junto Group Analyzer — a Claude skill he shared with our professional group that demonstrated the value of structured analysis over raw message consumption. His six-output framework (themes, big ideas, opportunities, participation analysis, live threads, notable quotes) proved the concept. This implementation extends it into a real-time MCP server with multi-group synthesis and configurable professional context.


Architecture

┌─────────────┐     stdio      ┌───────────────┐    WebSocket    ┌──────────────┐
│ Claude Code │◄──────────────►│  MCP Server   │◄───────────────►│  WhatsApp    │
└─────────────┘                │  (index.ts)   │  Noise/Signal   │  Multi-Device│
                               └───────────────┘                 └──────────────┘
┌─────────────┐   HTTP/SSE     ┌───────────────┐
│   Cowork    │◄──────────────►│  HTTP Server  │  (same WhatsApp client)
│  (Desktop)  │  + cloudflared │ (http-server) │
└─────────────┘                └───────────────┘

Two transport modes, one WhatsApp client:

  • Claude Code → stdio transport (index.ts) — direct pipe, single session
  • Cowork / Desktop → StreamableHTTP transport (http-server.ts) — multi-session over HTTPS via Cloudflare tunnel

WhatsApp has no open API for group chats. The Business API is for customer messaging only. So this server uses Baileys — a direct WebSocket implementation of the WhatsApp Multi-Device protocol. No headless browser, no DOM scraping. Credentials and Signal Protocol keys persist to .baileys_auth-<session>/ via useMultiFileAuthState, and the client reconnects in roughly two seconds after restarts.

Every read and write flows through an AsyncMutex that serializes WhatsApp operations behind a FIFO queue with a 100ms minimum interval. Baileys is reentrant-safe, but Signal Protocol session setup on unfamiliar recipients benefits from serialization, and the mutex keeps us well under WhatsApp's rate-limit thresholds without having to reason about them explicitly.

Messages stream in over the WebSocket and land in an in-memory ring buffer — 500 messages per group, JID-keyed — that the tool layer reads from. The buffer snapshots to .baileys_auth-<session>/buffer.json every 60 seconds and rehydrates on boot. This is load-bearing, not optional: the messages.history-set event that Baileys emits on first pairing is a one-shot, so on any reconnect the snapshot is the only thing standing between you and a cold buffer.

A readiness gate keeps this honest. Tool calls return 503 Service Unavailable until the WebSocket has reached connection.update → open AND the buffer is warm (either messages.history-set has drained or 30 seconds have elapsed). The server never crashes into half-initialized state, and clients get a clean retryable error instead.


Setup

Prerequisites

  • Node.js 22+
  • A WhatsApp account (pairs via QR code on first run)

Install and Build

git clone https://github.com/ericporres/whatsapp-mcp-server.git
cd whatsapp-mcp-server
npm install
npm run build

First Run — QR Pairing

WHATSAPP_SESSION_NAME=my-session node dist/mcp-server/index.js

Scan the QR code with WhatsApp on your phone. Credentials and Signal keys cache in .baileys_auth-my-session/ — you won't need to scan again unless you remove that directory or revoke the linked device from your phone.

Register with Claude Code

Add to ~/.claude.json:

{
  "mcpServers": {
    "whatsapp": {
      "command": "node",
      "args": ["/path/to/whatsapp-mcp-server/dist/mcp-server/index.js"],
      "env": {
        "WHATSAPP_SESSION_NAME": "my-session"
      }
    }
  }
}

Then ask Claude: "What WhatsApp groups am I in?"

HTTP Server (Cowork / Remote Access)

The HTTP server supports multiple concurrent MCP sessions. Each initialize handshake spawns a fresh Server + Transport pair. All sessions share the single WhatsApp client (protected by the mutex). Sessions are tracked in a Map<string, McpSession> with 30-minute TTL and automatic cleanup.

Pick any free high port on your machine and set it as MCP_HTTP_PORT. The server binds to 127.0.0.1 only — a tunnel or reverse proxy is responsible for exposing it.

# pick any free high port on your machine
MCP_HTTP_PORT=<your-port> node dist/mcp-server/http-server.js

Expose over HTTPS with a Cloudflare tunnel:

# Quick tunnel (temporary URL)
cloudflared tunnel --url http://localhost:$MCP_HTTP_PORT

# Named tunnel (stable URL — recommended for persistent setups)
cloudflared tunnel run your-tunnel-name

Securing the Tunnel

The server runs locally — your machine, your data, your paired WhatsApp session. But exposing it via a Cloudflare tunnel creates a public HTTPS endpoint. You should lock it down.

Security tiers (pick your comfort level):

Tier What It Does Effort Notes
Obscurity (default) Long random subdomain — mcp-random-words-123.yourdomain.com Zero — automatic Treat the URL like a password
IP Restriction Cloudflare Access policy allows only your IP 5 min in Zero Trust dashboard See caveat below
Bearer Token Server validates Authorization header on every request ~20 lines in http-server.ts Requires client support for custom headers
Email OTP Cloudflare Access sends a one-time code to your email 10 min in Zero Trust dashboard Works if your client handles browser auth flows
OAuth/OIDC (recommended for remote) Full identity provider integration (Google, Okta, etc.) 30 min — identity provider config Best option for cloud-hosted MCP clients

Important caveat about IP restriction: Cloudflare Access IP whitelisting works well for clients that connect from your local machine (like Claude Code via stdio). However, cloud-hosted MCP clients — including Claude Cowork, and potentially other platforms that proxy MCP connections through their own infrastructure — connect from the platform's IP addresses, not yours. An IP whitelist locked to your home network will block these clients. I learned this the hard way: the tunnel was healthy, the server was running, and Cloudflare was dutifully rejecting every legitimate request from the desktop app I built this for.

For local-only access (Claude Code, stdio): Obscurity alone is sufficient — the tunnel isn't even needed since stdio is a direct pipe.

For remote access (Cowork, Cursor, HTTP clients): Obscurity is the practical baseline today. The random subdomain is effectively unguessable, and your tunnel URL should never appear in public repos, articles, or documentation. For stronger security, OAuth/OIDC is the recommended path — it's the only auth mechanism that both Cloudflare Access and cloud-hosted MCP clients (like Cowork's custom connector) natively support. Bearer tokens require custom HTTP headers, which not all MCP client UIs expose.

For bearer token authentication, set MCP_AUTH_TOKEN in your environment and the HTTP server will validate the Authorization: Bearer <token> header on every request. See http-server.ts for implementation. Note: this requires your MCP client to support custom request headers.

macOS Persistence (LaunchAgents)

For always-on operation — server starts at login, tunnel reconnects automatically, logs to ~/Library/Logs/:

# Edit the variables at the top of the script first (SESSION_NAME, MCP_PORT, TUNNEL_TOKEN)
chmod +x scripts/setup-persistence.sh
./scripts/setup-persistence.sh

Templates for the LaunchAgent plists are in config/. The script substitutes your paths, your chosen port, and your tunnel token, then loads them.


Configuring the Intelligence Processor

The processor ships with a generic EXAMPLE_CONTEXT in src/processor/analyzer.ts. Replace it with your own professional context:

export const EXAMPLE_CONTEXT: UserContext = {
  name: 'Your Name',
  aliases: ['YourName', 'yourname'],
  role: 'Your role and company',
  focusAreas: [
    'your focus area 1',
    'your focus area 2',
    'your product or platform',
  ],
  opportunityTypes: [
    'partnerships',
    'speaking',
    'pain points your product solves',
    'content ideas',
  ],
  contentOutlets: ['Your Newsletter', 'LinkedIn'],
};

This context is the difference between generic summaries and personalized intelligence. The analyzer uses it to flag opportunities that map to your work, assess your participation patterns, and surface cross-group signals that matter to you specifically.

Rebuild after editing: npm run build


Cowork Plugin

The plugin/ directory contains a Claude Desktop (Cowork) plugin with a /whatsapp slash command. It triggers the full intelligence pipeline: pull messages from your configured groups, run the analyzer, generate a structured briefing. Say "check my WhatsApp" and get the five things that actually matter.


Project Structure

src/
├── mcp-server/
│   ├── index.ts          # Stdio transport (Claude Code)
│   ├── http-server.ts    # StreamableHTTP transport (Cowork + tunnel)
│   ├── tools.ts          # MCP tool definitions + fuzzy group matching
│   ├── types.ts          # Zod schemas for tool inputs
│   └── whatsapp.ts       # Baileys client wrapper + ring buffer + mutex
└── processor/
    ├── parser.ts         # Multi-format chat parser
    ├── analyzer.ts       # Theme/idea/opportunity extraction (← customize this)
    └── briefing.ts       # Formatted intelligence briefing output
config/                   # LaunchAgent plist templates
scripts/                  # Setup automation
plugin/                   # Cowork slash command plugin

Design Decisions

Baileys over a headless browser. An earlier cut of this server drove WhatsApp Web through Puppeteer. It worked, but every failure mode was a browser failure — page-context crashes on large fetches, stale DOM references after reconnects, memory leaks from orphaned Chromium processes. Baileys speaks the WhatsApp Multi-Device protocol directly over a WebSocket. No browser, no DOM, no Chromium. Reconnects take two seconds instead of fifteen, and the whole surface area collapses to "is the socket open and is the buffer warm."

In-memory ring buffer + disk snapshot. Baileys streams messages in real time via messages.upsert, but its historical sync (messages.history-set) fires once, on the initial pairing. Every subsequent reconnect delivers only live traffic. That's a trap: a restart would otherwise start from an empty buffer and tools would return stale or partial results. The server keeps a 500-message-per-group ring buffer in memory, snapshots it to .baileys_auth-<session>/buffer.json every 60 seconds, and rehydrates on boot. The snapshot is load-bearing — do not treat it as a cache.

Readiness gate, not a spinlock. On cold start there's a window between "process alive" and "ready to serve." The server doesn't answer tool calls during that window; it returns 503 Service Unavailable with a retry hint until connection.update → open fires AND the buffer is either drained from history-set or 30 seconds have elapsed. Clients that retry sensibly get clean results. Clients that don't fail fast instead of getting silently wrong data.

AsyncMutex over rate limiting. Every WhatsApp operation — reads, writes, metadata lookups — flows through a FIFO queue with a 100ms minimum interval between operations. Baileys itself is reentrant-safe, but Signal Protocol session setup on unfamiliar recipients benefits from serialization, and the mutex keeps us comfortably under WhatsApp's rate-limit thresholds without having to model them.

Multi-session HTTP server. The StreamableHTTP transport generates unique session IDs. Each Cowork initialize creates a fresh MCP Server + Transport pair. All sessions share the single WhatsApp client (already protected by the mutex). The Map<string, McpSession> tracks active sessions with 30-minute TTL — stale sessions are cleaned up automatically.

Fuzzy group name matching. Levenshtein distance + substring matching, case-insensitive. "book club" finds "Book Club — Monthly Reads." This is a small detail that makes the difference between a system you use daily and one you abandon after a week.

Write tools require the same mutex. whatsapp_send_message and whatsapp_reply_to_message go through the same AsyncMutex as every read. Quoted replies use Baileys' quoted field on sendMessage, so they render as native quoted messages on all clients — phones, desktop, web.

Context > Intelligence. The gap between a chatbot and a useful assistant is almost never a smarter model — it's better context. The EXAMPLE_CONTEXT object is a few lines of configuration that transforms the analyzer from generic summarization to personalized intelligence. A well-informed current model beats a brilliant amnesiac every time.


Acknowledgments

The chat intelligence processor was inspired by Scott Walker (Founder & CEO, UpShift Collective), who built the Junto Group Analyzer — a Claude skill that transforms WhatsApp group exports into structured intelligence briefings. Scott shared it as a gift to our professional group, and the six-output framework (themes, big ideas, opportunities, participation analysis, live threads, notable quotes) proved the concept: structured analysis of group conversations surfaces signal that passive consumption misses entirely. This project extends that framework into a real-time MCP server with multi-group synthesis and configurable professional context.

Built with Baileys, the MCP TypeScript SDK, and Cloudflare Tunnels.


License

MIT — clone it, fork it, make it yours.

If you build something interesting on top of it, I'd like to hear about it: github@porres.com or @eporres on LinkedIn.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured