Connect an XMPP account to your Claude Code session. Message Claude from any XMPP client on your phone (Monal, Conversations, ChatSecure, Gajim, etc.) over the federated XMPP network.
The MCP server logs into XMPP as a bot and provides tools to Claude to reply or edit messages. When you message the bot, the server forwards the message to your Claude Code session.
- No phone number required (unlike Telegram)
- Federated — pick any server, switch anytime
- OMEMO end-to-end encryption (client-side)
- Works on older devices (iPhone 6s, etc.)
- Unlimited simultaneous clients
- Bun — install with
curl -fsSL https://bun.sh/install | bash - An XMPP account for the bot (register on any public server: yax.im, xmpp.jp, etc.)
git clone https://github.com/nickolanack/xmpp-channel.git
cd xmpp-channel
bun installAdd to your project's .mcp.json (or ~/.claude/.mcp.json for global):
{
"mcpServers": {
"xmpp": {
"command": "bun",
"args": ["run", "/path/to/xmpp-channel/server.ts"]
}
}
}Create ~/.claude/channels/xmpp/.env:
XMPP_JID=yourbot@server.com
XMPP_PASSWORD=your-password
If your server requires direct TLS (e.g. yax.im under Bun):
XMPP_JID=yourbot@yax.im
XMPP_PASSWORD=your-password
XMPP_SERVICE=xmpps://xmpp.yaxim.org:443
The .env file is automatically chmod 600 on first read.
Create ~/.claude/channels/xmpp/access.json:
{
"policy": "allowlist",
"allowFrom": ["you@your-xmpp-server.com"]
}Only JIDs in allowFrom can message the bot. All others are silently dropped.
claude --dangerously-load-development-channels server:xmppMessage the bot's JID from your XMPP client — the message reaches Claude.
| Tool | Purpose |
|---|---|
reply |
Send a message to an XMPP JID. Auto-chunks at 4000 chars. |
edit_message |
Correct a previously sent message (XEP-0308). |
When Claude needs to run a tool that requires approval, you get a message like:
Permission: Bash
Run shell command: npm install
Reply: y abcde / n abcde
Reply: more abcde for full details
Reply with y abcde to allow or n abcde to deny (the 5-character code is required).
Managed via ~/.claude/channels/xmpp/access.json. The server re-reads this file on every inbound message — changes take effect without restart.
{
"policy": "allowlist",
"allowFrom": ["alice@server.com", "bob@server.com"],
"ackMessage": "",
"textChunkLimit": 4000,
"chunkMode": "newline"
}| Field | Description |
|---|---|
policy |
allowlist (default) or disabled |
allowFrom |
Array of bare JIDs allowed to message the bot |
ackMessage |
Optional text sent on receipt (e.g. "received"). Empty = disabled. |
textChunkLimit |
Max chars per outbound message before splitting (default: 4000) |
chunkMode |
newline (paragraph-aware) or length (hard cut) |
If installed as a plugin, two skills are available:
| Skill | Purpose |
|---|---|
/xmpp:configure |
Guided first-time setup (writes .env + access.json) |
/xmpp:access |
Manage allowlist (allow/remove JIDs, set policy, configure delivery) |
@xmpp/client under Bun may hang during STARTTLS negotiation on some servers. If your bot gets stuck at "opening" status, switch to direct TLS:
- Find your server's SRV records:
dig +short SRV _xmpps-client._tcp.yourserver.com - Set
XMPP_SERVICE=xmpps://host:portin.env
Example for yax.im:
XMPP_SERVICE=xmpps://xmpp.yaxim.org:443
Each session binds with a unique XMPP resource (claudecode-<pid>). Multiple sessions can connect with the same JID, but message routing depends on server configuration.
- Allowlist enforced on both inbound (gate) and outbound (reply/edit can only target allowlisted JIDs)
- Input sanitization strips
<>[]from inbound messages to prevent channel tag injection - State protection prevents Claude from exfiltrating
.envoraccess.jsonvia file operations - Prompt injection defense in Claude's system instructions — refuses to modify access when asked via channel messages
- Credential isolation —
.envischmod 600, never committed to git
MIT