OpenMessage is a local-first messaging workspace for Google Messages, WhatsApp, and Signal. Use it from the native macOS app, the localhost web UI, or any MCP-compatible client.
Built on mautrix/gmessages (libgm) for the Google Messages protocol and mcp-go for the MCP server.
git clone https://github.com/MaxGhenis/openmessage.git
cd openmessage
go build -o openmessage .
./openmessage pair
By default, a QR code appears in your terminal. On your phone, open Google Messages > Settings > Device pairing > Pair a device and scan it. The session saves to ~/.local/share/openmessage/session.json.
If Google only offers account pairing, you can also pair with Google account cookies copied from browser devtools:
pbpaste | ./openmessage pair --google
The CLI accepts either a JSON cookie object or a full curl command for messages.google.com/web/config, then prompts you to confirm an emoji on your phone.
./openmessage serve
This starts both:
- Web UI at http://127.0.0.1:7007
- MCP SSE endpoint at http://127.0.0.1:7007/mcp/sse
When serve is launched by an MCP client over pipes, it also serves MCP on stdio automatically.
After serve is running, open the local UI and link WhatsApp or Signal from the Connections surface. OpenMessage keeps those bridges local and syncs them into the same inbox as Google Messages.
./openmessage demo
or:
./openmessage serve --demo
Demo mode starts the same local UI on the normal port, but: - uses a fresh temporary data directory instead of your real message store - seeds fake SMS and WhatsApp conversations for screenshots and demos - disables live Google Messages, WhatsApp, and local desktop import sync
This is the safest way to capture website screenshots, App Store assets, or demo recordings without real messages bleeding back in.
Add to ~/.mcp.json:
{
"mcpServers": {
"openmessage": {
"command": "/path/to/openmessage",
"args": ["serve"]
}
}
}
Restart Claude Code. The MCP tools appear automatically.
| Tool | Description |
|---|---|
get_messages |
Recent messages with filters (phone, date range, limit) |
get_conversation |
Messages in a specific conversation |
search_messages |
Full-text search across all messages |
send_message |
Send a direct text by platform. Defaults to SMS/RCS and also supports direct WhatsApp/Signal recipients |
send_to_conversation |
Send a text reply directly to an existing conversation ID |
send_media_to_conversation |
Send a local file attachment to an existing conversation ID |
react_to_message |
Add, remove, or switch a reaction on an existing message |
list_conversations |
List recent conversations |
list_contacts |
List/search contacts |
get_status |
Google Messages, WhatsApp, and Signal connection status |
download_media |
Download an attachment from a message to a local temp file |
draft_message |
Save a draft for the local app to review/send later |
import_messages |
Import Google Chat, iMessage, WhatsApp export, or Signal Desktop history |
list_conversations(source_platform="signal")search_messages(query="airbnb")send_message(platform="signal", recipient="+15551230000", message="On my way")send_to_conversation(conversation_id="whatsapp:15551234567@s.whatsapp.net", message="On my way")send_media_to_conversation(conversation_id="signal-group:abc123", file_path="/tmp/photo.jpg", caption="Here")react_to_message(conversation_id="signal-group:abc123", message_id="signal:...", emoji="🔥")import_messages(source="signal", path="$HOME/Library/Application Support/Signal", name="Your Name", address="+15551230000")The web UI runs at http://localhost:7007 when the server is started. It provides:
The repo also includes a native Swift wrapper around the same local backend:
The macOS app target lives under OpenMessage/.
| Env var | Default | Purpose |
|---|---|---|
OPENMESSAGES_DATA_DIR |
~/.local/share/openmessage |
Data directory (DB + session) |
OPENMESSAGES_LOG_LEVEL |
info |
Log level (debug/info/warn/error/trace) |
OPENMESSAGES_PORT |
7007 |
Web UI port |
OPENMESSAGES_HOST |
127.0.0.1 |
Host/interface to bind the local web server to |
OPENMESSAGES_MY_NAME |
system user name | Display name for outgoing imported iMessage/WhatsApp messages |
OPENMESSAGES_STARTUP_BACKFILL |
auto |
Startup history sync mode: auto, shallow, deep, or off |
OPENMESSAGES_MACOS_NOTIFICATIONS |
interactive macOS serve sessions only |
Enable/disable native macOS notifications for fresh inbound live messages (1/0). Click-through opens the matching thread when terminal-notifier is available. |
OPENMESSAGE_TELEMETRY |
unset (off) | Set to 1 to send one anonymous heartbeat per launch (max one per 24h). Reports only: random install ID, version, OS/arch, and which platforms are paired (Google Messages / WhatsApp / Signal). No message content, no contact info, no IP-based identity. See internal/telemetry/. |
session.jsongo test ./... # Run all tests
go build . # Build binary
npm install # Install Playwright test runner
npx playwright install chromium
npm run test:e2e # Run browser-level web UI tests
./openmessage pair # Pair with phone
./openmessage serve # Start server
./openmessage demo # Start isolated fake-data demo mode
Before publishing a build or website update, run through the release checklist.
MIT
$ claude mcp add openmessage \
-- python -m otcore.mcp_server <graph>