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. |
--channels parameter to specify the channels to load:# Load plugin-type channelscodebuddy --channels plugin:fakechat@claude-plugins-official# Load the channel server configured in .mcp.jsoncodebuddy --channels server:webhook# Load multiple channels (comma-separated)codebuddy --channels plugin:telegram@claude-plugins-official,plugin:discord@claude-plugins-official
--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
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> tags:<channel source="fakechat" sender="web" chat_id="1">Hello, please help me look into this issue.</channel>
#fakechat · web: Hello, please help me look into this issue.
settings.json:{"channelsEnabled": true}
false completely disables the channel feature.claude/channel capability so that CodeBuddy Code registers a notification listener.notifications/claude/channel event.#!/usr/bin/env bunimport { 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')},})
.mcp.json:{"mcpServers": {"webhook": { "command": "bun", "args": ["./webhook.ts"] }}}
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. |
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. |
await mcp.notification({method: 'notifications/claude/channel',params: {content: 'build failed on main',meta: { severity: 'high', run_id: '1234' },},})
<channel source="webhook" severity="high" run_id="1234">build failed on main</channel>
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}`)})
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({ ... })
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.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.claude/channel/permission to the Server constructor:capabilities: {experimental: {'claude/channel': {},'claude/channel/permission': {}, // Enable permission relay.},tools: {},},
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 |
notifications/claude/channel/permission notification:await mcp.notification({method: 'notifications/claude/channel/permission',params: {request_id: '<received request_id>',behavior: 'allow', // or 'deny'},})
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*$/iconst 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.}
/plugin install and then enable it with --channels plugin:<name>@<marketplace>.Was this page helpful?
You can also Contact sales or Submit a Ticket for help.
Help us improve! Rate your documentation experience in 5 mins.
Feedback