Skip to main content
Channels are push-based notification streams that deliver real-time events into Claude Code sessions. They enable your MCP server to forward webhooks, application errors, agent completions, job results, and chat messages directly into Claude’s context — with optional two-way reply support.
This feature implements the Claude Code Channels extension — an experimental MCP protocol extension using notifications/claude/channel.

Why Channels?

Channels fill a gap that tools, resources, and prompts cannot address — server-initiated push notifications: Channels are ideal for:
  • CI/CD alerts — deploy status, build failures, PR notifications
  • Chat bridges — WhatsApp, Telegram, Slack, Discord messaging with Claude
  • Error monitoring — forward application errors for debugging assistance
  • Agent notifications — notify when AI agents complete background tasks
  • Job completion — alert when background jobs or workflows finish

Creating Channels

Class Style

Use class decorators for channels that need complex message transformation or two-way communication:

Function Style

Use the channel() builder for simple transform-only channels:

Channel Sources

Every channel has a source that determines how events flow into it:

Webhook Source

External services send HTTP POST requests to the configured path:

App Event Source

Your application emits events to the ChannelEventBus:

Agent & Job Completion

Auto-subscribe to system events with optional filtering:

Service Connector

Service connectors maintain persistent connections to external messaging services. Claude sends messages via channel-contributed tools, and incoming responses arrive as channel notifications. This is the most powerful channel pattern — it turns Claude Code into a full messaging client.
The conversation flow:
  1. Claude calls send-whatsapp({ to: "+1234567890", text: "Hi Alice!" })
  2. Message is delivered to Alice’s WhatsApp
  3. Alice replies “Got it, will review the PR”
  4. onConnect()’s listener fires → pushIncoming()onEvent() transforms it
  5. Claude sees: <channel source="whatsapp" sender="Alice">Alice: Got it, will review the PR</channel>
  6. Claude can continue the conversation by calling send-whatsapp again
Service connector channels call onConnect() during scope initialization and onDisconnect() during teardown. The connection persists for the lifetime of the server.

File Watcher

Watch file system paths and notify Claude when files change. Uses onConnect() to start watching.

Manual Push

Push notifications programmatically from any code with scope access:

Replay Buffer

By default, events are lost when no Claude Code sessions are connected. Enable replay to buffer events:
How it works:
  1. Events arrive and are processed normally via onEvent()
  2. Each notification is also stored in an in-memory ring buffer
  3. When a new session connects, replayBufferedEvents(sessionId) sends all buffered events
  4. Replayed events include replayed: "true" in their meta
For events that must survive server restarts, combine replay with a persistent store (Redis, SQLite) in onConnect(). See the replay buffer skill example for the pattern.

Two-Way Communication

Set twoWay: true to enable Claude Code to reply back through the channel. This auto-registers a channel-reply tool.
Claude Code sees the channel notification as:
And can reply using the auto-registered channel-reply tool:

Registration

In an App

Enable at Server Level

Channels must be explicitly enabled with channels: { enabled: true } in the @FrontMcp config. Without this, channel declarations are ignored.

Wire Protocol

Channel notifications use the experimental notifications/claude/channel JSON-RPC method:
The server advertises experimental: { 'claude/channel': {} } in its capabilities. Only sessions whose client capabilities include this extension receive channel notifications.

Session Isolation

Channel notifications are session-scoped to prevent data leaking between connected agents.

How It Works

  1. When a session initializes with claude/channel capability, it is auto-subscribed to all channels
  2. Notifications are only delivered to sessions subscribed to the specific channel
  3. Session-targeted events (job completions, agent results) go ONLY to the originating session
  4. Global events (webhooks, file changes) go to all subscribed sessions
  5. Channel subscriptions are cleaned up automatically on disconnect

Delivery Matrix

Selective Subscriptions

Sessions can subscribe to specific channels instead of all:
Session-targeted events from job/agent completions carry the originating sessionId in the event payload. If your custom source produces session-scoped data, pass targetSessionId to channel.pushNotification() to enforce isolation.

Security

Sender Gating

For chat bridges, always validate individual sender identity:

Meta Key Restrictions

Meta keys must be valid identifiers (letters, digits, underscores). Invalid keys are rejected at startup:

@Channel Decorator

Full decorator API reference

ChannelContext

Context class API reference

ChannelRegistry

Registry API reference

Claude Code Channels

Official Claude Code channels specification