Slack MCP Server: Read Access for Agents, Not a Voice
What a Slack MCP server actually gives an agent, the official Slack-hosted option versus the self-hosted korotovsky server, how to wire either into Claude Code or Hermes Agent, and why posting should stay off by default.
The useful Slack agent reads. It pulls a channel’s history, searches for a decision someone made three weeks ago, and tells you what it found. It does not post. Posting is a privilege you hand out on purpose, not a default you forgot to turn off.
That is the whole thesis of this page. Everything below is how to get a Slack MCP server into an agent, verified against Slack’s own developer docs, the two server options worth using, and Anthropic’s current Claude Code docs, checked today.
Which Slack MCP server should you use?
Two options cover almost every case. Slack itself hosts one, and the community runs one.
Slack’s own server lives at mcp.slack.com/mcp, reachable over Streamable HTTP only, no SSE, no Dynamic Client Registration. It authenticates with user-token OAuth 2.0 behind a confidential client, which means your request has to come from a registered Slack app with a fixed app ID, and only a Marketplace-listed or internal app may use it. The agent that connects through it operates under the OAuth grant of whoever authorized it: it reads what that person can read, nothing more.
korotovsky/slack-mcp-server is the self-hosted alternative, MIT-licensed. It supports three authentication modes (more on that below), stdio, SSE and HTTP transports, and it ships read-only by default: every write tool is disabled until you explicitly turn it on.
Slack MCP server, October 2026
| Official (mcp.slack.com) | korotovsky/slack-mcp-server | |
|---|---|---|
| Hosting | Remote, hosted by Slack | Self-hosted: npx, Docker, or a DXT extension |
| Transport | Streamable HTTP only | Stdio, SSE, or HTTP |
| Auth | User-token OAuth 2.0, confidential client, admin-approved | User (xoxp), bot (xoxb), or browser session (xoxc/xoxd) |
| Default write access | Whatever OAuth scopes you request | Off. Posting and reactions need their own env var |
| Fits | A company that wants admin approval and an audit trail | A developer wiring Slack into Claude Code or Hermes today |
Auth: what each token actually grants
Slack’s official server needs your app’s client_id and client_secret for a confidential OAuth flow, and it requests scopes per tool: channels:history to read a channel, chat:write to post, search:read.public plus three more search:read.* scopes to search across visibility levels. Request only what the agent needs to read.
Read-only scopes worth requesting
- Required:channels:history, groups:history, im:history, mpim:historyRead messages in public channels, private channels, DMs and group DMs.
- Required:channels:read, groups:read, im:read, mpim:readList conversations and their metadata without reading content.
- Required:search:read.public, search:read.private, search:read.mpim, search:read.imSearch across the visibility levels you actually need, not the full set by default.
- Required:users:readResolve user IDs to names, needed for almost any useful summary.
korotovsky’s server takes a token through an environment variable instead of a full OAuth dance: SLACK_MCP_XOXP_TOKEN for a user token, SLACK_MCP_XOXB_TOKEN for a bot token, or both SLACK_MCP_XOXC_TOKEN and SLACK_MCP_XOXD_TOKEN for a browser-session pair pulled from your own logged-in Slack tab. A bot token is the most contained option: it only sees channels it has been invited to and cannot call search.messages at all, so conversations_search_messages never registers. Whichever token you use, the server’s own defaults already match the thesis here: write tools (conversations_add_message, reactions_add, reactions_remove, attachment_get_data) are not registered unless you set their specific environment variable or list them explicitly in SLACK_MCP_ENABLED_TOOLS. Read-only is not a setting you choose. It is what you get until you choose otherwise.
Slack MCP in Claude Code: the claude mcp add syntax
Claude Code’s current docs give two paths, and which one you use depends on which server you picked.
For the official hosted server, add it as an HTTP server, then open /mcp inside a Claude Code session, select slack and authenticate:
Official Slack MCP server in Claude Code
claude mcp add --transport http slack https://mcp.slack.com/mcp
To pin the scopes Claude Code requests instead of accepting whatever the server offers, set oauth.scopes on the entry. Anthropic’s own docs use this exact server as the worked example:
{
"mcpServers": {
"slack": {
"type": "http",
"url": "https://mcp.slack.com/mcp",
"oauth": {
"scopes": "channels:history channels:read search:read.public users:read"
}
}
}
}
For korotovsky’s server, add it as a local stdio process with the token as an environment variable:
Community Slack MCP server in Claude Code
claude mcp add --env SLACK_MCP_XOXB_TOKEN=xoxb-your-token -- npx -y slack-mcp-server@latest --transport stdio
The -- separator matters here: everything after it is the command Claude Code runs to start the server, untouched. Without it, Claude Code tries to parse --transport as its own flag instead of the server’s.
Wiring it into Hermes Agent: mcp_servers, not a plugin
Hermes Agent takes the same server through its own mcp_servers block, covered in full in Hermes Agent and MCP. The stdio shape for korotovsky’s server:
mcp_servers:
slack:
command: "npx"
args: ["-y", "slack-mcp-server@latest", "--transport", "stdio"]
env:
SLACK_MCP_XOXB_TOKEN: "${env:SLACK_MCP_XOXB_TOKEN}"
tools:
include:
[
conversations_history,
conversations_replies,
conversations_search_messages,
channels_list,
users_search,
]
tools.include is doing the real work in that entry. It is a second, config-level lock on top of the server’s own read-only default: even if a future version of the server changes its defaults, this agent only ever sees the five tools named here.
Slack as a gateway versus Slack as an MCP source
These are two different wires, and they are easy to conflate. Hermes ships both.
Slack as a gateway
- 01Slack talks to Hermes: slash commands, threads, mentions
- 02Needs a bot token (xoxb) and an app-level token (xapp) over Socket Mode
- 03Lives in Hermes' slack platform plugin, one setup per workspace
- 04Hermes is the one posting, with approval blocks on risky actions
Slack as an MCP source
- 01Hermes reads Slack's history as data, nothing talks back by default
- 02Needs whatever token the MCP server wants: bot, user, or OAuth
- 03Configured per entry under mcp_servers, like any other MCP server
- 04Posting through this path is off until you explicitly enable it
A workspace can run both at once: a bot that answers questions when mentioned, and a separate cron-driven agent that only ever reads. Keep them on different tokens. A gateway bot token invited into dozens of channels is not the credential you want sitting in a read-only research agent’s config, and the reverse is just as true.
Confirm the leash before you trust it
- 01
Make the agent list what it cannot do, not just what it can.
Read-only is a server setting. The agent will not volunteer the boundary unless you ask for it directly.
Type this
List every Slack tool you currently have, and tell me which of them, if any, can post a message, add a reaction, or write to a channel.
- 02
Ask for the scope, not the capability.
A tool appearing in a list and a scope being granted are two different claims. The token decides what a call actually does.
Type this
What token type and OAuth scopes is this Slack connection using right now?
- 03
Have it name the exact channels before a real task starts.
A bot token only sees channels it has been invited to. Confirming the list up front beats a confident wrong answer mid-task.
Type this
List every channel you can currently read from, by name, before we start.
Rate limits and tokens in logs
Slack enforces its Web API rate-limit tiers on MCP calls exactly as it does on direct API calls, 20-plus requests a minute on Tier 2 methods like channel search, 50-plus on Tier 3 methods like reading a channel, 100-plus on Tier 4 methods like reading a user profile. chat.postMessage and message search carry their own special limits documented per method. None of this is unique to MCP. It is the same ceiling you would hit calling the Slack API directly, which is the point: an MCP server does not grant the agent more than the token already allows.
The token itself is the part worth guarding. I rotated a set of API tokens once, after a dump of config.yaml inside a Hermes session wrote them into the session log. A Slack bot or user token sitting in env: is exactly as exposed as anything else in that file. Do not let an agent print its own config, and treat a leaked Slack token the same way you would any other credential: rotate it, do not just hope the log gets cleaned up.
My actual use: a briefing, not a chatbot
At my day job, a Hermes cron job reads the company’s Slack alongside Google Workspace, Git and Confluence or Jira, and writes me a daily briefing of what is happening. Its job is to read: four sources through MCP servers, turned into one message to me. The full setup, including why a briefing beats a chat interface for this job, is in Hermes Agent and the daily briefing.
That is the shape I would recommend for most Slack-plus-agent setups: narrow scopes, a server that defaults to read-only, and a cron job instead of a bot that is always listening for a reason to reply.
Slack MCP server, quick answers
Is there an official Slack MCP server?
Yes. Slack hosts one at mcp.slack.com/mcp, reachable over Streamable HTTP, authenticated with user-token OAuth 2.0 behind an admin-approved, Marketplace-listed or internal Slack app.
What is the best Slack MCP server for Claude Code?
The official server if your workspace requires admin approval for third-party access. korotovsky/slack-mcp-server if you want a self-hosted option you can wire in today with a single token and no app review, and it already defaults to read-only.
How do I connect Slack MCP to Claude Code?
claude mcp add --transport http slack https://mcp.slack.com/mcp for the official server, then authenticate through /mcp in a session. For the community server, claude mcp add --env SLACK_MCP_XOXB_TOKEN=... -- npx -y slack-mcp-server@latest --transport stdio, with -- separating Claude Code's own flags from the server's.
Can a Slack MCP server post messages?
korotovsky's server ships with every write tool disabled until you set its specific environment variable or list it explicitly. The official server can post if the OAuth scope you request includes chat:write. Request read-only scopes unless the agent has an approved reason to post.
What is the difference between Slack MCP and the Hermes Slack gateway?
The gateway plugin lets Slack talk to Hermes: slash commands, mentions, a bot that answers in threads. An MCP server lets Hermes read Slack as a data source, through mcp_servers, with no posting unless you turn it on. They use different tokens and solve different problems.
The newsletter
Don’t Code, Specify. A weekly dispatch from where AI agents meet real production. No hype, just what shipped and what broke.
Subscribe on Substack (opens in a new tab)