> ## Documentation Index
> Fetch the complete documentation index at: https://docs.simular.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Channels (research preview)

> Let Sai push results into Claude Code instead of being polled.

Claude Code channels let an MCP server send a notification into the session on its own. With channels, the Sai server holds the `/events` long-poll itself and wakes Claude Code when the task needs an approval, finishes or fails. Without channels, the model calls `sai_task_wait` in a loop.

This is an advanced option. Polling is the baseline and works everywhere.

## Constraints

* Claude Code only. Codex and Cursor have no equivalent.
* Channels are a research preview and require Anthropic authentication (a Claude account), not a third-party API key.
* Third-party channel plugins must be loaded explicitly with `--dangerously-load-development-channels`.

## Enable

```bash theme={null}
claude mcp add sai -e SAI_API_KEY=sapi_... -e SAI_PUSH=1 -- npx -y @simular-ai/sai-mcp
claude --dangerously-load-development-channels server:sai
```

Claude Code shows a warning dialog for development channels; choose **I am using this for local development**.

Only set `SAI_PUSH=1` together with that flag. Without it, the model is told not to poll and the pushed results are dropped. To go back to polling, remove the server and add it again without `SAI_PUSH`.

## What changes

* `sai_task_start` returns `push: true`.
* The model does not call `sai_task_wait`. The tool description tells it so.
* When the session reaches `needs_approval`, `idle` or `error`, the server emits a `notifications/claude/channel` message. Its `content` is the text so far and its `meta` is:

```json theme={null}
{
  "session_id": "cs_01HZY",
  "event": "needs_approval",
  "approval_id": "ap_7Qw",
  "approval_url": "https://sai.simular.ai/approval/3fA9kQ2xYz/ap_7Qw?from=api"
}
```

`approval_id` and `approval_url` are present only when `event` is `needs_approval`.

## Gotchas

* If the flag is missing, the server still connects and works in polling mode. Nothing breaks; you only lose the push.
* The server always declares `capabilities.experimental["claude/channel"]`. That is expected and harmless in clients that do not use it.
* Reference: the Claude Code channels documentation at code.claude.com.
