MCPサーバーのChannels連携を実装する
MCPサーバーにclaude/channel capability(機能宣言)を足すとClaude Codeセッションへ通知を送り込めます。有効化手順と落とし穴を解説します。
普段のMCPサーバーは、Claudeがツールを呼んだときだけ答えます。ここにclaude/channelというcapability(機能宣言)を1つ足すと、そのサーバーは外部で何かが起きた瞬間に、実行中のセッションへ自分から通知を送り込めるようになります。これがClaude Code Channelsで、サーバー側に必要なのはclaude/channelの宣言と通知の送出です。研究プレビュー段階のため、有効化にはセッション単位の明示的な有効化が要ります。
MCPサーバーがChannelsとして動く仕組みとは何か
Channelとは、claude/channel capabilityを宣言したMCPサーバーのことです。宣言があると、Claude Codeはそのサーバー用に通知リスナーを登録します。サーバー側がnotifications/claude/channelを送るたびに、イベントが<channel>タグとしてClaudeの文脈に流れ込みます。CIの失敗通知や監視アラートのような一方向のイベント転送も、Telegramのようなチャットの橋渡しも、同じ仕組みの上に成り立っています。
サーバーはClaude Codeと同じマシン上で、子プロセスとして起動します。通信は標準入出力(stdio)です。チャットプラットフォーム向けのプラグインは、手元からAPIをポーリングしてメッセージを拾うので、公開するURLは要りません。Webhook向けのサーバーは、ローカルのHTTPポートで待ち受け、外部システムからのPOSTを受けてClaudeへ流します。
外から関わる仕組みにはClaude Tagもあります。Team・Enterprise向けで、Slackの@claudeメンションから新しいクラウドセッションを立ち上げます(Pro・Maxは従来のClaude in Slack)。Channelsは、あなたがすでに開いているローカルセッションにイベントを送り込む点が異なります。
通常のMCPツール呼び出しとの違い
同じMCPサーバーでも、Channel対応の有無で挙動がまったく変わります。違いは会話の起点、有効化の条件、応答の扱いの3点です。
通常のMCPとChannelの違い
通常のMCPサーバー
Claudeがタスクの途中で必要になったときに問い合わせ、レスポンスを待って結果を受け取ります。.mcp.jsonに登録すれば使えます。プロジェクトの.mcp.jsonのサーバーは、初回に承認ダイアログが出ます。
Channel
外部イベントが起きた時点で、サーバー側から送り込みます。登録に加えて、起動時に--channelsでセッションを明示的に有効化します。組織側はchannelsEnabledポリシーで制御し、claude.ai Team/Enterpriseは既定でブロックです。
送った通知への確認応答もありません。Claude Codeは受信を確認応答しないので、サーバー側は「送りっぱなし」で動くことになります。
ステップ1 — サーバーにclaude/channel capabilityを宣言する
自分のMCPサーバーをChannel化する最初の一歩は、Serverコンストラクタのcapabilitiesにclaude/channelを追加することです。
const mcp = new Server(
{ name: 'my-server', version: '0.0.1' },
{
capabilities: { experimental: { 'claude/channel': {} } },
instructions: 'Events arrive as <channel source="my-server" ...>. One-way: read and act, no reply expected.',
},
)このキーが存在するだけで、Claude Codeはそのサーバーを通知の登録対象として認識します。instructionsは接続時にClaudeへ渡されるテキストで、どんなイベントが来るか・返信が必要かどうか・返信が必要ならどのツールでどの属性を渡すかをここに書いておきます。
イベントを送るのはmcp.notification()です。contentが<channel>タグの本文になり、metaの各エントリがタグの属性になります。
await mcp.notification({
method: 'notifications/claude/channel',
params: {
content: 'build failed on main: https://ci.example.com/run/1234',
meta: { severity: 'high', run_id: '1234' },
},
})Claudeの文脈には、サーバー名をsourceに入れた次のタグとして届きます。
<channel source="your-channel" severity="high" run_id="1234">
build failed on main: https://ci.example.com/run/1234
</channel>作れるChannelは3つの型に分かれる
capabilityの組み合わせで、Channelの性格が決まります。
Channelの3つの型
一方向(アラート転送)
toolsを宣言しません。CI失敗や監視アラートのようなイベントを、Claudeが読んで動くだけの構成です。双方向(チャットブリッジ)
tools: {}を宣言し、replyのような標準のMCPツールを公開します。instructionsに「返信はreplyツールで、タグのchat_idを渡す」と書いておくと、Claudeがタグの属性を拾って返信先を決められます。権限リレー付き
claude/channel/permission: {}も宣言した双方向Channelです。ツール実行の承認プロンプト(Bash、Write、Editなど)を手元の端末と並行してチャット側へ転送し、先に届いた回答が適用されます。
権限リレーを宣言するなら、送信者の認証が前提です。返信できる人は誰でも、あなたのセッションのツール実行を承認・拒否できてしまうためです。受信側では、チャットルームではなく送信者のIDで許可リストと照合します。グループチャットでは両者が別物なので、ルームで照合すると許可リストに入ったグループの全員が、セッションにメッセージを差し込めます。
権限リレーの宣言はfalseでは無効になりません。v2.1.234より前のClaude Codeはfalseも宣言ありとして扱ったため、オプトアウトするにはキー自体を省きます。リレーの対象はツール実行の承認だけで、プロジェクトの信頼確認とMCPサーバーの同意ダイアログは端末にしか出ません。
ステップ2 — --channelsフラグでセッションを有効化する
capability(機能宣言)を宣言しただけでは、Channelとしては動きません。起動時に--channelsでそのサーバーを明示的に指定すると、セッションが通知を受け取るようになります。
claude --channels plugin:telegram@claude-plugins-official--channelsはプレビュー中、承認済み一覧のプラグイン(plugin:<name>@<marketplace>)のみを受け付けます。この--channelsによるセッション単位の有効化は、.mcp.jsonのスコープ(local・project・user)とは別の軸です。.mcp.json側のスコープはサーバーをどこから読み込むかを決め、--channelsはそのセッションで通知を受け取るかどうかを決めます。イベントが届くのは、この2つが両方そろったときです。Team・Enterpriseプランの組織設定は、後述の認証とプラットフォームの制約の節にまとめています。
自作サーバーを手元で動かして確かめる
承認済み一覧に載らない自作サーバーは、開発フラグで試します。公式のWebhook受信サーバーの例(ポート8788、webhook.ts)を使うと、次の流れで通知が届くところまで確認できます。
開発フラグでの動作確認
- 1
サーバーを.mcp.jsonに登録する
プロジェクト直下の
.mcp.jsonに"webhook": { "command": "bun", "args": ["./webhook.ts"] }をmcpServersの下へ書きます。Claude Codeは起動時にこの設定を読み、サーバーを子プロセスとして立ち上げます。自分でサーバーを起動する必要はありません。 - 2
開発フラグ付きで起動する
claude --dangerously-load-development-channels server:webhookで起動します。開発チャンネルを読み込む旨の全画面の警告が出るので、I am using this for local developmentを選んで進みます。 - 3
新しいMCPサーバーの同意に応える
そのプロジェクトで初めて起動するときは、「New MCP server found in this project: webhook」というダイアログも出ます。Use this MCP serverを選びます。
- 4
登録の表示を確かめる
起動バナーの下に、
Channels (experimental) messages from server:webhook inject directly in this sessionで始まる薄い表示が出れば登録できています。
別の端末からcurlでWebhookを模擬します。
curl -X POST localhost:8788 -d "build failed on main: https://ci.example.com/run/1234"Claudeの文脈には<channel source="webhook" path="/" method="POST">タグ付きで本文が届きます。端末側の表示は生のタグではなく、← webhook: build failed on main: ...の1行要約です。一方向のChannelなので、Claudeが何かを調べて動いても、Webhook側に返事は戻りません。
組み合わせにも決まりがあります。開発フラグが承認済み一覧を外すのは、フラグで指定した項目ごとです。--channelsと併用しても、--channels側の項目には効きません。また、このフラグが外すのは承認済み一覧だけで、組織のchannelsEnabledポリシーは変わらず効きます。出どころの分からないChannelの実行には使わないでください。
通知が届かないときの切り分け
curlは成功するのにClaudeに何も届かない場合は、サーバーの状態から順に見ます。
| 症状 | 見る場所 | 読み取れること |
|---|---|---|
curlは成功するが届かない | 見る場所セッション内で/mcp | 読み取れることfailedなら、多くはサーバーファイルの依存関係かimportのエラー |
| 原因の詳細がほしい | 見る場所claude --debug --dangerously-load-development-channels server:webhookで再起動し、~/.claude/debug/<session-id>.txtを見る | 読み取れることサーバーのstderrのトレース |
curlが「connection refused」 | 見る場所lsof -i :<port> | 読み取れることポートが未バインドか、前回の古いプロセスが握っている。killしてから再起動 |
| 起動時に「blocked by org policy」 | 見る場所管理者に依頼 | 読み取れること組織のchannelsEnabledが有効でない |
起動バナーの下の警告も手がかりです。--channelsに渡したプラグインが承認済み一覧に無いと、Claude Codeは通常どおり起動しますが、Channelだけが登録されません。起動時の通知に理由が出ます。
MCPプロトコルネゴシエーションの落とし穴
v2のMCPクライアントランタイムでは、サーバーがMCPプロトコルリビジョン2026-07-28をネゴシエートすると、Channelメッセージを配信できません。Claude Codeはそのサーバーをチャンネルとして登録しないため、エラーは表に出ず、単に通知が届かないだけです。
厄介なのは、この条件が自分の設定を変えなくても満たされうる点です。Claude Codeは、環境変数MCP_PROTOCOL_NEGOTIATIONをautoにするとstdioサーバーへこのリビジョンを打診します。さらにAnthropicは、v2.1.285以降で機能フラグを取得するセッションについて、これを既定でオンにしていく方針です。
stdioのChannelサーバーを従来のハンドシェイクのままにしたいなら、MCP_PROTOCOL_NEGOTIATIONをlegacyに設定します。legacyは全サーバーを従来の方式に保ちます。このリビジョンに対応していないChannelサーバーは、従来のハンドシェイクで接続し、これまでどおり登録されます。
通知は届いても確認応答が無い
mcp.notification()のawaitが解決するのは、メッセージがトランスポートに書き込まれた時点であって、Claudeがそれを処理した時点ではありません。セッションがそのサーバーをChannelとして読み込んでいない場合や、組織ポリシーがブロックしている場合、Claude Codeはイベントを黙って捨て、サーバー側にはエラーを返しません。確実に処理されたか知りたいなら、サーバー側でイベントの状態を追跡し、Claudeが状況を報告できる返信用ツールを別途公開する必要があります。
イベントはセッションにキューされ、順番に処理されます。複数の通知が届いたタイミングでClaudeが作業中だった場合、それらはまとめて次のターンで配信され、Claudeはひとまとまりとして処理します。独立したイベントの流れを並行して処理したいなら、セッションを分けます。
metaに付けられるキーは、英数字とアンダースコアだけの識別子に限られます。ハイフンを含むキーは、エラーなく<channel>タグの属性から落とされるので、run-idではなくrun_idと書きます。
認証とプラットフォームの制約
Channelsを使うにはclaude.aiアカウントかAnthropic ConsoleのAPIキーによる認証が必要です。Amazon Bedrock・Google Cloud's Agent Platform・Microsoft Foundryでは利用できません。組織に属さないPro・Maxユーザーはこうしたポリシーチェックの対象外で、--channelsをセッションごとに指定するだけで使えます。
組織の扱いは、認証の方法で既定値が分かれます。
- claude.aiのTeam・Enterprise: Ownerが有効にするまでブロックされます。claude.aiの管理設定のClaude Code、Channelsから切り替えるか、managed settingsで
channelsEnabledをtrueにします - Anthropic ConsoleのAPIキー認証: 既定で許可されます。ただし組織がmanaged settingsを配布している場合は、
channelsEnabledが設定されるまでブロックされます
channelsEnabledが無効または未設定のときも、MCPサーバー自体は接続し、ツールは動きます。届かないのはChannelのメッセージだけで、起動時の警告が管理者に有効化を頼むよう伝えます。
管理者が使えるプラグインを絞りたい場合は、allowedChannelPluginsでAnthropicの既定一覧を組織独自の一覧に置き換えます。
{
"channelsEnabled": true,
"allowedChannelPlugins": [
{ "marketplace": "claude-plugins-official", "plugin": "telegram" },
{ "marketplace": "acme-corp-plugins", "plugin": "internal-alerts" }
]
}空配列を設定すると一覧経由の起動はすべてブロックされますが、--dangerously-load-development-channelsはこの制限をバイパスできてしまいます。開発フラグも含めて完全に締め出したいなら、allowedChannelPluginsを空にするのではなくchannelsEnabled自体を未設定のままにします。
既存のMCP機能との重なりに注意する
Channel対応にしても、そのサーバーの通常のMCP挙動が消えるわけではありません。返信用ツールは標準のMCPツールなので、サーバーごとのtimeoutとアイドルタイムアウトの対象です。メインの会話からの呼び出しが2分を超えて実行中だと、バックグラウンドタスクに自動で移されます(この自動バックグラウンド化はv2.1.212以降の挙動です)。双方向チャンネルの返信ツールを設計するときは、この2つのタイムアウトが効くことを前提にしておく必要があります。
Claude Codeの他の連携方法との違い
外部からClaude Codeのセッションに関わる方法は、Channelsだけではありません。何を任せたいかによって向き不向きが分かれます。
| 機能 | 何をするか | 向いている場面 |
|---|---|---|
| Claude Code on the web | 何をするかGitHubからクローンした新規のクラウドサンドボックスでタスクを実行する | 向いている場面後で結果だけ確認すればいい、自己完結した非同期タスクを丸投げする |
| Claude Tag(Slack。Team・Enterprise向けで、Pro・Maxは従来のClaude in Slack) | 何をするか@claudeメンションからクラウドセッションを立ち上げる | 向いている場面チームの会話の文脈からそのままタスクを始める |
| 通常のMCPサーバー | 何をするかClaudeがタスク中に問い合わせる。セッションへ送らない | 向いている場面読み取り専用の照会や、必要なときだけ叩くAPI連携 |
| Remote Control | 何をするかclaude.aiやモバイルアプリから、手元で動いているセッションを操作する | 向いている場面席を離れた場所から進行中のセッションを操縦する |
| Channels | 何をするか実行中のセッションへ外部イベントを送り込む | 向いている場面CI・監視・チャットのイベントを、あなたがすでに開いているセッションに割り込ませる |
研究プレビュー中はヘルプに載らないフラグがある
Channelsは研究プレビュー段階の機能で、--channelsのフラグ仕様やプロトコルの契約はフィードバックをもとに変わる可能性があります。公式ドキュメントは、--channelsも--dangerously-load-development-channelsもclaude --helpに表示されないと説明しています。v2.1.289のclaude --helpでchannelsの文字列を数えると0件です。
claude --version
claude --help | grep -c -i channels出力は2.1.289 (Claude Code)と0です。ヘルプに出ないのは仕様どおりで、フラグ自体は動作します。
自作のサーバーを試す間は、開発フラグで承認済み一覧をバイパスします。配布する段階になったらClaude Codeプラグイン完全ガイドの手順でプラグイン化し、マーケットプレイスに公開したうえで正式な一覧入りを別途調整します。
プラグインを入れた直後に再起動せず反映したいときは/reload-pluginsを使います。
まとめ
実装に進むなら、手元のサーバーを開発フラグで動かしてcurlで通知を流し、届き方を見てからプラグイン化を考える順番が手戻りの少ない進め方です。サーバーの基本的な追加方法自体はClaude Code MCP設定ガイドで扱っています。