tencent cloud

Channels Reference (Beta)

Download
Focus Mode
Font Size
Last updated: 2026-09-30 18:41:48
AI-Translated
Note:
Beta Feature: Channels is currently in the Beta stage, and its protocols and APIs may be adjusted based on feedback.
A Channel is a special type of MCP server that can push external events (such as webhooks, chat messages, and monitoring alarms) into CodeBuddy Code sessions, enabling CodeBuddy Code to react to events occurring outside the terminal.

Overview

A Channel runs on the same machine as CodeBuddy Code and communicates with it over stdio. CodeBuddy Code starts the Channel as a child process.
Typical use cases:
Chat Platforms (Telegram, Discord): The plugin runs locally, polls the platform APIs to fetch new messages, and forwards them to CodeBuddy Code.
Webhook (CI, Monitoring): The server listens on a local HTTP port, receives POST requests from external systems, and pushes them to CodeBuddy Code.
Channels are available in two modes:
Mode
Description
One-way
Only forwards events to CodeBuddy Code (alarms and webhooks) and processes them in the local session.
Bidirectional
Additionally exposes the reply tool, allowing CodeBuddy Code to reply to messages.

Using Channels

Start

Use the --channels parameter to specify the channels to load:
# Load plugin-type channels
codebuddy --channels plugin:fakechat@claude-plugins-official

# Load the channel server configured in .mcp.json
codebuddy --channels server:webhook

# Load multiple channels (comma-separated)
codebuddy --channels plugin:telegram@claude-plugins-official,plugin:discord@claude-plugins-official

Development Mode

Custom channels are tested during the initial phase using the --dangerously-load-development-channels flag. This flag allows any channel to run without being on the allowlist:
codebuddy --dangerously-load-development-channels server:my-webhook
This flag only bypasses the allowlist check. The channelsEnabled org policy remains in effect. Once a channel is submitted to the official marketplace and passes security review, it is added to the allowlist and can then be loaded directly using --channels.

Channel Messages in Conversations

Channel messages are injected into the CodeBuddy Code context in the form of <channel> tags:
<channel source="fakechat" sender="web" chat_id="1">Hello, please help me look into this issue.</channel>
In the TUI, channel messages are displayed in a friendly format:
#fakechat · web: Hello, please help me look into this issue.

Settings

You can control the channel feature in settings.json:
{
"channelsEnabled": true
}
Setting it to false completely disables the channel feature.

Building Channels

Basic Requirements

A channel server requires:
1. Declare the claude/channel capability so that CodeBuddy Code registers a notification listener.
2. Send the notifications/claude/channel event.
3. Connect over stdio transport (CodeBuddy Code starts it as a child process).

Minimal Example: Webhook Receiver

#!/usr/bin/env bun
import { Server } from '@modelcontextprotocol/sdk/server/index.js'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'

const mcp = new Server(
{ name: 'webhook', version: '0.0.1' },
{
capabilities: { experimental: { 'claude/channel': {} } },
instructions: 'Events from webhooks arrive with the <channel source="webhook" ...> tag. This is a one-way channel, so you only need to read and process them.',
},
)

await mcp.connect(new StdioServerTransport())

Bun.serve({
port: 8788,
hostname: '127.0.0.1',
async fetch(req) {
const body = await req.text()
await mcp.notification({
method: 'notifications/claude/channel',
params: {
content: body,
meta: { path: new URL(req.url).pathname, method: req.method },
},
})
return new Response('ok')
},
})
Register in .mcp.json:
{
"mcpServers": {
"webhook": { "command": "bun", "args": ["./webhook.ts"] }
}
}

Server Configuration Options

Field
Type
Description
capabilities.experimental['claude/channel']
object
Required. Always {}. After declaration, CodeBuddy Code registers a notification listener.
capabilities.experimental['claude/channel/permission']
object
Optional. Always {}. Declares that this channel can receive permission relay requests.
capabilities.tools
object
Required for bidirectional channels. Always {}. Standard MCP tool capability.
instructions
string
Recommended. Injects into the system prompt and tells CodeBuddy Code how to handle events on this channel.

Notification Formats

When the notifications/claude/channel notification is sent, params contains two fields:
Field
Type
Description
content
string
Event content, which becomes the body of the <channel> tag.
meta
Record<string, string>
Optional. Each key-value pair becomes an attribute of the <channel> tag. Key names can contain only letters, digits, and underscores. Keys containing hyphens or other characters are silently discarded.
Example:
await mcp.notification({
method: 'notifications/claude/channel',
params: {
content: 'build failed on main',
meta: { severity: 'high', run_id: '1234' },
},
})
Format upon arrival at CodeBuddy Code:
<channel source="webhook" severity="high" run_id="1234">
build failed on main
</channel>

Exposing the Reply Tool

A bidirectional channel needs to expose standard MCP tools so that CodeBuddy Code can reply to messages:
import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js'

mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [{
name: 'reply',
description: 'Send a reply message through this channel',
inputSchema: {
type: 'object',
properties: {
chat_id: { type: 'string', description: 'The conversation ID to reply to' },
text: { type: 'string', description: 'The message to send' },
},
required: ['chat_id', 'text'],
},
}],
}))

mcp.setRequestHandler(CallToolRequestSchema, async req => {
if (req.params.name === 'reply') {
const { chat_id, text } = req.params.arguments as { chat_id: string; text: string }
// Call your chat platform API to send a message.
await sendToPlatform(chat_id, text)
return { content: [{ type: 'text', text: 'sent' }] }
}
throw new Error(`unknown tool: ${req.params.name}`)
})

Sender Security Control

An unprotected channel is a prompt injection attack vector. Anyone who can access your endpoint can inject text into CodeBuddy Code.
Before calling mcp.notification(), you must verify the sender's identity:
const allowed = new Set(loadAllowlist())

// In the message handler, before sending a notification:
if (!allowed.has(message.from.id)) { // Check the sender ID, not the group ID.
return // Silently discard.
}
await mcp.notification({ ... })
Important: Always verify based on the sender identity (message.from.id), not the chat identity (message.chat.id). In group chats, these two values differ, and verifying by group allows anyone in the group to inject messages into the session.

Permission Relaying

When CodeBuddy Code calls a tool that requires approval, such as Bash, Write, or Edit, the local terminal opens a permission dialog. A bidirectional channel can also receive this prompt, allowing you to approve or deny it on a remote device.
The dialog boxes on the local terminal and the remote channel open simultaneously. The first response received takes effect, and the other closes automatically.

Enabling Permission Relaying

Add claude/channel/permission to the Server constructor:
capabilities: {
experimental: {
'claude/channel': {},
'claude/channel/permission': {}, // Enable permission relay.
},
tools: {},
},

Permission Request Fields

CodeBuddy Code sends notifications/claude/channel/permission_request, which contains the following fields:
Field
Description
request_id
Five lowercase letters (excluding l), used to match the reply.
tool_name
Name of the tool to be used by CodeBuddy Code, such as Bash and Write
description
Readable description of the tool call
input_preview
JSON string of tool parameters, truncated to 200 characters

Sending Adjudications

Your channel needs to send a notifications/claude/channel/permission notification:
await mcp.notification({
method: 'notifications/claude/channel/permission',
params: {
request_id: '<received request_id>',
behavior: 'allow', // or 'deny'
},
})

Processing Inbound Adjudications

In the inbound message handler, identify replies in the format yes <id> or no <id>:
// Matches "y abcde", "yes abcde", "n abcde", "no abcde"
// [a-km-z] is the ID alphabet used by CodeBuddy Code (lowercase, skipping 'l').
const PERMISSION_REPLY_RE = /^\\s*(y|yes|n|no)\\s+([a-km-z]{5})\\s*$/i

const m = PERMISSION_REPLY_RE.exec(message.text)
if (m) {
await mcp.notification({
method: 'notifications/claude/channel/permission',
params: {
request_id: m[2].toLowerCase(),
behavior: m[1].toLowerCase().startsWith('y') ? 'allow' : 'deny',
},
})
return // Handle as a decision without forwarding to chat.
}

Packaging as a Plugin

Wrapping a channel as a plugin makes it easier to share and install. Users can install it via /plugin install and then enable it with --channels plugin:<name>@<marketplace>.

References

fakechat example: A complete bidirectional channel implementation that includes a Web UI, file attachments, and a reply tool.
MCP Protocol: Channels are implemented based on the MCP protocol.


Help and Support

Was this page helpful?

Help us improve! Rate your documentation experience in 5 mins.

Feedback