Channels в Claude Code: подключаем Telegram, Discord и вебхуки

Channels превращают Claude Code в хаб для внешних событий. Показываю, как подключить Telegram, Discord и написать свой webhook-канал за 5 минут.

Channels в Claude Code: подключаем Telegram, Discord и вебхуки
TL;DR: Channels в Claude Code позволяют получать сообщения из Telegram, Discord и любых вебхуков прямо в терминальную сессию. Claude читает событие, реагирует и может ответить обратно. Показываю, как всё настроить за 5 минут.

Channels появились 20 марта 2026 года в research preview. По сути это MCP-серверы, которые работают как мост между внешним миром и твоей сессией Claude Code. Telegram, Discord, вебхуки от CI, алерты мониторинга, что угодно.

Что понадобится

  • Claude Code v2.1.80+ (проверь claude --version)
  • Аккаунт claude.ai (API-ключи и Console не поддерживаются)
  • Bun (предустановленные плагины написаны на нём, проверь bun --version)
  • Для Telegram: бот через @BotFather
  • Для Discord: приложение в Developer Portal
  • Team/Enterprise: админ должен включить channelsEnabled в managed settings

Шаг 1. Проверяем на fakechat

Перед тем как подключать настоящие платформы, есть смысл потестировать механику на fakechat. Это демо-канал от Anthropic, который поднимает чат-UI на localhost. Никаких внешних сервисов, токенов, ботов.

Устанавливаем плагин:

/plugin install fakechat@claude-plugins-official

Запускаем Claude Code с каналом:

claude --channels plugin:fakechat@claude-plugins-official

Открывай http://localhost:8787 в браузере. Пишешь сообщение в веб-интерфейсе, оно прилетает в терминальную сессию Claude Code. Claude отвечает, ответ появляется обратно в браузере.

Если всё работает, переходим к настоящим платформам.

Шаг 2. Подключаем Telegram

Telegram, наверное, самый практичный вариант.

Создаём бота

  1. Открой @BotFather в Telegram
  2. Отправь /newbot
  3. Придумай имя и username (должен заканчиваться на bot)
  4. Скопируй токен

Ставим плагин и конфигурируем

/plugin install telegram@claude-plugins-official
/telegram:configure <твой-токен>

Запускаем с каналом

claude --channels plugin:telegram@claude-plugins-official

Привязываем аккаунт

Это важный момент. Channels используют allowlist отправителей, и пока ты не пройдёшь pairing, бот будет игнорировать все сообщения.

  1. Найди своего бота в Telegram и отправь ему любое сообщение
  2. Бот ответит кодом сопряжения
  3. В терминале Claude Code выполни: /telegram:access pair <код>
  4. Зафиксируй политику: /telegram:access policy allowlist

Готово. Теперь пишешь боту «проверь, проходят ли тесты на feature-ветке», и Claude Code в терминале начинает работать. Ответ прилетает обратно в Telegram.

Пишу про Claude Code и AI-инструменты для разработчиков. Channels, MCP, агенты — подписывайся в телеге.

Шаг 3. Подключаем Discord

Процесс похож на Telegram, но чуть больше настроек на стороне Discord.

Создаём бота

  1. Зайди в Discord Developer Portal
  2. Нажми New Application, задай имя
  3. Перейди в BotReset Token → скопируй токен
  4. Там же включи Message Content Intent в разделе Privileged Gateway Intents (без этого бот не увидит текст сообщений)
  5. Пригласи бота на сервер с правами: просмотр каналов, отправка сообщений, чтение истории, прикрепление файлов

Ставим и запускаем

/plugin install discord@claude-plugins-official
/discord:configure <твой-токен>
claude --channels plugin:discord@claude-plugins-official

Привязка аккаунта

Напиши боту в личку, получи код сопряжения, подтверди в терминале:

/discord:access pair <код>

Можно подключить оба канала одновременно, перечислив плагины через пробел:

claude --channels plugin:telegram@claude-plugins-official plugin:discord@claude-plugins-official

Шаг 4. Пишем свой webhook-канал

Telegram и Discord покрывают базовые сценарии, но интереснее другое: можно написать свой канал для чего угодно. CI упал? Мониторинг кричит? Grafana шлёт алерт? Всё это можно направить прямо в Claude Code.

Покажу на примере простого HTTP-приёмника, который принимает POST-запросы и пробрасывает их в сессию.

Создаём проект

mkdir webhook-channel && cd webhook-channel
bun add @modelcontextprotocol/sdk

Пишем сервер

Создай файл webhook.ts:

#!/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 the webhook channel arrive as <channel source="webhook" ...>. They are one-way: read them and act, no reply expected.',
  },
)

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')
  },
})

На что обратить внимание:

  • capabilities: { experimental: { 'claude/channel': {} } } — именно эта строка делает MCP-сервер каналом. Без неё Claude Code не зарегистрирует listener
  • instructions — попадает в системный промпт Claude. Объясни, чего ожидать от событий и нужно ли отвечать
  • hostname: '127.0.0.1' — слушаем только на localhost, ничего наружу не торчит

Регистрируем в .mcp.json

{
  "mcpServers": {
    "webhook": { "command": "bun", "args": ["./webhook.ts"] }
  }
}

Тестируем

Кастомные каналы пока не в официальном allowlist, поэтому нужен флаг разработчика:

claude --dangerously-load-development-channels server:webhook

Claude Code прочитает .mcp.json, запустит webhook.ts как подпроцесс, и HTTP-сервер поднимется автоматически. В другом терминале:

curl -X POST localhost:8788 -d "build failed on main: https://ci.example.com/run/1234"

В сессии Claude Code появится событие:

<channel source="webhook" path="/" method="POST">
build failed on main: https://ci.example.com/run/1234
</channel>

Claude прочитает сообщение и начнёт разбираться. Если в тексте упомянута ссылка на CI, он может сам полезть смотреть логи.

Шаг 5. Добавляем двустороннюю связь

Односторонний канал уже полезен для алертов, но если хочешь, чтобы Claude мог отвечать (например, в чат-бридже), нужно добавить reply tool. Это стандартный MCP-инструмент, ничего специфичного для каналов.

Дополним webhook.ts:

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

const mcp = new Server(
  { name: 'webhook', version: '0.0.1' },
  {
    capabilities: {
      experimental: { 'claude/channel': {} },
      tools: {},  // включаем обнаружение инструментов
    },
    instructions: 'Messages arrive as <channel source="webhook" chat_id="...">. Reply with the reply tool, passing the chat_id from the tag.',
  },
)

// Регистрируем reply tool
mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [{
    name: 'reply',
    description: 'Send a message back over this channel',
    inputSchema: {
      type: 'object',
      properties: {
        chat_id: { type: 'string', description: 'The conversation to reply in' },
        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 }
    // Тут вызов API твоей платформы
    console.error(`Reply to ${chat_id}: ${text}`)
    return { content: [{ type: 'text', text: 'sent' }] }
  }
  throw new Error(`unknown tool: ${req.params.name}`)
})

await mcp.connect(new StdioServerTransport())

let nextId = 1
Bun.serve({
  port: 8788,
  hostname: '127.0.0.1',
  async fetch(req) {
    const body = await req.text()
    const chat_id = String(nextId++)
    await mcp.notification({
      method: 'notifications/claude/channel',
      params: {
        content: body,
        meta: { chat_id, path: new URL(req.url).pathname, method: req.method },
      },
    })
    return new Response('ok')
  },
})

Что добавилось:

  • tools: {} в capabilities, чтобы Claude Code обнаружил инструменты сервера
  • ListToolsRequestSchema описывает reply tool со схемой параметров
  • CallToolRequestSchema обрабатывает вызовы (замени console.error на реальный API отправки)
  • chat_id в meta, чтобы Claude знал, куда отвечать

Шаг 6. Защита от prompt injection

Открытый канал без фильтрации отправителей — это вектор prompt injection. Любой, кто может отправить POST на твой endpoint, может подсунуть текст прямо в контекст Claude.

Проверяй отправителя до вызова mcp.notification():

const allowed = new Set(loadAllowlist()) // из access.json или аналога

// Внутри обработчика сообщений, ДО отправки:
if (!allowed.has(message.from.id)) {
  return // игнорируем молча
}
await mcp.notification({ ... })
⚠️
Фильтруй по ID отправителя (message.from.id), а не по ID чата (message.chat.id). В групповых чатах это разные вещи, и фильтрация по комнате позволит любому участнику группы инжектить сообщения в сессию.

Официальные плагины Telegram и Discord используют именно этот подход: allowlist по sender ID + pairing flow для первичной привязки.

Результат

Если всё настроил правильно, у тебя теперь есть Telegram/Discord-бот для управления Claude Code с телефона, webhook-приёмник для алертов от CI и мониторинга, и опционально двусторонний канал, через который Claude может отвечать.

В терминале ты видишь входящее сообщение и инструмент, который Claude вызвал для ответа. Сам текст ответа появляется на платформе отправителя, в терминале только подтверждение «sent».

События приходят только пока сессия открыта. Для always-on режима запускай Claude Code в фоновом процессе или persistent-терминале (tmux, screen). Но будь осторожен с --dangerously-skip-permissions — он отключает все подтверждения.

Пишу про Claude Code и AI-инструменты для разработчиков. Channels, MCP, агенты — подписывайся в телеге.

Частые ошибки

Если видишь «blocked by org policy», значит ты в Team или Enterprise организации, а админ не включил channelsEnabled. Включается в claude.ai → Admin settings → Claude Code → Channels.

Канал регистрируется, но сообщения не приходят? Проверь, что ты указал сервер в --channels. Запись в .mcp.json сама по себе не активирует канал, нужно явно передать имя при запуске.

Кастомный канал не загружается. Во время research preview кастомные каналы не в allowlist. Используй --dangerously-load-development-channels server:<имя>. Флаг работает только для конкретного entry, а не для всех каналов в сессии.

Telegram-бот игнорирует сообщения? Скорее всего не прошёл pairing. Напиши боту, получи код, подтверди через /telegram:access pair <код>.

FAQ

Чем Channels отличается от Remote Control?

Remote Control синхронизирует терминальную сессию с claude.ai или мобильным приложением. Ты видишь полный UI и можешь печатать, как будто сидишь за терминалом. Channels работают иначе: ты отправляешь сообщение, Claude обрабатывает его и отвечает. Это модель передачи сообщений, а не screen-sharing.

Чем Channels отличается от Dispatch?

Dispatch — фича Cowork для не-разработчиков. Она связывает мобильное приложение Claude с десктопной сессией для задач вроде организации файлов и создания контента. Channels — для разработчиков, построены на MCP и заточены под event-driven воркфлоу.

Можно ли подключить Slack или WhatsApp?

Официальных плагинов пока нет (март 2026), но протокол открытый. Любой MCP-сервер с claude/channel capability может стать каналом. Нужно написать свой плагин по схеме из шага 4 и запустить с --dangerously-load-development-channels.

Что происходит с сообщениями, когда сессия закрыта?

Они не доставляются. Channels работают только при активной сессии. Для постоянной доступности запускай Claude Code в фоновом процессе.

Безопасно ли давать внешним системам доступ к Claude Code?

При правильной настройке — да. Sender allowlist отсекает всех, кого ты не добавил. Два уровня контроля: на уровне сессии (--channels) и на уровне организации (channelsEnabled). Кастомные каналы слушают только на localhost.

Что ещё почитать