Slack Team Bot with MCP Tools
This playbook builds a shared Slack bot that answers when mentioned in allow-listed channels, calls a custom team MCP tool plus Read/Grep, and can post proactively with SlackSendMessage.
Who this is for
Section titled “Who this is for”A DevOps engineer running a shared team bot.
A Slack Socket Mode bot, mention-triggered in allowed channels, with a custom MCP tool plus Read/Grep and the SlackSendMessage tool for proactive posts.
Features used
Section titled “Features used”slack.socket-mode— Slack channelruntime.per-trigger-model— Slack runtime controlschannel.final-only-delivery— Delivery and send toolstool-policy.allowlist— Tool policytool-policy.mcp-servers— MCP serversagent-app.adapter-send-tools— Delivery and send toolsruntime.concurrency— Sessions, concurrency & Pi-native tuning
Configuration
Section titled “Configuration”The Slack section runs in Socket Mode (effective botToken and appToken values are required); Slack’s app_mention event handles real mentions, the adapter discovers its own bot user ID/username, and the bot only responds in allowedChannelIds. Put MONO_AGENT_SLACK_BOT_TOKEN and MONO_AGENT_SLACK_APP_TOKEN in .env; the source config omits credentials. The built-in @agent /model / @agent /effort thread controls and workspace-registered /<bot>-model / /<bot>-effort channel controls automatically expose runtime.model plus any configured fallbacks, with no bot-ID or Slack-specific model config. This agent opts into a specific tool allowlist instead of the allow-all default, so the built-ins it uses and SlackSendMessage are named explicitly; deployTool comes from the declared MCP server. concurrency bounds in-flight work app-wide.
{ "runtime": { "model": "anthropic:claude-sonnet-4-6" }, "slack": { "enabled": true, "allowedChannelIds": ["C012345"] }, "tools": { "allowedTools": ["Read", "Grep", "SlackSendMessage", "deployTool"], "mcpConfigPath": "./mcp.json" }, "concurrency": { "maxConcurrentRuns": 4, "maxPendingRuns": 8 }}Secrets can also come from the environment: MONO_AGENT_SLACK_BOT_TOKEN and MONO_AGENT_SLACK_APP_TOKEN. The unset mention-text policy keeps one authenticated readable @name marker in the current turn; set slack.stripMentionText: true only when legacy full stripping is required.
- Create a Slack app with Socket Mode (app token
connections:write), a bot token (chat:writepluscommandsfor slash controls,users:readso the agent can address teammates by name, andchannels:history/groups:historyso a mention inside a thread arrives with that thread behind it), and Interactivity & Shortcuts enabled so runtime selectors can deliverblock_actionsover Socket Mode. Register/<bot-username>-modeland/<bot-username>-effort; Socket Mode needs no Request URL. mono-agent init --model anthropic:claude-sonnet-4-6- Write
mcp.jsonwith the team’s stdio MCP server;deployToolbecomes available from the server declaration (MCP tools aren’t gated bytools.allowedTools). This playbook keeps a specific allowlist, so it listsdeployToolfor readability, but the entry is not what enables it. - Set a specific
tools.allowedTools(the built-ins you want plusSlackSendMessage) and add theslacksection; set concurrency bounds (note: per-channel scope). Or droptools.allowedToolsentirely to keep the allow-all default. mono-agent validate, thenmono-agent start(confirm Slack is running with both tokens).- Mention the bot in an allowed channel and confirm a 👀 reaction, then a final reply. If a tool runs, confirm the final reply is a new message and the temporary activity message is removed.
Smoke test
Section titled “Smoke test”Related
Section titled “Related”- Slack channel
- Delivery and send tools
- Tool policy
- MCP servers
- Sessions, concurrency & Pi-native tuning
- Composer skill
For real-turn cache measurements and tool-definition changes, enable
providers.piNative.promptCacheDiagnostics and use the offline
prompt-cache artifact reader.