|
| 1 | +# @mastra/slack |
| 2 | + |
| 3 | +Slack integration for Mastra agents. Handles app creation, OAuth, slash commands, and messaging. |
| 4 | + |
| 5 | +## Quick Start |
| 6 | + |
| 7 | +```ts |
| 8 | +import { Mastra } from '@mastra/core/mastra'; |
| 9 | +import { Agent } from '@mastra/core/agent'; |
| 10 | +import { SlackProvider } from '@mastra/slack'; |
| 11 | + |
| 12 | +const myAgent = new Agent({ |
| 13 | + id: 'my-agent', |
| 14 | + name: 'My Agent', |
| 15 | + model: 'openai/gpt-4.1', |
| 16 | + instructions: 'You are a helpful assistant.', |
| 17 | +}); |
| 18 | + |
| 19 | +const slack = new SlackProvider({ |
| 20 | + refreshToken: process.env.SLACK_APP_CONFIG_REFRESH_TOKEN, |
| 21 | + // For local dev, set SLACK_BASE_URL to your tunnel URL |
| 22 | + // In production, this is auto-derived from server config |
| 23 | + baseUrl: process.env.SLACK_BASE_URL, |
| 24 | +}); |
| 25 | + |
| 26 | +const mastra = new Mastra({ |
| 27 | + agents: { myAgent }, |
| 28 | + channels: { slack }, |
| 29 | +}); |
| 30 | + |
| 31 | +// Or configure credentials later (e.g., from UI or vault) |
| 32 | +// slack.configure({ refreshToken: 'xoxe-1-...' }); |
| 33 | + |
| 34 | +// Connect an agent to Slack (creates app, returns OAuth URL) |
| 35 | +const { authorizationUrl } = await slack.connect('my-agent', { |
| 36 | + name: 'My Bot', |
| 37 | + description: 'An AI assistant', |
| 38 | + iconUrl: 'https://example.com/my-bot-icon.png', |
| 39 | + slashCommands: [ |
| 40 | + { command: '/ask', prompt: 'Answer: {{text}}' }, |
| 41 | + { command: '/help', prompt: 'List your capabilities.' }, |
| 42 | + ], |
| 43 | +}); |
| 44 | +``` |
| 45 | + |
| 46 | +## Setup |
| 47 | + |
| 48 | +1. **Get App Configuration Tokens** from https://api.slack.com/apps (look for "Your App Configuration Tokens" section) |
| 49 | + |
| 50 | +2. **Set up a tunnel** for local development: |
| 51 | + |
| 52 | + ```bash |
| 53 | + cloudflared tunnel --url http://localhost:4111 |
| 54 | + ``` |
| 55 | + |
| 56 | +3. **Add to .env**: |
| 57 | + ``` |
| 58 | + SLACK_APP_CONFIG_TOKEN=xoxe.xoxp-... |
| 59 | + SLACK_APP_CONFIG_REFRESH_TOKEN=xoxe-1-... |
| 60 | + SLACK_BASE_URL=https://abc123.trycloudflare.com |
| 61 | + ``` |
| 62 | + |
| 63 | +> ⚠️ **Token Rotation**: Slack config access tokens expire after 12 hours, but the refresh token does not expire (it's single-use — each rotation returns a new pair). Tokens auto-rotate and are persisted to storage, so the `.env` values are only used as the initial seed. If you lose your persisted storage (e.g., DB wipe), you'll need fresh tokens from the Slack dashboard. |
| 64 | +
|
| 65 | +## Storage & Persistence |
| 66 | + |
| 67 | +`SlackProvider` automatically uses Mastra's storage if configured. Just add `storage` to your Mastra config: |
| 68 | + |
| 69 | +```ts |
| 70 | +import { LibSQLStore } from '@mastra/libsql'; |
| 71 | + |
| 72 | +const mastra = new Mastra({ |
| 73 | + agents: { myAgent }, |
| 74 | + storage: new LibSQLStore({ url: 'file:./mastra.db' }), |
| 75 | + channels: { |
| 76 | + slack: new SlackProvider({ |
| 77 | + refreshToken: process.env.SLACK_APP_CONFIG_REFRESH_TOKEN!, |
| 78 | + }), |
| 79 | + }, |
| 80 | +}); |
| 81 | +``` |
| 82 | + |
| 83 | +When Mastra has storage configured, `SlackProvider` automatically: |
| 84 | + |
| 85 | +- Persists rotated config tokens (so you don't need fresh tokens after restart) |
| 86 | +- Persists Slack app installations |
| 87 | +- Detects config changes (e.g., agent renames) and updates manifests on startup |
| 88 | + |
| 89 | +Without storage, data is lost on restart and apps are recreated. |
| 90 | + |
| 91 | +## How It Works |
| 92 | + |
| 93 | +1. Register a `SlackProvider` on your `Mastra` instance |
| 94 | +2. Call `slack.connect(agentId)` to provision a Slack app and get an OAuth URL |
| 95 | +3. Visit the OAuth URL to install the app to your Slack workspace |
| 96 | +4. After installation, messages and slash commands route to your agent |
| 97 | +5. Config access tokens auto-rotate (they expire every 12 hours) and are saved to storage |
| 98 | + |
| 99 | +## Slash Commands |
| 100 | + |
| 101 | +Commands use prompt templates with variable substitution: |
| 102 | + |
| 103 | +```ts |
| 104 | +await slack.connect('my-agent', { |
| 105 | + slashCommands: [ |
| 106 | + { |
| 107 | + command: '/ask', |
| 108 | + description: 'Ask the AI a question', |
| 109 | + prompt: 'Answer this question: {{text}}', |
| 110 | + }, |
| 111 | + { |
| 112 | + command: '/summarize', |
| 113 | + description: 'Summarize content', |
| 114 | + prompt: 'Summarize the following in 2-3 sentences: {{text}}', |
| 115 | + }, |
| 116 | + ], |
| 117 | +}); |
| 118 | +``` |
| 119 | + |
| 120 | +Available variables: `{{text}}`, `{{userId}}`, `{{channelId}}`, `{{teamId}}` |
| 121 | + |
| 122 | +## App Icons |
| 123 | + |
| 124 | +Each agent's Slack app can have its own icon: |
| 125 | + |
| 126 | +```ts |
| 127 | +await slack.connect('my-agent', { |
| 128 | + iconUrl: 'https://example.com/my-bot-avatar.png', |
| 129 | +}); |
| 130 | +``` |
| 131 | + |
| 132 | +The image should be: |
| 133 | + |
| 134 | +- Square (1:1 aspect ratio) |
| 135 | +- At least 512x512 pixels |
| 136 | +- PNG, JPG, or GIF format |
| 137 | + |
| 138 | +The icon is uploaded automatically when the Slack app is created. |
| 139 | + |
| 140 | +## Disconnecting |
| 141 | + |
| 142 | +```ts |
| 143 | +await slack.disconnect('my-agent'); |
| 144 | +``` |
| 145 | + |
| 146 | +This deletes the Slack app and removes the local installation record. |
0 commit comments