Content
# Matrix Channel for Claude Code
Self-contained MCP server bridging Matrix rooms to a running Claude Code session.
Mirrors the shape of the official Telegram and Discord channel plugins
(`claude-plugins-official`), adapted for Matrix using `matrix-js-sdk`.
## Status
**Phase 1 — text bidirectional, single room, allow-list, optional voice (STT/TTS).**
## Layout
```
matrix-channel/
server.ts # Bun-based MCP server, long-lived
package.json # Bun deps: matrix-js-sdk, @modelcontextprotocol/sdk
skills/
access/SKILL.md # /matrix:access — manage allow-list, pairing
configure/SKILL.md # /matrix:configure — first-time setup
ACCESS.md # Operator-facing access-control documentation
```
## State
State directory: `~/.claude/channels/matrix/` (or `MATRIX_STATE_DIR` env var).
```
~/.claude/channels/matrix/
.env # MATRIX_ACCESS_TOKEN, MATRIX_HOMESERVER, MATRIX_USER_ID, MATRIX_DEVICE_ID (mode 0600)
access.json # dmPolicy, allowFrom, rooms, pending pairings
approved/ # /matrix:access skill drops a marker file here when pairing succeeds
inbox/ # Downloaded inbound media (cleaned periodically)
bot.pid # PID of running server, for stale-poller detection
```
## Identity
The bot is a regular Matrix account (any homeserver — Synapse, Dendrite, Conduit). Create a user
on your homeserver, generate an access token, and put it in `~/.claude/channels/matrix/.env`:
```
MATRIX_HOMESERVER=https://matrix.example.org
MATRIX_USER_ID=@your-bot:example.org
MATRIX_ACCESS_TOKEN=syt_...
MATRIX_DEVICE_ID=ABCDEFGHIJ
```
Run `/matrix:configure` from inside Claude Code for a guided setup that writes the .env, seeds
`access.json`, and registers your operator mxid on the allowlist.
## Running
The server starts automatically when Claude Code launches (declared via the plugin's `.mcp.json`),
communicates over stdio, and shuts down when stdin closes. Manual invocation for debugging:
```bash
cd "${CLAUDE_PLUGIN_ROOT}" # or wherever the plugin is installed
bun install
bun server.ts
```
## Optional voice
Set `MATRIX_STT_CMD` and/or `MATRIX_TTS_CMD` to point at a local script that takes an audio
path (STT, prints transcript on stdout) or an output `.ogg` path with text on stdin (TTS,
writes the file). Both are off if the env vars are unset; the bridge stays language-agnostic.
## Security
- `gate()` checks every inbound message against `access.allowFrom` before notifying Claude.
- `assertAllowedChat()` checks every outbound `reply` call against the same list.
- `assertSendable()` blocks the `reply` tool from exfiltrating channel state files.
- The `/matrix:access` skill is the only thing that should mutate `access.json`. Never edit by hand mid-session.
Connection Info
You Might Also Like
cc-switch
All-in-One Assistant for Claude Code, Codex & Gemini CLI across platforms.
awesome-mcp-servers
A collection of MCP servers.
git
A Model Context Protocol server for Git automation and interaction.
oh-my-opencode
Background agents · Curated agents like oracle, librarians, frontend...
TrendRadar
TrendRadar: Your hotspot assistant for real news in just 30 seconds.
Appwrite
Build like a team of hundreds