> For the complete documentation index, see [llms.txt](https://docs.flowcp.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.flowcp.ai/guides/distribute-via-chat-bot.md).

# Distribute as a chat bot

The **chat bot** channel runs a hosted AI bot in your team's chat platform that answers in-thread using your published MCP server's tools. People **@mention** the bot in a channel (or DM it); FlowCP runs the same agentic loop as the [Playground](/guides/chat-test-your-mcp-server.md) and [chat widget](/guides/embed-ai-chat-widget.md) and posts the reply back into the thread.

> **Premium feature.** Chat bots require a **Team** plan or higher (the `chat_bot` capability). The **Distribute → Chat bot** entry is hidden on plans that don't include it.

## How it works

FlowCP runs a **hosted bot gateway** that holds your bot's connection to the chat platform — Slack and Discord over persistent sockets, Telegram by long-polling, and WhatsApp via an inbound webhook. You never run any server yourself. When a message arrives, the gateway runs your server's tools in an agentic loop and replies in the same thread. Conversation context is kept per-thread for follow-ups.

## What you need

1. A **published** server (the bot connects to its enabled tools).
2. An **OpenRouter API key** for the bot. Each bot has its **own** key — create one at [openrouter.ai/keys](https://openrouter.ai/keys).
3. Credentials for your chat platform (below).

## Create a bot

1. Open your app and go to **Distribute → Chat bot**. The page targets the branch selected in the header.
2. Under **Add a bot**, choose a **platform** and click **Create bot**.
3. Enter the platform **credentials** and click **Save credentials**, then **Test connection** to confirm they work.
4. Set the bot's **OpenRouter API key** (required — the bot can't reply without it).
5. Optionally set the **model**, a **system prompt**, and attach extra **connectors** (additional MCP servers whose tools the bot can also use).
6. Flip **Enabled** on. The gateway picks the bot up within moments (no restart), and the status badge turns **active**.

## Platform setup

### Slack

Create a Slack app, enable **Socket Mode**, and copy the **Bot User OAuth Token** (`xoxb-…`) and an **App-Level Token** (`xapp-…`) with the `connections:write` scope. Subscribe to the `app_mention` and `message.im` events. No public URL is required.

### Discord

Create a Discord application + bot, enable the **Message Content** intent, and copy the **Bot Token**. Invite the bot to your server. No public URL is required.

### Telegram

Create a bot with [@BotFather](https://t.me/BotFather) and copy the **Bot Token**. The gateway uses long-polling, so no public URL is required. In groups, the bot only replies when mentioned; in private chats it always replies.

### WhatsApp

Use the WhatsApp **Cloud API**. Provide the **Access Token**, **Phone Number ID**, a **Webhook Verify Token** (any string you choose), and the **App Secret**. Point your Meta app's webhook at `https://<gateway-host>/webhooks/whatsapp/<botId>` and use the same verify token. Inbound payloads are validated with an HMAC signature.

## Identity: per-user sign-in

* Servers using **shared-credential** auth (API key, bearer, or none) work directly — every user shares the configured credential.
* A server that uses **user OAuth** runs in **each chat user's own account**. The first time a user invokes one of its tools, the bot sends them a sign-in link **privately** (a DM, or an ephemeral message only they can see) — never in the shared channel, since the link is tied to their identity. Once they complete OAuth, the bot stores their token (encrypted) and acts as them. Per-user authorization is enforced. Until a user connects, that tool is **skipped** for them (the bot never calls it anonymously or as someone else).
* **Expiring sign-ins refresh automatically.** When a stored token nears expiry (or an upstream call comes back unauthorized mid-conversation), the bot refreshes it in the background and retries — users are **not** re-prompted. A fresh sign-in link is only sent when refresh is impossible: the provider revoked access, issued no refresh token, or definitively rejected the stored grant.
* **Remote (catalog) OAuth connectors** can run per-user too. On the bot's connector list, flip **"Each user connects their own account"** on a remote OAuth connector and each chat user is sent their own sign-in for that service (driven against the remote server's own authorization server), instead of everyone sharing the bot's upstream token. This requires the remote server to support standard OAuth discovery with dynamic client registration (or a pre-registered catalog client). The optional **shared upstream token** in bot settings applies only to remote OAuth connectors left in shared mode; platform user-OAuth servers always use per-user sign-in.

## Approving destructive actions

When the assistant wants to run a **destructive or confirmation-gated** tool, the bot pauses and posts **Approve / Reject** buttons in the thread — one pair per pending action, showing the tool name, the connector, and the arguments. The action only runs after you tap **Approve**; **Reject** declines it. Only the user who asked for the action can approve or reject it — clicks from anyone else in the thread are ignored, since the action runs in the requester's own account. Once every pending action in the batch is decided, the bot resumes and replies. This works in Slack, Discord, Telegram, and WhatsApp. Approval requests expire after 30 minutes; if one lapses, just ask again.
