Channel Mode
DMs, inbound calls, and call state changes arrive in your agent's context the moment they happen — no polling loop to write.
What is it?
Channel mode is Chamade's real-time push layer. Every time something happens on a platform you care about — a new DM on Telegram, a caller ringing your SIP number, a batched WhatsApp flush — the MCP server pushes the event on your open session as a notifications/claude/channel message. Channel-aware clients (currently Claude Code) display it directly in the agent's context so it can react immediately.
- Chat messages — DMs from Discord, Telegram, Teams, WhatsApp, Slack, NC Talk
- Incoming calls — ringing SIP calls, new conversations
- Call state changes — joined, active, disconnected, ended
- WhatsApp flush —
dm_deliveredwhen queued messages are sent after the 24 h window reopens - Transcript lines — only when hosted STT is enabled (beta-gated in early access). In the default BYO audio mode, transcripts come from your own STT client reading the call's audio WebSocket and never go through the MCP channel.
Setup
Two pieces, one server-side (automatic) and one client-side (per-launch flag).
Server side — nothing to configure
Chamade's hosted MCP server at mcp.chamade.io/mcp/ always declares the experimental.claude/channel capability during the initialize handshake — push mode is always on, no server-side flag to set.
The only thing you need on the config side is a valid MCP entry (see MCP Server setup) pointing at Chamade. Pick HTTP direct if your client supports Streamable HTTP; otherwise use the @chamade/mcp-server@3 stdio shim — both paths carry the same channel events.
Client side — launch Claude Code with the channel flag
Claude Code only processes notifications/claude/channel messages from MCP servers you've explicitly opted in. That opt-in is a per-launch command-line flag:
The --dangerously-load-development-channels server:chamade flag is required every time you start Claude Code. It's a command-line argument, not a settings.json entry. Without it, your tools still work in polling mode but push events are silently dropped client-side — the agent will not see new DMs or ringing calls in real time.
The server name after server: must match the key in your .mcp.json. If you have multiple Chamade entries (chamade, chamade-http, etc.), pass the flag once per entry: --dangerously-load-development-channels server:chamade server:chamade-http.
The "dangerously" prefix is Claude Code's naming for flags that load MCP channels not on the official Anthropic allowlist — it is not dangerous in the security sense, it's just how you opt into experimental channels during the research preview. When Chamade is added to the allowlist, the flag will become optional.
The client-side flag is unrelated to transport. Whether you use HTTP direct, the @chamade/mcp-server@3 stdio shim, or mcp-remote directly, you still need --dangerously-load-development-channels server:chamade on the Claude Code launch.
How it works
- Client opens an MCP session and sends
initialize. - Chamade responds with server capabilities, including
experimental.claude/channel: {}. - On the first discovery request (
list_tools,list_resources, …), the server eagerly subscribes to that user's inbox hub in the background — no tool call needed. - When any event is published to the hub (DM webhook, Maquisard bridge, SIP trunk, etc.), it is forwarded to the live MCP session as a
notifications/claude/channelJSON-RPC notification. - Channel-aware clients surface the event content to the agent, which reacts using the normal MCP tools (
chamade_call_say,chamade_dm_chat, etc.). - When the client disconnects, the background subscription cleans up automatically.
Do not call chamade_call_status or chamade_inbox in a loop when using channel mode with a channel-aware client. Events arrive on their own. You can still call those tools manually to catch up after a reconnect, or in polling mode with non-channel-aware clients.
Voice call workflow
The example below pushes call_transcript events through the MCP channel and uses chamade_call_say. Both depend on hosted STT/TTS, which is beta-gated in early access — contact [email protected] for supervised access. In the default BYO audio mode, transcripts come from your own STT client over the call's audio WebSocket and the agent speaks via your own TTS — neither path touches the MCP channel. DM, call-state, and inbound-call push still work exactly as shown in the other examples.
A typical voice meeting with hosted STT/TTS enabled:
chamade_call_join → call_id: "abc123", state: "connecting"
chamade_call_say → "Got it, I'm noting that the auth migration is complete."
Messaging workflow
Incoming DMs are also pushed automatically:
chamade_dm_typing → OK
chamade_dm_chat → "All 42 tests passing. The auth migration looks good."
Inbound calls
When a phone call or new voice request comes in, the event arrives immediately:
chamade_call_accept → state: "active"
Channel mode vs polling
Clients without channel support aren't stuck — they simply ignore the push notifications and fall back to polling. Every tool that has a push-event equivalent also has a polling mode; see the polling fallback notes in the MCP tools reference (chamade_call_status, chamade_inbox with wait=55, chamade_call_list). Nothing breaks, you just trade real-time latency for a tighter control loop.
| Polling (default MCP) | Channel mode | |
|---|---|---|
| Transcript delivery (hosted STT only) | Agent polls chamade_call_status when hosted STT is enabled; otherwise the agent's own STT client is the source | Pushed automatically when hosted STT is enabled (beta-gated); in BYO audio mode transcripts live in your STT client, not the channel |
| Latency | Depends on poll interval | Real-time (<1 s) |
| DM messages | Agent polls chamade_inbox (optionally long-poll up to 55 s) | Pushed automatically |
| Incoming calls | Agent polls chamade_call_list | Pushed automatically |
| Clients | Any MCP client | Claude Code (and any client that opts into experimental.claude/channel) |
| Config | Same | Same — automatic if client supports it |
