E2EE Matrix bridge — CLI and MCP server for any AI coding agent.
Send and read end-to-end encrypted messages in Matrix rooms from your terminal or any MCP-compatible tool (Claude Code, Cursor, Windsurf, Cline, etc.). Zero system dependencies — just download and run.
AI coding agents (Claude Code, Cursor, Windsurf, etc.) are powerful but isolated — they can't talk to other bots or people outside their own session. Matrix is an open, federated, end-to-end encrypted chat protocol that solves this.
With matrix-bridge, your coding agent can:
- Collaborate with other AI agents — have a coding agent build something, send it to a product agent for review, get feedback, and iterate — all automatically through encrypted chat
- Join team rooms — humans and bots in the same encrypted group chat, discussing work in real time
- Bridge across providers — an agent running on Anthropic can chat with one on OpenAI, or with a human on Element, all through the same Matrix room
- Send and wait for replies — ask a question to another bot or person and get the answer back in the same session
Real-world example: We use this to connect Claude Code with Žofka, a bot running on Hermes Agent. Claude Code builds a plugin, Žofka tests it and reports issues, Claude reads her feedback and ships fixes — two agents working together in a contractor/supplier loop, with the human operator overseeing the conversation. The whole flow happens in an encrypted Matrix room via this bridge.
- End-to-end encryption — automatic encrypt/decrypt using vodozemac (pure Rust Olm)
- CLI —
matrix-bridge send,read,rooms,send-wait,setup,config - MCP server — 5 tools exposed over stdio for any MCP client
- Agent-agnostic — no hardcoded bot names or provider assumptions
- Static binaries — no Python, no venv, no libolm
- Cross-platform — Linux (x86/ARM), macOS (Intel/Apple Silicon). Windows support planned.
- TOFU trust — Trust On First Use device verification, suitable for bot-to-bot communication
Currently from source only (GitHub Releases and crates.io coming after broader testing):
git clone https://github.com/elkimek/matrix-bridge.git
cd matrix-bridge
cargo build --release
# Binaries at target/release/matrix-bridge and target/release/matrix-bridge-mcpYou need a Matrix account for the bridge. Create one at element.io or any Matrix homeserver, then note your user ID (e.g., @mybot:matrix.org) and password.
matrix-bridge setup
# Enter your Matrix user ID and password when prompted
# This creates encryption keys and saves your session# Use the config command to avoid shell escaping issues with !
matrix-bridge config default_room "!yourRoomId:matrix.org"Tip: Run
matrix-bridge roomsto see your joined rooms and copy the room ID from there.
# Send a message
matrix-bridge send "Hello from the bridge!"
# Read recent messages
matrix-bridge read --limit 10
# Send and wait for a reply (30s timeout)
matrix-bridge send-wait "ping" --timeout 30matrix-bridge setup Interactive login + key setup
matrix-bridge send <msg> Send a message
--room <id> Room ID (overrides default)
--mention <@user:server> @mention a user
--no-mention Suppress default mention
matrix-bridge read Read recent messages
--room <id> Room ID (overrides default)
--limit <n> Number of messages (1-100, default 10)
matrix-bridge rooms List joined rooms
matrix-bridge send-wait <msg> Send and wait for reply
--room <id> Room ID (overrides default)
--mention <@user:server> @mention a user
--no-mention Suppress default mention
--timeout <secs> Timeout (1-300, default 30)
matrix-bridge config View all config
matrix-bridge config <key> View one config key
matrix-bridge config <key> <value> Set a config key
matrix-bridge mcp-server Start MCP server on stdio
All commands support --json for machine-readable output.
The MCP server exposes 5 tools over stdin/stdout:
| Tool | Description |
|---|---|
send_message |
Send a message to a room (auto-encrypted) |
send_and_wait |
Send and wait for a reply with timeout |
read_messages |
Read recent messages (auto-decrypted) |
list_rooms |
List joined rooms |
join_room |
Join a room by ID or alias |
Add to ~/.claude/settings.json:
{
"mcpServers": {
"matrix": {
"command": "/path/to/matrix-bridge-mcp"
}
}
}Add to .cursor/mcp.json:
{
"mcpServers": {
"matrix": {
"command": "/path/to/matrix-bridge-mcp"
}
}
}Works with any MCP client that supports stdio transport.
The bridge connects coding agents (Claude Code, Cursor, etc.) to Matrix. On the other side of the room you typically have a gateway bot — an always-on agent that lives in Matrix and responds to messages. The two main gateways are OpenClaw and Hermes Agent, and they handle Matrix natively (no bridge needed on their side).
Hermes Agent connects to Matrix directly via its built-in gateway. No bridge needed on the Hermes side — just configure Matrix in ~/.hermes/.env:
MATRIX_HOMESERVER=https://matrix.org
MATRIX_USER_ID=@yourbot:matrix.org
MATRIX_PASSWORD=your-password
MATRIX_ACCESS_TOKEN=your-token
MATRIX_ENCRYPTION=true
MATRIX_ALLOWED_USERS=@you:matrix.orgThen start the gateway:
hermes gateway startGroup chat mention handling: Hermes doesn't have built-in mention filtering for Matrix (unlike Discord/Telegram which have require_mention). In group rooms, the bot responds to every message. Two approaches:
-
SOUL.md (soft gate) — Add instructions to
~/.hermes/SOUL.mdtelling the bot to distinguish between being addressed directly vs. mentioned in passing. The bot uses judgment — it may still respond to incidental mentions when it has something useful to add. This is often the better behavior for small team rooms. -
require_mention(hard gate) — Not yet available for Matrix in Hermes. Planned as an upstream PR to bring parity with Discord/Telegram.
OpenClaw also connects to Matrix natively via its gateway. Configure Matrix in ~/.openclaw/openclaw.json and restart the gateway.
Group chat mention handling: OpenClaw supports mention-gate, a companion plugin that uses a cheap LLM (Haiku) to classify intent — "talking to the bot" vs. "talking about it" — and cancels replies to incidental mentions.
Security note: mention-gate passes messages through an LLM classification prompt — prompt injection is a feature, not a bug (it's a noise filter, not a security boundary). Keep the gate's API key separate from the bot's main provider key. See mention-gate's SECURITY.md for details.
Your machine Your server
┌──────────────────┐ ┌──────────────────┐
│ Claude Code │ │ Hermes Agent │
│ Cursor / Cline │ Matrix Room │ or OpenClaw │
│ Windsurf / ... │ ┌──────────────┐ │ │
│ │ │ E2EE group │ │ ┌────────────┐ │
│ ┌────────────┐ │◄────►│ chat with │◄────────►│ │ gateway │ │
│ │ matrix- │ │ │ humans and │ │ │ (native │ │
│ │ bridge │ │ │ bots │ │ │ Matrix) │ │
│ └────────────┘ │ └──────┬───────┘ │ └────────────┘ │
└──────────────────┘ │ └──────────────────┘
coding agent │ always-on bot
builds, tests, ships ┌─────┴──────┐ reviews, chats,
│ Element / │ runs tools
│ any Matrix│
│ client │
└────────────┘
human operator
watches, steers
The bridge runs on the coding agent side. The gateway bot connects directly. Both meet in the same encrypted room, with the human operator joining via Element or any Matrix client.
Config lives at ~/.matrix-bridge/config.json (created by matrix-bridge setup):
{
"homeserver": "https://matrix.org",
"user_id": "@mybot:matrix.org",
"device_name": "matrix-bridge",
"store_path": "/home/user/.matrix-bridge/store",
"trust_mode": "tofu",
"default_room": "!roomid:matrix.org",
"default_mention": "@friend:matrix.org",
"notify_on_mention": "mybot"
}| Field | Description |
|---|---|
homeserver |
Matrix homeserver URL |
user_id |
Matrix user ID |
device_name |
Device display name (default: "matrix-bridge") |
store_path |
Path for encryption keys and state |
trust_mode |
Device trust: tofu, all, or explicit |
default_room |
Default room for CLI commands |
default_mention |
Default @mention for send commands |
notify_on_mention |
Pattern for MCP mention notifications (defaults to local part of user_id) |
- tofu (default) — Trust On First Use. Auto-verify new devices. Best for bots.
- all — Trust all devices unconditionally.
- explicit — Manual verification only. Most secure, requires out-of-band verification.
All messages show as "[encrypted — unable to decrypt]"
This means the bridge doesn't have the Megolm session keys for those messages. This happens when:
- You're reading messages sent before the bridge device was created — these can never be decrypted
- You need to run
matrix-bridge setupto create a fresh device with proper key exchange
Messages sent after setup will decrypt normally.
"crypto store doesn't match" error during setup
Delete the old crypto store and run setup again:
rm ~/.matrix-bridge/store/matrix-sdk-*.sqlite3 ~/.matrix-bridge/store/credentials.json
matrix-bridge setupShell escaping issues with room IDs
Room IDs start with ! which bash interprets as history expansion. Use double quotes:
matrix-bridge config default_room "!roomid:matrix.org"Or edit ~/.matrix-bridge/config.json directly.
Requires Rust 1.80+ (for dependency compatibility).
cargo build --releaseFeature flags:
cli(default) — CLI binary with clapmcp(default) — MCP server with rmcp
Build CLI-only (no MCP):
cargo build --release --no-default-features --features cliGPL-3.0-or-later