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.
Build a CI/CD alert channel that forwards deploy events into Claude Code, then upgrade it to a two-way service connector with replay support. By the end, you’ll understand how channels work end-to-end.
Prerequisites : A FrontMCP project initialized (see Installation ). Channels require @frontmcp/sdk >= 1.0.0.
What You’ll Build
A webhook channel that receives deploy events and pushes them to Claude Code
Upgrade to a two-way channel where Claude can reply
Add a service connector with outbound tools
Add replay buffering for offline sessions
Step 1: Create the Channel
Create src/apps/devops/channels/deploy.channel.ts:
import { Channel , ChannelContext } from ' @frontmcp/sdk ' ;
import type { ChannelNotification } from ' @frontmcp/sdk ' ;
@ Channel ({
name : ' deploy-alerts ' ,
description : ' CI/CD deployment status notifications ' ,
source : { type : ' webhook ' , path : ' /hooks/deploy ' },
meta : { team : ' platform ' },
})
export class DeployChannel extends ChannelContext {
async onEvent ( payload : unknown ): Promise < ChannelNotification > {
const { body } = payload as { body : { status : string ; version : string ; env : string } };
return {
content : ` Deploy ${ body . status } : ${ body . version } to ${ body . env } ` ,
meta : { status : body . status , version : body . version , env : body . env },
};
}
}
Key concepts:
Part Purpose @Channel()Declares metadata — name, source, static meta ChannelContextBase class providing logger, DI, and lifecycle hooks onEvent()Inbound handler — receives external events, returns a notification for Claudesource: { type: 'webhook', path: '...' }Registers an HTTP POST endpoint metaStatic key-value pairs added to every notification
Step 2: Register in an App
Create src/apps/devops/index.ts:
import { App } from ' @frontmcp/sdk ' ;
import { DeployChannel } from ' ./channels/deploy.channel ' ;
@ App ({
name : ' DevOps ' ,
description : ' CI/CD and deployment monitoring ' ,
channels : [ DeployChannel ],
})
export class DevOpsApp {}
Step 3: Enable Channels in Server
Update src/main.ts:
import { FrontMcp } from ' @frontmcp/sdk ' ;
import { DevOpsApp } from ' ./apps/devops ' ;
@ FrontMcp ({
info : { name : ' my-server ' , version : ' 1.0.0 ' },
apps : [ DevOpsApp ],
channels : { enabled : true },
})
export default class Server {}
Channels must be explicitly enabled with channels: { enabled: true }. Without this, channel declarations are ignored.
Step 4: Test It
Write an E2E test using createDirect():
import { FrontMcpInstance , DirectMcpServer } from ' @frontmcp/sdk ' ;
describe ( ' Deploy Channel ' , () => {
let server : DirectMcpServer ;
beforeEach ( async () => {
server = await FrontMcpInstance . createDirect ({
info : { name : ' test ' , version : ' 0.0.1 ' },
apps : [ DevOpsApp ],
auth : { mode : ' public ' },
channels : { enabled : true },
});
});
afterEach ( async () => {
await server . dispose ();
});
it ( ' should register the channel ' , async () => {
const tools = await server . listTools ();
// No tools from this channel (it's one-way, no reply tool needed)
expect ( tools ). toBeDefined ();
});
});
When Claude Code connects to this server, it will see events as:
< channel source = " deploy-alerts " team = " platform " status = " success " version = " 1.2.3 " env = " production " >
Deploy success: 1.2.3 to production
</ channel >
Step 5: Add Two-Way Support
Make it so Claude can reply to deploy events (e.g., to trigger a rollback):
@ Channel ({
name : ' deploy-alerts ' ,
description : ' CI/CD notifications. Reply to trigger actions. ' ,
source : { type : ' webhook ' , path : ' /hooks/deploy ' },
twoWay : true , // Enables the channel-reply tool
meta : { team : ' platform ' },
})
export class DeployChannel extends ChannelContext {
async onEvent ( payload : unknown ): Promise < ChannelNotification > {
// ... same as before
}
async onReply ( reply : string , meta ?: Record < string , string >): Promise < void > {
// Claude replied — forward to Slack, trigger rollback, etc.
console . log ( ` Claude says: ${ reply } ` );
if ( reply . toLowerCase (). includes ( ' rollback ' )) {
await triggerRollback ( meta ?. version );
}
}
}
Setting twoWay: true auto-registers a channel-reply tool. Claude can now call:
channel-reply({ channel_name: "deploy-alerts", text: "Rollback to v1.2.2", meta: { version: "1.2.2" } })
Step 6: Upgrade to Service Connector
For full bidirectional messaging (like WhatsApp), use a service connector with contributed tools:
import { Tool , ToolContext } from ' @frontmcp/sdk ' ;
import { z } from ' @frontmcp/sdk ' ;
// Outbound tool — Claude calls this to send messages
@ Tool ({
name : ' send-deploy-command ' ,
description : ' Send a deploy command to the CD system ' ,
inputSchema : {
env : z . enum ([ ' staging ' , ' production ' ]),
version : z . string (),
},
})
class SendDeployCommand extends ToolContext {
async execute ( input : { env : string ; version : string }) {
// Call CD API to trigger deploy
return { triggered : true , env : input . env , version : input . version };
}
}
// Upgrade the channel to service connector
@ Channel ({
name : ' deploy-service ' ,
description : ' Bidirectional deploy service. Send commands and receive status. ' ,
source : { type : ' service ' , service : ' deploy-pipeline ' },
tools : [ SendDeployCommand ], // Auto-registered in tool list
twoWay : true ,
})
export class DeployServiceChannel extends ChannelContext {
async onConnect (): Promise < void > {
// Start listening to deploy pipeline events
this . logger . info ( ' Connected to deploy pipeline ' );
}
async onEvent ( payload : unknown ): Promise < ChannelNotification > {
const event = payload as { status : string ; version : string };
return { content : ` Deploy ${ event . status } : ${ event . version } ` };
}
}
Step 7: Add Replay Buffer
Events that arrive while Claude is offline can be buffered and replayed:
@ Channel ({
name : ' deploy-alerts ' ,
source : { type : ' webhook ' , path : ' /hooks/deploy ' },
replay : {
enabled : true ,
maxEvents : 50 , // Ring buffer, oldest evicted
},
})
export class DeployChannel extends ChannelContext {
async onEvent ( payload : unknown ): Promise < ChannelNotification > {
// ... same as before
}
}
When a new Claude Code session connects, buffered events can be replayed. Replayed events include replayed: "true" in their meta so Claude can distinguish them from live events.
Next Steps
Channels Reference Full channels documentation with all 7 source types
@Channel API Complete decorator and configuration reference