Skip to content
Conduit

mcp server

whatsrust

WhatsApp in pure Rust. Single binary, 5 MB, 15 MB RAM. 54 API endpoints, 30 MCP tools, full protocol.

199-biotechnologies/whatsrustcommunitylistedunreviewed

Set up

Runs on your computer. Pick your agent and operating system.

This project does not publish an install method we can turn into a config. Follow the README instead.

README

synced Oct 17, 2026

WhatsRust

WhatsApp in pure Rust. One 5 MB binary. 15 MB RAM. No Node.js required.

Star this repo    Follow @longevityboris

Rust   License: MIT   54 API Endpoints   30 MCP Tools   PRs Welcome


A single Rust binary that handles the full WhatsApp Web protocol: text, images, audio, video, stickers, reactions, edits, polls, status stories, groups, and chat management. No npm. No Python. No Docker. Just cargo build and scan the QR code.

Install | How It Works | Features | API | MCP Tools | Contributing


Why WhatsRust exists

Every WhatsApp automation library follows the same playbook: Node.js, Baileys, and a node_modules folder the size of a small country. It works until 3 AM when the process crashes, the memory leak finally wins, and you're reading someone else's JavaScript trying to figure out what went wrong.

We needed WhatsApp inside agent software and got tired of babysitting a Node sidecar. So we replaced it with one Rust binary.

Before vs After

Node.js + BaileysWhatsRust
LanguageJavaScript / Node.jsRust
Install size~200 MB with node_modules5 MB single binary
Memory usage~50-120 MB idle~15 MB
Dependenciesnpm install + hopecargo build
Crash recoveryRoll your ownSQLite-backed queue + per-message backoff
APINone built-in54 REST endpoints + CLI + MCP server
Status/storiesDIYText, image, video, revoke -- all built in
Chat managementManual API calls12 operations (pin, mute, archive, star...)
Group managementManual12 methods, full CRUD
Anti-ban protectionNoneRead receipt batching, typing sim, jitter
AI agent supportNone30 MCP tools for Claude Code, etc.

Install

git clone https://github.com/199-biotechnologies/whatsrust
cd whatsrust && cargo run

Scan the QR code with your phone. That's it.

# Phone number pairing instead of QR
WHATSAPP_PAIR_PHONE="+1234567890" cargo run

# With sender allowlist + custom port
WHATSAPP_ALLOWED="1234567890" WHATSRUST_PORT=8080 cargo run

How it works

WhatsRust runs as a daemon with a built-in REPL, REST API, and MCP server. Every outbound message goes through a durable SQLite queue -- messages survive crashes and restarts. Inbound messages are deduplicated with a generation-tracked concurrent map.

src/
  bridge.rs          Core: events, messaging, queue, groups, chat management
  outbound.rs        21 typed outbound ops, durable SQLite queue
  bridge_events.rs   Broadcast event bus (tokio::sync::broadcast)
  api.rs             REST API (54 endpoints) + SSE + CLI HTTP client
  mcp.rs             MCP server (30 tools, JSON-RPC over stdio)
  storage.rs         rusqlite Signal Protocol store + schema migrations
  polls.rs           Poll crypto (HKDF-SHA256 + AES-256-GCM)
  dedup.rs           Generation-tracked DashMap (concurrent-safe)
  read_receipts.rs   Batched receipt scheduler
  qr.rs              QR rendering (terminal/PNG/HTML/SVG)
  instance_lock.rs   flock-based single-instance guard
  main.rs            Daemon (REPL) + CLI (54 commands) + MCP mode
  lib.rs             Library crate exports

~11,000 lines across 13 files. Built on whatsapp-rust (v0.5.0, MIT) for the protocol layer.

Four ways to run it

ModeHow
Daemoncargo run -- REPL with 54 commands
CLIwhatsrust send 15551234567 "Hello" -- JSON to stdout
LibraryWhatsAppBridge::start(config, tx, cancel) -- embed in your Rust app
MCP serverwhatsrust mcp -- 30 tools for AI agents (Claude Code, etc.)

Features

Every WhatsApp message type

Text, image, audio/voice, video, document, sticker, location, contact card, reaction (add/remove), edit, revoke, reply/quote, forward, view-once (image/video), poll (create + encrypted vote decryption), status/story (text/image/video/revoke).

Chat management (12 operations)

Pin/unpin, mute/unmute, archive/unarchive, mark read/unread, delete chat, delete message for me, star/unstar. Direct app-state mutations that sync across all linked devices.

Full group management

List groups, get info, create, rename, set description, add/remove/promote/demote participants, invite links. Group metadata cached with TTL and mutation invalidation.

Status/story posting

Text stories with custom background colors and fonts. Image and video stories. Revoke posted stories. Privacy controls (contacts, allowlist, denylist). All go through the durable outbound queue.

Stays alive

  • Crash-safe outbound queue in SQLite. Messages survive restarts.
  • Atomic dedup with generation-tracked DashMap. No double-processing under concurrent handlers.
  • Per-message exponential backoff. One stuck message doesn't block the rest.
  • Graduated reconnect backoff with jitter. Not the naive kind.
  • Graceful shutdown. Drains in-flight messages on SIGINT/SIGTERM.
  • Single-instance flock. Two bridges can't fight over one session.
  • SQLite backup on startup and shutdown. WAL mode, no corruption.

Doesn't get you banned

  • Read receipt batching. Groups message IDs per chat into single stanzas on a 200 ms coalesce.
  • Flush-before-reply. Marks messages as read before responding.
  • Recording indicator before voice notes.
  • Configurable send pacing with randomized jitter intervals.
  • Auto presence management. Available on connect, unavailable on shutdown.

CLI

With the daemon running, use whatsrust as a one-shot CLI. Every command returns JSON to stdout:

# Messaging
whatsrust send 15551234567 "Hello from the CLI"
whatsrust image 15551234567 /tmp/photo.jpg "Check this out"
whatsrust video 15551234567 /tmp/clip.mp4
whatsrust react 15551234567 MSG_ID "thumbsup"
whatsrust poll 15551234567 1 "Lunch?" -- "Pizza" "Sushi" "Tacos"

# Status/stories
whatsrust status-text 15551234567 "Hello world"
whatsrust status-image 15551234567 /tmp/photo.jpg

# Chat management
whatsrust pin-chat 15551234567
whatsrust mute-chat 15551234567
whatsrust archive-chat 15551234567
whatsrust mark-read 15551234567
whatsrust delete-chat 15551234567

# Groups
whatsrust groups
whatsrust group-info 120363012345678901@g.us
whatsrust group-create "My Group" 15551234567 15559876543

Output:

{"ok": true, "id": "3EB0A1B2C3D4E5F6"}

API

54 REST endpoints on localhost:7270. JSON in, JSON out. No framework -- raw TCP for minimal overhead.

Messaging

EndpointBody
POST /api/send{jid, text, mentions?, schedule_at?}
POST /api/reply{jid, id, sender, text}
POST /api/edit{jid, id, text}
POST /api/react{jid, id, emoji}
POST /api/revoke{jid, id}
POST /api/image{jid, data, mime?, caption?}
POST /api/video{jid, data, mime?, caption?}
POST /api/audio{jid, data}
POST /api/poll{jid, question, options, selectable_count}
POST /api/forward{jid, msg_id}

Status/stories

EndpointBody
POST /api/status-text{recipients, text, background_argb?, font?}
POST /api/status-image{recipients, data, caption?}
POST /api/status-video{recipients, data, caption?}
POST /api/status-revoke{recipients, message_id}

Chat management

EndpointBody
POST /api/pin-chat{jid}
POST /api/mute-chat{jid}
POST /api/archive-chat{jid}
POST /api/mark-read{jid}
POST /api/delete-chat{jid}
POST /api/delete-for-me{jid, id}
POST /api/star{jid, id}

Plus: SSE streaming (GET /api/events), groups, presence, health check, QR.

Async sends return {ok, job_id}. Add ?sync=true to wait for the WhatsApp message ID.


MCP server for AI agents

Run whatsrust mcp to start a Model Context Protocol server with 30 tools over JSON-RPC stdio. Connect it to Claude Code, Cursor, or any MCP-compatible AI agent and your agent can send messages, manage groups, post stories, and handle chat operations through WhatsApp.

Works out of the box with Claude Code -- just add it to your MCP config and your AI agent gets full WhatsApp access.


Use as a library

Designed to be embedded. About 10 lines to wire up:

use whatsrust::bridge::{BridgeConfig, WhatsAppBridge, WhatsAppInbound};
use tokio::sync::mpsc;
use tokio_util::sync::CancellationToken;

let (inbound_tx, mut inbound_rx) = mpsc::channel::<WhatsAppInbound>(256);
let cancel = CancellationToken::new();

let bridge = WhatsAppBridge::start(
    BridgeConfig {
        db_path: "whatsapp.db".into(),
        health_port: 8080,
        ..Default::default()
    },
    inbound_tx,
    cancel.clone(),
);

// Send
bridge.send_message_with_id("1234567890", "Hello from Rust").await?;

// Receive
while let Some(msg) = inbound_rx.recv().await {
    println!("{}: {}", msg.sender, msg.content.display_text());
}

Inbound messages arrive as WhatsAppInbound with sender, JID, message ID, reply context, MessageFlags (forwarded, view-once), and typed content. Media arrives as raw bytes -- no second download step.


Config

VariableDefaultWhat it does
WHATSAPP_PAIR_PHONE(QR mode)Phone number for pair-code linking
WHATSAPP_ALLOWED(everyone)Comma-separated sender allowlist
WHATSRUST_PORT7270API server port (0 = disabled)
WHATSRUST_BIND127.0.0.1API bind address
WHATSRUST_API_TOKEN(none)Bearer token for API auth
BACKUP_DIRwhatsapp.db.backupsSQLite backup directory
RUST_LOGinfoLog level (debug for protocol)

Contributing

PRs welcome. Run cargo test and cargo clippy before submitting. See CONTRIBUTING.md.

License

MIT


Built by Boris Djordjevic at 199 Biotechnologies | Paperfoot AI

If this is useful to you:

Star this repo    Follow @longevityboris

↑↓ navigate openesc close