A channel is an MCP server that pushes events into a Claude Code session that is already running. That one word is the whole distinction. A normal MCP server waits to be queried during a task. A channel arrives uninvited, so Claude can react to something that happened while you were not at the terminal.
Channels are in research preview. The --channels flag does not appear in claude --help while the preview lasts, but it works anyway. Telegram, Discord and iMessage ship as official plugins.
How this differs from Remote Control
People conflate the two because both let you reach Claude Code from your phone. The direction is opposite:
| Remote Control | Channels | |
|---|---|---|
| Direction | You drive the session | Events arrive in the session |
| Interface | claude.ai/code or the Claude app | Telegram, Discord, iMessage, or your own webhook |
| Typical use | Steering work already in progress | Reacting to CI failures, alerts, or a question texted from a chat app |
| Session needed | Yes, yours, running locally | Yes, yours, running locally |
They are complementary rather than competing. Remote Control gives you a viewport onto the session; a channel gives the outside world a way in. Both need the session open, so see running on an always-on machine if you want either to work while you sleep.
What you need first
- Bun. Every official channel plugin is a Bun script. Check with
bun --version. - Anthropic authentication through claude.ai or a Console API key. Channels are not available on Amazon Bedrock, Google Cloud Agent Platform, or Microsoft Foundry.
- On Team or Enterprise, an admin toggle. Channels are blocked until an Owner enables them. Console organizations with API keys have them on by default unless managed settings are deployed.
Pro and Max users without an organization skip the admin check entirely and just opt in per session.
Try it without touching a real platform
There is an official demo channel called fakechat that runs a chat UI on localhost, with nothing to authenticate. Worth ten minutes before you start creating bot tokens.
/plugin install fakechat@claude-plugins-official
Then exit Claude Code and restart with the channel enabled:
claude --channels plugin:fakechat@claude-plugins-official
Open http://localhost:8787 and type something. It appears in your terminal as an inbound line like ← fakechat · web: what is in my working directory?, and the model receives it as a <channel source="plugin:fakechat:fakechat"> event. Claude does the work and calls the channel’s reply tool. The first reply triggers a permission prompt; approve it and the answer lands back in the browser.
If the install fails with Marketplace "claude-plugins-official" not found, run /plugin marketplace add anthropics/claude-plugins-official. If the plugin is not found in a marketplace you already have, your local copy is stale: /plugin marketplace update claude-plugins-official. Choose the user scope at install so the plugin works across all your projects.
Telegram
- Open BotFather in Telegram, send
/newbot, give it a display name and a username ending inbot, and copy the token it returns. - Install the plugin with
/plugin install telegram@claude-plugins-official, then run/reload-pluginsto activate its configure command. - Save the token with
/telegram:configure <token>. It writes to~/.claude/channels/telegram/.env. SettingTELEGRAM_BOT_TOKENin your shell before launching works too. - Restart with
claude --channels plugin:telegram@claude-plugins-official. This starts polling for messages from your bot. - Message your bot. It replies with a pairing code. Back in Claude Code run
/telegram:access pair <code>, then lock it down with/telegram:access policy allowlist.
If the bot does not answer, check that Claude Code is actually running with --channels. The bot can only reply while the channel is active.
Discord
- In the Discord Developer Portal, create a New Application, add a bot username, then Reset Token and copy it.
- Under Privileged Gateway Intents, enable Message Content Intent. Without this the bot cannot read messages.
- In OAuth2 > URL Generator select the
botscope and grant View Channels, Send Messages, Send Messages in Threads, Read Message History, Attach Files, and Add Reactions. Open the generated URL to add it to your server. /plugin install discord@claude-plugins-official, then/reload-plugins./discord:configure <token>, or setDISCORD_BOT_TOKENin your shell.- Restart with
claude --channels plugin:discord@claude-plugins-official, DM the bot, then/discord:access pair <code>and/discord:access policy allowlist.
iMessage
The iMessage channel is the odd one out: no bot, no token, no external service. It reads your Messages database directly and sends replies through AppleScript, so it is macOS only.
- Grant Full Disk Access.
~/Library/Messages/chat.dbis protected, so macOS prompts the first time. The prompt names whichever app launched Bun, such as Terminal or your IDE. If you miss it, add your terminal under System Settings > Privacy & Security > Full Disk Access. Without it the server exits immediately withauthorization denied. /plugin install imessage@claude-plugins-official.- Restart with
claude --channels plugin:imessage@claude-plugins-official. - Text yourself from any device on your Apple ID. Self-chat bypasses access control with no setup. The first reply triggers a macOS Automation prompt asking whether your terminal can control Messages.
- To let someone else through:
/imessage:access allow +15551234567. Handles are phone numbers in+countryform or Apple ID emails.
Security worth understanding before you open this up
- Every channel keeps a sender allowlist. Only IDs you have added can push messages. Everyone else is silently dropped.
- Being in
.mcp.jsonis not enough. A server also has to be named in--channelsfor that session. Nothing runs implicitly. - Permission relay is a real authority handover. If a channel declares the capability, anyone who can reply through it can approve or deny tool use in your session. Only allowlist people you trust with that.
On Team and Enterprise, admins hold two managed settings users cannot override: channelsEnabled is the master switch, and allowedChannelPlugins replaces Anthropic’s default plugin allowlist with your own. Setting an empty array blocks the allowlist but --dangerously-load-development-channels can still bypass it, so leave channelsEnabled unset if you want channels off entirely.
Gotchas
- A permission prompt while you are away stalls everything. The session pauses until you answer. Channels that support permission relay can forward the prompt to you.
- You do not see Claude’s reply text in the terminal. You see the inbound message and a confirmation such as “sent”. The reply itself only appears on the other platform.
- Non-interactive mode changes behaviour. With
-p, tools needing terminal input such as multiple-choice questions and plan mode approval are disabled so the session cannot stall. - Events only arrive while the session is open. There is no queue for a closed session.
Where channels sit among the alternatives
| Feature | What it does | Best for |
|---|---|---|
| Channels | Pushes events from outside into your running local session | Reacting to CI, alerts, or a chat message while away |
| Remote Control | You drive your local session from claude.ai or the Claude app | Steering work already in progress |
| Claude Code on the web | Runs tasks in a fresh cloud sandbox cloned from GitHub | Self-contained async work you check later |
| Claude in Slack | Spawns a web session from an @Claude mention | Starting tasks from team conversation |
| Standard MCP server | Claude queries it during a task; nothing is pushed | On-demand access to read or query a system |
Fuller comparison on Remote Control vs Claude Code on the web.