
Mastra Slack 渠道集成实战SlackProvider 如何接管 Slack App 创建、OAuth 安装与 Agent 消息路由【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra本文以 Mastra 仓库的 Slack 渠道包 channels/slack 为主体完整讲解mastra/slack的核心定位与配置方式它通过 Slack Manifest API 程序化创建 App、自动托管 OAuth 安装流程、校验 Webhook 签名并把 Slack 消息路由到已注册的 Mastra Agent。读完本文你将掌握SlackProvider的全部配置参数、connect()连接流程、默认 App Manifest 的 scopes 与事件订阅细节以及签名校验、令牌轮换、密钥加密等底层实现机制并能把 Slack 渠道安全地跑在本地开发和 Serverless 环境上。一、mastra/slack 是什么包 README 对它的定位是一句话mastra/slackconnects Mastra agents to Slack —— 创建并配置 Slack App通过 Manifest API、管理 OAuth 安装流程、把 Slack 会话路由给注册到 Mastra 的 Agent。从 package.json 可以确认几个工程事实包名mastra/slack当前版本 1.6.3Apache-2.0 许可运行环境要求 Node.js 22.13.0engines字段唯一运行时依赖是chat-adapter/slack^4.34.0消息收发、流式渲染等“适配器层”能力由它提供mastra/slack本身聚焦“管理面”App 生命周期、凭据、路由Peer 依赖mastra/core^1.0.0即它必须配合一个 Mastra 实例使用。入口文件 导出的公共 API 包括SlackProvider主入口、SlackManifestClientManifest API 客户端、verifySlackRequest/parseSlackFormBody签名与表单工具、buildManifest与DEFAULT_BOT_SCOPES/DEFAULT_BOT_EVENTSManifest 构建并为了方便再导出createSlackAdapter及相关 Zod 存储 Schema 与类型定义。在 Mastra 的渠道体系中它属于“托管路径”managed path你不需要自己到 Slack 后台建 App、配 scopes、填 Webhook URL与之对应的“低层路径”是直接使用createSlackAdapter并挂在 Agent 的channels.adapters上由你自己管理 App——参考文档在 slack-provider.mdx 中对两条路径做了区分。本文聚焦托管路径。二、安装与最小集成安装方式来自 channels/slack/README.mdnpm install mastra/slackREADME 给出的最小用法是设置 Slack App Configuration refresh token 环境变量构造SlackProvider并注册到Mastra的channels上import { Mastra } from mastra/core/mastra; import { SlackProvider } from mastra/slack; const slack new SlackProvider({ refreshToken: process.env.SLACK_APP_CONFIG_REFRESH_TOKEN, }); export const mastra new Mastra({ channels: { slack }, });结合官方参考文档一个更接近生产的写法会显式传入storage和baseUrlimport { 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, }), }, });两个关键前提源码可验证必须有持久化存储。SlackProvider启动时通过#resolveStorage()从 Mastra 实例取channels存储见 provider.ts取不到时会抛出明确错误“No storage available. SlackProvider requires persistent storage, configure a storage backend on your Mastra instance”。baseUrl 有自动推导逻辑。#getBaseUrl()的解析优先级是显式配置的baseUrl→ Mastra server 配置的studioProtocol/studioHost/studioPort回退host/port与环境变量MASTR A_HOST→ 默认http://localhost:4111port取process.env.PORT因为 CLI 会把实际解析出的端口写进去标准端口 80/443 会省略。本地开发时文档建议用隧道如cloudflared作为baseUrl因为 Slack 的回调要求公网可达。如果构造时拿不到凭据例如凭据由 UI 或 Vault 在运行时提供可以先构造再调用configure()const slack new SlackProvider(); // 提供凭据会立即持久化到存储 await slack.configure({ refreshToken: xoxe-1-... }); // 或清除凭据和已存储的令牌 await slack.configure(null);三、SlackProvider 配置项详解SlackProviderConfig是一个判别联合类型types.tsstreaming字段决定toolDisplay的合法取值。它由三层内容组成——Slack 特有字段、Slack 适配器覆盖项、以及转发给每个已连接 Agent 的ChannelConfig子集。所有字段均为可选。3.1 凭据与令牌配置项类型默认值说明refreshTokenstring无Slack App Configuration refresh token用于自动令牌轮换。单次使用每次轮换返回新的 access/refresh 令牌对可在构造时或后续configure()提供。省略时 provider 处于“未配置”状态不能创建 App直到configure()被调用或从存储加载令牌tokenstring无Slack App Configuration access token。可省略因为 provider 会在启动时用refreshToken轮换出新的Slack 的 App Configuration access token 有效期是 12 小时refresh token 是一次性的。SlackManifestClient 的rotateToken()调tooling.tokens.rotate完成轮换并用#rotationPromise对并发调用去重——避免多个请求同时消费同一个一次性 refresh token。轮换成功后通过onTokenRotation回调把新令牌对加密后写回存储因此refresh token 只保存在你的数据库里环境变量里的原始值用一次即失效这也是文档强调“结果访问令牌持久化到Mastra.storage”的原因。3.2 回调地址与 OAuth 行为配置项类型默认值说明baseUrlstring自动推导Webhook 与 OAuth 回调的公网基础 URL。调用connect()创建 App 时必须可解析出来否则抛出SlackProvider baseUrl not set错误也可用setBaseUrl()事后设置redirectPathstring/OAuth 完成后的重定向路径onInstall(installation: SlackInstallation) Promisevoid无某工作区成功安装 App 时的回调3.3 安全与存储配置项类型默认值说明encryptionKeystring无敏感数据clientSecret、signingSecret、botToken的加密密钥。建议 32 位随机字符串也可通过环境变量MASTRA_ENCRYPTION_KEY提供不设置则明文存储生产环境不推荐storageChannelsStorage取自 Mastra 全局存储自定义安装记录存储没有持久化存储时会抛错加密实现值得看一眼crypto.ts 使用AES-256-GCM HKDF-SHA256密钥派生info 为mastra-slack-encryption密文格式是aes-256-gcm-hkdf:base64(salt):base64(iv):base64(authTag):base64(ciphertext)每次加密随机生成 16 字节 salt 和 12 字节 IV。前缀设计是刻意为算法升级留的口子decrypt()按前缀分发未来新增算法只需加一个分支。3.4 消息渲染行为Slack 适配器覆盖项配置项类型默认值说明streamingStreamingConfig \| falsetrue将 Agent 文本增量流式写入 Slack传{ updateIntervalMs }可自定义“发布-编辑”间隔false时缓冲文本到step-finish且toolDisplay被限制为静态模式toolDisplayToolDisplay流式下grouped静态下cards工具调用的渲染方式cards每工具一张 Running→Result 的 Block Kit 卡片、text纯文本消息、timeline内联任务条目需流式、grouped收拢为单个 “Thinking Steps” 计划组件适合 Slack AI Assistant UI需流式、hidden静默执行、或函数textFormatmarkdown \| plainmarkdown最终回复的方言。markdown让 Slack 原生渲染加粗/链接/表格plain输出字面纯文本适合提示词里已让模型输出 Slack mrkdwn 的场景。作用于静态分支与流式回退原生流式恒为 markdowntypingStatusboolean \| TypingStatusFntrue“正在输入”指示与 Assistant 状态文案。默认文案形如is typing…、is calling {tool}…、is waiting for approval…传函数可逐 chunk 自定义返回false/null/undefined表示保持不变可用defaultTypingStatus兜底formatErrorChannelAdapterConfig[formatError]无自定义错误在 Slack 消息中的渲染loggerSlackAdapterConfig[logger]适配器的ConsoleLogger转发给底层SlackAdapter默认的streaming: true与toolDisplay: grouped是在 resolveSlackAdapterConfig() 中落地的源码注释解释这是 Slack 的“意见化默认值”Slack 支持原生消息流式、工具折叠成 “Thinking Steps” 组件在其 AI Assistant UI 中效果好但并非适合所有平台所以放在 provider 层而不是 core。该函数还处理了已废弃的adapterConfig字段顶层字段优先adapterConfig作为向后兼容的兜底合并undefined值会被过滤以免覆盖保留选项。3.5 转发给 AgentChannels 的选项以下字段从 provider 转发到每一个经此渠道连接的 Agent配置项说明handlers覆盖内置事件处理器如onDirectMessage、onMentioninlineMedia哪些媒体类型内联发给模型inlineLinks是否把消息文本中的 URL 提升为文件部件threadContextAgent 中途加入会话时是否拉取近期线程消息作为上下文tools是否让渠道暴露add_reaction/remove_reaction渠道工具它们不会自动加给 Agent需显式通过tools传入state状态适配器用于消息去重、加锁、订阅持久化chatOptions直接透传给 Chat SDK 的额外选项3.6 Serverless 运行时的 waitUntil在 Serverless 环境部署时有两个容易踩坑的配置配置项说明waitUntil直接传平台的裸waitUntil(promise)函数例如vercel/functions。在 Hono 无法自动桥接平台ExecutionContext的运行时Vercel、AWS Lambda上必需否则运行时会在返回 200 ack 后立即冻结调用把正在进行的 Agent 运行中途杀掉用户收不到 Slack 回复resolveWaitUntil从请求的 HonoContext解析waitUntil当运行时的waitUntil挂在请求对象上且 core 默认逻辑覆盖不到时使用。解析顺序waitUntil→resolveWaitUntil→ core 默认core 默认会读 Cloudflare Workers 的c.executionCtx.waitUntil与 Netlify 的c.env.context.waitUntil这个逻辑在 事件路由处理 中生效源码注释直言“没有 waitUntilServerless 调用会在返回 200 后冻结中途杀死 Agent 运行”。四、连接流程connect()、OAuth 与内置路由4.1 connect() APIconnect()是创建 Slack App 的入口两种签名见 provider.ts// 形式一按已注册的 agent id const result await slack.connect(my-agent, { name: My Bot, slashCommands: [/ask, /help], }); if (result.type oauth) { // 把用户重定向到 result.authorizationUrl } // 形式二任意连接 id如 AgentController此时 name 必填 await slack.connect({ id: my-controller, name: My Controller Bot });返回统一的ChannelConnectResultinterface ChannelConnectResult { type: oauth; installationId: string; authorizationUrl: string; }SlackConnectOptions可序列化可存入数据库供“存储型 Agent”使用选项说明nameSlack 机器人显示名默认为 agent 名再退化为 agent iddescriptionSlack 中展示的说明默认{name} - Powered by MastraiconUrl方形图片 URL最小 512x512自动下载并上传为 App 图标上传失败只告警不阻断创建slashCommands字符串数组如[/ask]或完整配置对象数组{ command, description?, usageHint?, prompt? }。prompt是提示词模板{{text}}占位符会被用户输入替换默认模板即{{text}}manifest(defaults: SlackAppManifest) SlackAppManifest在 Manifest 发给 Manifest API 前自定义它——加 scopes、订阅额外事件、调整 interactivity 设置都走这里redirectUrlOAuth 成功后的重定向 URL默认为 provider 的redirectPath或/Studio UI 通常用它回到 Agent 页面connect()的内部流程provider.ts可以概括为七步校验baseUrl可解析否则抛错查该 agent 是否已有安装记录pending状态则先探测 Slack 上 App 是否仍存在防止复用已被管理员删除的 App 的死链接存在则复用其authorizationUrl不重复建 Appactive状态则直接抛出 “already connected. Disconnect first to reconnect.”生成webhookIdUUID用 buildManifest() 构建 App Manifest其中 Webhook、OAuth 回调、命令 URL 都挂在这个webhookId上若传了manifest变换函数则先应用调client.createApp(manifest)走 Manifest API拿到appId、clientId、clientSecret、signingSecret若给了iconUrl则下载图片并调apps.icon.set上传非致命用 manifest 里的 bot scopes 拼出slack.com/oauth/v2/authorize授权 URL追加redirect_uri与stateinstallation id参数把 pending 安装记录含凭据加密后写入存储并把斜杠命令配置登记到内存 Map返回{ type: oauth, installationId, authorizationUrl }。4.2 内置 API 路由SlackProvider通过getRoutes()向 Mastra server 暴露一组 Hono 风格路由provider.ts每个 handler 首次被请求时会注入mastra实例并触发一次性的自动初始化路由方法认证职责/slack/oauth/callbackGET否OAuth 回调用state找到 pending 记录换 code 取access_token/bot_user_id/team落库为 active 安装激活适配器随后 302 回redirectUrl带channel_connectedtrue、platformslack、agent、team查询参数失败则带channel_error/slack/events/:webhookIdPOST否Slack 事件/交互载荷入口/slack/commands/:webhookIdPOST否斜杠命令入口/slack/connectPOST是供 UI 调用的 connect 端点/slack/disconnectPOST是供 UI 调用的 disconnect 端点/slack/installationsGET是列出全部安装仅公开信息4.3 其他生命周期方法disconnect(agentId)删除 Slack 端 Appapps.manifest.delete、移除内存适配器与斜杠命令、删除存储中的安装记录getInstallation(agentId)返回解密后的SlackInstallation不存在则nulllistInstallations()列出 active 与 pending 安装仅公开字段initialize()从存储恢复所有 active 安装逐个创建SlackAdapter并注入AgentChannels/AgentControllerChannels不会自动创建新 App创建用connect()。Mastra 会自动调用它一般无需手动触发setBaseUrl(baseUrl)/configure(credentials | null)/getInfo()/isConfigured()基础 URL 与凭据管理、UI 发现元数据。在代码中访问已注册的 provider// 类型化访问 const result await mastra.channels.slack.connect(support-agent); // key 只在运行时可知时按字符串 id 取 const slack mastra.getChannelProviderSlackProvider(slack); const result await slack.connect(support-agent);五、默认 App Manifestscopes 与事件订阅connect()生成的 Manifest 由 manifest.ts 中的buildManifest()构建。默认 bot scopesDEFAULT_BOT_SCOPES默认 bot scopes默认 bot 事件chat:writeapp_mentionchat:write.publicmessage.channelsim:writemessage.groupschannels:historymessage.imchannels:readmessage.mpimgroups:historygroups:readim:historyim:readmpim:historympim:readapp_mentions:readusers:readreactions:writefiles:readassistant:write两个实现细节值得注意配置了斜杠命令才会追加commandsscopemanifest.ts不配置就不多要权限assistant:write是 Slack 的 Assistant 模式 scope会让 App 出现在 AI Assistant 选择器中并开启 DM 的线程上下文——所以 manifest 里同时带了assistant_view与app_home.messages_tab_enabled: truedescription 超过 139 字符会被截断Slack 文档说 140但 API 在 140 长度处会拒绝short_desc源码里专门注释了这一点。Manifest 还会固定oauth_config.redirect_urls指向/slack/oauth/callback事件订阅与 interactivity 的request_url均指向/slack/events/:webhookId且socket_mode_enabled: false纯 HTTP 回调不走 Socket Mode。要加自定义 scope 或事件用connect()的manifest变换函数manifest: (m) ({ ...m, oauth_config: { ...m.oauth_config, scopes: { bot: [...(m.oauth_config?.scopes?.bot ?? []), files:write] }, }, })启动时 provider 还会做配置漂移检测checkConfigDrift对名字、描述、斜杠命令、baseUrl 算 SHA-256 短哈希取前 16 位十六进制与安装记录里存的configHash不一致就自动updateApp同步 Manifest 并把新哈希写回如果 Slack 返回app_not_foundApp 在后台被删了则清理本地陈旧安装记录。六、Webhook 处理签名校验、事件路由与斜杠命令6.1 签名校验/slack/events/:webhookId与/slack/commands/:webhookId两个入口都做同一套校验crypto.ts 的verifySlackRequest读取x-slack-request-timestamp与x-slack-signature头缺失返回 401时间戳与当前时间差超过 **300 秒5 分钟防重放窗口**直接判无效计算v0:timestamp:原始 body的 HMAC-SHA256以该安装的signingSecret为密钥得到期望签名v0...用timingSafeEqual做时序安全比较校验通过后JSON 载荷先识别url_verification挑战并原样回challengeSlack 首次配置事件订阅时的握手其余载荷原样重建Request委托给AgentChannels.handleWebhookEvent(slack, ...)——适配器内部按 content-type 自己区分事件、交互载荷与斜杠命令。6.2 斜杠命令的执行模型斜杠命令路由provider.ts实现了一个“快应答 后台执行”的模式直接对应 Slack 的 3 秒响应限制按webhookId查安装、验签解析表单体中的command、text、response_url从该安装登记的命令列表里匹配命令配置未知命令返回 ephemeral 提示Unknown command: /xxx把commandConfig.prompt中的{{text}}全部替换为用户输入得到最终提示词立即返回{ response_type: ephemeral, text: Processing... }作为 ack后台执行agent.generate(prompt)完成后通过response_urlPOST 一条in_channel消息失败时回Error: message用waitUntil把后台任务挂到当前调用上防止 Serverless 实例在 ack 后被冻结。从源码结构看还有两个边界约束斜杠命令只支持单次agent.generate()不进入线程会话agentController类型的安装不支持斜杠命令Slack 斜杠载荷不带thread_ts无法映射到某个线程会话会提示用户在线程里 机器人来开会话。6.3 事件进入 Agent 的路径#handleEvent验签后调用#resolveChannelsForInstallation()解析该安装对应的渠道实例ownerType agentController时构造/复用AgentControllerChannels否则是AgentChannels。创建渠道实例时会合并而非覆盖Agent 上已有的 channels 配置例如作者直接在 agent 上配了别的适配器时Slack 会叠加进去然后调用initialize(mastra)完成注册。这样 Slack 的 DM、提及、频道消息最终都以统一的渠道抽象进入对应 Agent 的会话。七、适用前提与限制小结结合源码与参考文档使用mastra/slack时需要注意Node.js 22.13.0且 Mastra 实例必须配置持久化存储如 LibSQL/Postgres 等否则渠道初始化会失败refreshToken在 api.slack.com/apps 的 “Your App Configuration Tokens” 处生成单次使用轮换后的新令牌对会加密写入你的存储丢了存储等于丢了凭据需重新生成connect()要求baseUrl可解析显式配置、server 配置自动推导或setBaseUrl()本地开发建议走隧道生产环境建议设置encryptionKey32 位随机串或MASTRA_ENCRYPTION_KEY环境变量否则clientSecret、signingSecret、botToken以明文落库部署在 Vercel、AWS Lambda 等 Hono 无法桥接ExecutionContext的运行时上时需传waitUntilCloudflare Workers / Netlify 通常不需要该 provider 面向“Mastra 托管 App 生命周期”的场景如果你要自己控制 App 的创建与配置应走createSlackAdapterchannels.adapters的低层路径。八、延伸阅读包 README 与变更历史channels/slack/README.md、channels/slack/CHANGELOG.md核心实现SlackProvider、Manifest 构建与默认 scopes、Manifest API 客户端与令牌轮换、签名校验与 AES-256-GCM 加密、配置类型定义单元测试provider.test.ts、client.test.ts、crypto.test.ts、manifest.test.ts参考文档SlackProvider 参考、ChannelProvider 接口【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考