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

# @Channel

> The @Channel decorator defines a push-based notification channel with source configuration and optional two-way communication.

## Basic Usage

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
import { Channel, ChannelContext } from '@frontmcp/sdk';
import type { ChannelNotification } from '@frontmcp/sdk';

@Channel({
  name: 'deploy-alerts',
  description: 'CI/CD deployment notifications',
  source: { type: 'webhook', path: '/hooks/deploy' },
})
class DeployAlertChannel extends ChannelContext {
  async onEvent(payload: unknown): Promise<ChannelNotification> {
    const { body } = payload as { body: { status: string; version: string } };
    return {
      content: `Deploy ${body.status}: ${body.version}`,
      meta: { status: body.status },
    };
  }
}
```

## Signature

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
function Channel(opts: ChannelMetadata): ClassDecorator
```

## Function Builder

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
function channel(opts: ChannelMetadata): (handler: ChannelMessageHandler) => () => void
```

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
const ErrorChannel = channel({
  name: 'error-alerts',
  source: { type: 'app-event', event: 'app:error' },
})((payload) => ({
  content: `Error: ${(payload as { message: string }).message}`,
}));
```

## Configuration Options

### Required Properties

| Property | Type | Description |
| - | - | - |
| `name` | `string` | Unique channel identifier. Becomes the `source` attribute in notifications. |
| `source` | `ChannelSourceConfig` | Event source configuration (see Source Types below). |

### Optional Properties

| Property | Type | Default | Description |
| - | - | - | - |
| `description` | `string` | — | Human-readable description. Included in server instructions for Claude. |
| `twoWay` | `boolean` | `false` | Enable reply support. Auto-registers `channel-reply` tool when `true`. |
| `meta` | `Record<string, string>` | — | Static metadata appended to every notification from this channel. |
| `tools` | `ToolType[]` | — | Tools contributed by this channel. Auto-registered in the scope's tool registry. |
| `replay` | `{ enabled: boolean; maxEvents?: number }` | — | Buffer events for replay when sessions connect later. |
| `tags` | `string[]` | — | Tags for categorization and filtering. |
| `availableWhen` | `EntryAvailability` | — | Environment constraints (platform, runtime, env). |

### Source Types

#### Webhook

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
source: { type: 'webhook', path: '/hooks/github' }
```

| Field | Type | Description |
| - | - | - |
| `type` | `'webhook'` | Source discriminator |
| `path` | `string` | HTTP POST endpoint path |

#### App Event

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
source: { type: 'app-event', event: 'app:error' }
```

| Field | Type | Description |
| - | - | - |
| `type` | `'app-event'` | Source discriminator |
| `event` | `string` | Event name to subscribe to on `ChannelEventBus` |

#### Agent Completion

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
source: { type: 'agent-completion', agentIds: ['code-reviewer'] }
```

| Field | Type | Description |
| - | - | - |
| `type` | `'agent-completion'` | Source discriminator |
| `agentIds` | `string[]` | Optional filter — only these agent IDs trigger the channel |

#### Job Completion

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
source: { type: 'job-completion', jobNames: ['daily-report'] }
```

| Field | Type | Description |
| - | - | - |
| `type` | `'job-completion'` | Source discriminator |
| `jobNames` | `string[]` | Optional filter — only these job names trigger the channel |

#### Service

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
source: { type: 'service', service: 'whatsapp-business' }
```

| Field | Type | Description |
| - | - | - |
| `type` | `'service'` | Source discriminator |
| `service` | `string` | Human-readable service identifier |

Channels with `service` source use `onConnect()` / `onDisconnect()` lifecycle hooks and `pushIncoming()` for feeding incoming events.

#### File Watcher

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
source: { type: 'file-watcher', paths: ['./logs/*.log'], events: ['change'] }
```

| Field | Type | Description |
| - | - | - |
| `type` | `'file-watcher'` | Source discriminator |
| `paths` | `string[]` | Glob patterns or file paths to watch |
| `events` | `Array<'change' \| 'create' \| 'delete' \| 'rename'>` | Optional file system events to watch |

#### Manual

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
source: { type: 'manual' }
```

No automatic wiring. Push programmatically via `scope.channelNotifications.send()`.

## ChannelNotification Type

The return type of `onEvent()`:

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
interface ChannelNotification {
  /** Notification content (appears inside <channel> tags in Claude) */
  content: string;
  /** Key-value metadata (becomes XML attributes on the <channel> tag) */
  meta?: Record<string, string>;
}
```

<Warning>
  Meta keys must be valid identifiers: letters, digits, and underscores only. Keys like `my-env` or `123start` will fail validation.
</Warning>

## Two-Way Channels

When `twoWay: true`, implement `onReply()` to handle responses from Claude:

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
@Channel({
  name: 'chat-bridge',
  source: { type: 'webhook', path: '/hooks/chat' },
  twoWay: true,
})
class ChatBridge extends ChannelContext {
  async onEvent(payload: unknown): Promise<ChannelNotification> {
    const { body } = payload as { body: { sender: string; text: string; chatId: string } };
    return {
      content: `${body.sender}: ${body.text}`,
      meta: { chat_id: body.chatId },
    };
  }

  async onReply(reply: string, meta?: Record<string, string>): Promise<void> {
    await sendToChatPlatform(meta?.chat_id, reply);
  }
}
```

The `channel-reply` tool is auto-registered with this input schema:

| Field | Type | Required | Description |
| - | - | - | - |
| `channel_name` | `string` | Yes | Target channel name |
| `text` | `string` | Yes | Reply text |
| `meta` | `Record<string, string>` | No | Metadata passed to `onReply()` |

## Server Configuration

Enable channels at the server level:

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
@FrontMcp({
  channels: {
    enabled: true,
    defaultMeta: { server: 'my-app' },  // Optional
  },
})
```

| Option | Type | Default | Description |
| - | - | - | - |
| `enabled` | `boolean` | `false` | Enable the channel system |
| `defaultMeta` | `Record<string, string>` | — | Metadata appended to all channel notifications |

## Related

* [Channels Guide](/frontmcp/servers/channels) — full documentation with all source types
* [ChannelContext](/frontmcp/sdk-reference/contexts/channel-context) — context class reference
* [ChannelRegistry](/frontmcp/sdk-reference/registries/channel-registry) — registry API


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.