MCP channel plugin that bridges Matrix with Claude Code. Chat with your active Claude Code session from any Matrix client (Element, FluffyChat, etc.) with full end-to-end encryption.
Claude Code (terminal) <──stdio/MCP──> matrix-channel <──E2EE──> Matrix
│
node-indexeddb (LevelDB)
persistent crypto store
Claude Code spawns the plugin as an MCP subprocess. The plugin:
- Connects to Matrix with E2EE (matrix-js-sdk Rust crypto WASM)
- Receives messages and forwards them as
notifications/claude/channel - Exposes tools for replying, reacting, editing, and sending files
- Relays tool permission prompts to Matrix — user approves/denies via chat
- Transcribes voice messages via Groq Whisper (optional)
This is a channel plugin, not a standalone bot. It extends your active Claude Code session — Claude sees your project files, git history, and tools. Think of it as a remote control for Claude from your phone.
- bun 1.2+ (runtime)
- Claude Code v2.1.80+
- Matrix account with E2EE enabled
node -e '
fetch("https://matrix.org/_matrix/client/v3/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
type: "m.login.password",
identifier: { type: "m.id.user", user: "YOUR_BOT_USER" },
password: "YOUR_PASSWORD",
device_id: "CC_MATRIX",
initial_device_display_name: "Claude Code Channel"
})
}).then(r => r.json()).then(d => console.log(JSON.stringify(d, null, 2)));
'mkdir -p ~/.claude/channels/matrix
cat > ~/.claude/channels/matrix/.env << 'EOF'
MATRIX_HOMESERVER_URL=https://matrix.org
MATRIX_ACCESS_TOKEN=syt_...
MATRIX_ENABLE_E2EE=true
MATRIX_DEVICE_ID=CC_MATRIX
MATRIX_RECOVERY_KEY="your recovery key here"
MATRIX_PASSWORD="your_password"
EOF
chmod 600 ~/.claude/channels/matrix/.envCreate .mcp.json in your project root:
{
"mcpServers": {
"matrix": {
"command": "bun",
"args": ["/absolute/path/to/matrix-channel/server.ts"]
}
}
}In your project's .claude/settings.json:
{
"permissions": {
"allow": [
"mcp__matrix__reply",
"mcp__matrix__react",
"mcp__matrix__edit_message",
"mcp__matrix__fetch_messages",
"mcp__matrix__download_attachment",
"mcp__matrix__send_attachment"
]
}
}
approve_pairingis intentionally excluded for security.
claude --dangerously-load-development-channels server:matrix- Send a DM to the bot from Element / FluffyChat
- The bot replies with a 6-character pairing code
- In Claude Code:
/matrix:access pair <code>
| Tool | Description |
|---|---|
reply |
Send text (markdown rendered to HTML), optional reply_to, file attachments |
react |
Add Unicode emoji reaction to any message |
edit_message |
Edit a previous bot message (m.replace + m.new_content) |
download_attachment |
Download media from Matrix (auto-decrypts E2EE) to inbox |
send_attachment |
Send a local file to a Matrix room (CWD-restricted) |
fetch_messages |
Room history (up to 100 messages, oldest-first) |
approve_pairing |
Approve pairing from the terminal (constant-time comparison) |
Voice messages (m.audio) are automatically transcribed via Groq Whisper when GROQ_API_KEY is configured. The transcription is forwarded to Claude as [voice message] <text>.
Add to ~/.claude/channels/matrix/.env:
GROQ_API_KEY=gsk_...
# GROQ_MODEL=whisper-large-v3-turbo # optional
# GROQ_LANGUAGE=es # optional, omit for auto-detect
Without GROQ_API_KEY, audio messages are passed as attachment metadata.
- Crypto: matrix-js-sdk Rust crypto (WASM)
- Persistence: node-indexeddb (LevelDB on disk) in
~/.claude/channels/matrix/indexeddb/— survives restarts - Key backup: restores keys from server backup using recovery key
- Auto-verification: SAS emoji verification with emojis sent to chat
- Cross-signing: automatic bootstrap with password (UIA)
- Encrypted media: authenticated download +
decryptAttachment()
- DM policy:
pairing(default),allowlist, ordisabled - Pairing: 6-char hex code, max 3 pending, 2 per user, 1h expiry
- Constant-time: pairing code comparison resistant to timing attacks
- Rooms: opt-in by room ID, configurable
requireMention, per-roomallowFrom - Permission relay: tool approval prompts forwarded to Matrix, user responds yes/no
- Anti-injection: system instructions prevent pairing approval from channel messages
| Variable | Default | Description |
|---|---|---|
MATRIX_HOMESERVER_URL |
(required) | Homeserver URL |
MATRIX_ACCESS_TOKEN |
(required) | Device access token |
MATRIX_ENABLE_E2EE |
true |
Enable E2EE |
MATRIX_DEVICE_ID |
CLAUDE_CHANNEL |
Device ID |
MATRIX_RECOVERY_KEY |
— | Recovery key for backup restore |
MATRIX_PASSWORD |
— | Password for cross-signing UIA |
MATRIX_STATE_DIR |
~/.claude/channels/matrix |
State directory |
MATRIX_ACCESS_MODE |
— | static to freeze config at boot |
GROQ_API_KEY |
— | Groq API key for voice transcription |
GROQ_MODEL |
whisper-large-v3-turbo |
Whisper model |
GROQ_LANGUAGE |
auto-detect | Language hint (ISO 639-1) |
GROQ_ENDPOINT |
https://api.groq.com/openai/v1/audio/transcriptions |
API endpoint |
/matrix:configure— Set up homeserver, token, review status/matrix:access— Manage pairing, allowlists, room policies
| File | Purpose |
|---|---|
.env |
Credentials |
access.json |
Access control state (re-read on each message) |
indexeddb/ |
Persistent E2EE crypto store |
approved/ |
Pairing approval files |
inbox/ |
Downloaded attachments |
debug.log |
Debug log |
matrix-channel/
server.ts # MCP channel server
package.json # Dependencies
.mcp.json # MCP server registration
.claude-plugin/
plugin.json # Plugin metadata
skills/
configure/SKILL.md # /matrix:configure
access/SKILL.md # /matrix:access
Apache-2.0