Skip to main content

SlackProvider

SlackProvider is the managed path for connecting agents to Slack. Register it on Mastra.channels and it provisions Slack apps via the Manifest API, runs the OAuth install flow, rotates configuration tokens, and routes Slack events to your agents. Use it when you want Mastra to own app creation and installation. For the lower-level path where you create the Slack app and configure scopes and webhooks yourself, use createSlackAdapter on the agent's channels.adapters instead.

Usage example
Direct link to Usage example

Register the provider on the Mastra constructor. The refresh token is single-use and rotates on startup; the resulting access tokens are persisted to Mastra.storage.

src/mastra/index.ts
import { Mastra } from '@mastra/core/mastra'
import { SlackProvider } from '@mastra/slack'

export const mastra = new Mastra({
storage,
channels: {
slack: new SlackProvider({
refreshToken: process.env.SLACK_APP_CONFIG_REFRESH_TOKEN,
baseUrl: process.env.MASTRA_BASE_URL,
}),
},
})

When credentials aren't available at construction time (for example, entered through the Editor UI or loaded from a vault), construct the provider without them and call configure() later:

src/mastra/index.ts
const slack = new SlackProvider()

await slack.configure({
refreshToken: process.env.SLACK_APP_CONFIG_REFRESH_TOKEN,
})

Constructor parameters
Direct link to Constructor parameters

SlackProviderConfig combines Slack-specific fields, Slack-adapter overrides (toolDisplay, streaming, typingStatus), and a curated subset of ChannelConfig options (such as handlers, inlineMedia, and state) forwarded to every connected agent. All fields are optional.

refreshToken?:

string
Slack App Configuration refresh token, used for automatic token rotation. Single-use; each rotation returns a new pair. Can also be provided later via `configure()`. If omitted, the provider starts unconfigured and cannot create apps until `configure()` is called or tokens are loaded from storage. Generate it under "Your App Configuration Tokens" at api.slack.com/apps.

token?:

string
Slack App Configuration access token for programmatic app creation. Optional, because the provider rotates to a fresh token on startup using `refreshToken`.

baseUrl?:

string
Public base URL for webhook and OAuth callbacks. Required when calling `connect()` to create apps. Can also be set via `setBaseUrl()` or auto-detected from the Mastra server config. For local development, use a tunnel such as `cloudflared`.

encryptionKey?:

string
Encryption key for sensitive stored data (client secret, signing secret, bot token). Use a 32+ character random string. Can be set via the `MASTRA_ENCRYPTION_KEY` env var. If omitted, secrets are stored in plaintext (not recommended for production).

storage?:

ChannelsStorage
Custom storage for installations. Defaults to Mastra's `ChannelsStorage` from the global storage. Throws if no persistent storage is available.

redirectPath?:

string
= "/"
Path to redirect to after OAuth completion.

onInstall?:

(installation: SlackInstallation) => Promise<void>
Called when a workspace successfully installs the app.

streaming?:

StreamingConfig | false
= true
Stream agent text deltas to Slack as they're generated. Pass `{ updateIntervalMs }` to customize the post-and-edit interval, or `false` to buffer text until step-finish. Disabling streaming restricts `toolDisplay` to static modes.

toolDisplay?:

ToolDisplay
= 'grouped'
How tool calls are rendered in Slack: `'cards'`, `'text'`, `'timeline'`, `'grouped'`, `'hidden'`, or a function. `'hidden'` suppresses tool call/result rendering entirely. `'timeline'` and `'grouped'` require streaming. With `streaming: false`, only static modes are available and the default is `'cards'`.

typingStatus?:

boolean | TypingStatusFn
= true
Show a typing indicator while the agent works. Set `false` to disable, or pass a function to return custom status text per stream chunk (return `undefined` to fall back to the default for that chunk).

waitUntil?:

WaitUntilFn
Returns a `waitUntil` for the current Slack webhook request. Required on serverless runtimes where Hono can't bridge the platform's `ExecutionContext` (Vercel, AWS Lambda). Without it, the invocation freezes after the 200 ack and kills the run mid-flight. Pass the bare `waitUntil(promise)` from your platform SDK (for example, `@vercel/functions`). Cloudflare Workers and Netlify users typically don't need this.

resolveWaitUntil?:

WaitUntilResolver
Resolve `waitUntil` from the request's Hono `Context` when the runtime exposes it through the request and core's default doesn't cover it. Resolution order: `waitUntil` → `resolveWaitUntil` → core default.

handlers?:

ChannelHandlers
Override built-in event handlers (`onDirectMessage`, `onMention`). Forwarded to `AgentChannels` for every agent connected via this provider.

inlineMedia?:

ChannelConfig['inlineMedia']
Which media types to send inline to the model.

threadContext?:

ChannelConfig['threadContext']
Fetch recent thread messages from Slack when the agent joins mid-conversation.

tools?:

ChannelConfig['tools']
Whether to include channel tools (`add_reaction`, `remove_reaction`).

state?:

ChannelConfig['state']
State adapter for message deduplication, locking, and subscriptions. Defaults to the `MastraStateAdapter` backed by the Mastra instance's configured storage, so subscriptions persist across restarts.

chatOptions?:

ChannelConfig['chatOptions']
Additional options passed directly to the Chat SDK.

logger?:

SlackAdapterConfig['logger']
Logger forwarded to the underlying `SlackAdapter`. Defaults to the adapter's `ConsoleLogger`.

Methods
Direct link to Methods

Agent connections
Direct link to Agent connections

connect(agentId, options?)
Direct link to connectagentid-options

Creates a new Slack app for the agent via the Manifest API and returns an OAuth result with the authorization URL to redirect the user to. Requires baseUrl to be set. If a pending installation already exists for the agent, returns its existing authorization URL instead of creating a duplicate app.

const result = await slack.connect('support-agent', {
name: 'Support Bot',
})

// Redirect the user to result.authorizationUrl to install the app

Returns: Promise<ChannelConnectResult>

interface ChannelConnectResult {
type: 'oauth'
installationId: string
authorizationUrl: string
}

SlackConnectOptions is serializable and can be stored for stored agents:

name?:

string
Display name for the Slack bot. Defaults to the agent name, then the agent ID.

description?:

string
Bot description shown in Slack. Defaults to "{name} - Powered by Mastra".

iconUrl?:

string
URL to a square image (min 512x512) for the app icon. Downloaded and uploaded to Slack automatically.

manifest?:

(defaults: SlackAppManifest) => SlackAppManifest
Customize the Slack app manifest before it is sent to the Manifest API. Receives the default manifest and returns the final one. Use it for custom scopes, additional events, or interactivity settings.

redirectUrl?:

string
URL to redirect to after successful OAuth completion. Defaults to the provider's `redirectPath` or `/`.

disconnect(agentId)
Direct link to disconnectagentid

Disconnects an agent from Slack by deleting its app and removing the installation from storage.

await slack.disconnect('support-agent')

Returns: Promise<void>

getInstallation(agentId)
Direct link to getinstallationagentid

Returns the Slack installation for an agent, or null if none exists.

const installation = await slack.getInstallation('support-agent')

Returns: Promise<SlackInstallation | null>

listInstallations()
Direct link to listinstallations

Lists all Slack installations (public info only), including active and pending.

const installations = await slack.listInstallations()

Returns: Promise<ChannelInstallationInfo[]>

Configuration
Direct link to Configuration

configure(credentials)
Direct link to configurecredentials

Provides or clears Slack App Configuration credentials at runtime. Use this when credentials aren't available at construction time. Pass null to clear credentials and delete stored tokens.

// Provide credentials (persists to storage immediately)
await slack.configure({ refreshToken: 'xoxe-1-...' })

// Clear credentials and stored tokens
await slack.configure(null)

Returns: Promise<void>

setBaseUrl(baseUrl)
Direct link to setbaseurlbaseurl

Sets the public base URL used for webhook and OAuth callbacks. Use this when the URL isn't known at construction time and can't be auto-detected from the server config.

slack.setBaseUrl('https://abc123.trycloudflare.com')

initialize()
Direct link to initialize

Recreates a SlackAdapter for each active installation in storage and injects AgentChannels into the corresponding agent so it receives Slack events on startup. Does not auto-provision new apps; use connect() to create one. Mastra calls this automatically, so you rarely call it directly.

await slack.initialize()

Returns: Promise<void>

Default manifest
Direct link to Default manifest

When connect() builds a Slack app, the generated manifest requests a default set of bot scopes and event subscriptions. Override them with the manifest option on connect().

Default bot scopesDefault bot events
chat:writeapp_mention
chat:write.publicmessage.channels
im:writemessage.groups
channels:historymessage.im
channels:readmessage.mpim
groups:history
groups:read
im:history
im:read
mpim:history
mpim:read
app_mentions:read
users:read
reactions:write
files:read
assistant:write

Accessing the provider
Direct link to Accessing the provider

Access the registered provider through the typed channels getter, keyed by the id you registered it under:

const result = await mastra.channels.slack.connect('support-agent')

When the key is only known at runtime, look it up by string id and pass the concrete type:

const slack = mastra.getChannelProvider<SlackProvider>('slack')
const result = await slack.connect('support-agent')

Storage requirement
Direct link to Storage requirement

SlackProvider requires persistent storage on Mastra to encrypt and persist installations and rotating configuration tokens. The constructor throws if no persistent storage is available and no custom storage is passed.