A Slack MCP server for Claude Code that provides full messaging, channels, search, and threads across multiple Slack workspaces.
- 12 tools — channels, messages, threads, DMs, reactions, search, file upload
- Multi-workspace — connect as many Slack workspaces as you need
- Dual token support — bot tokens and user tokens, with automatic preference
- Post as yourself — user tokens make messages appear from you, not a bot
- Full search —
search_messagesworks with user tokens (no limitations) - Env-var tokens — no secrets in config files or the repo
- Channel name resolution — use
#generalorgeneral, not just IDs
git clone https://github.com/coreyepstein/slack-mcp.git
cd slack-mcp
npm install- Go to api.slack.com/apps and click Create New App > From scratch
- Name it (e.g. "Claude MCP") and select your workspace
- Go to OAuth & Permissions and add scopes (see Scopes below)
- Click Install to Workspace
- Copy the Bot User OAuth Token (
xoxb-...) - Optionally, copy the User OAuth Token (
xoxp-...) — see Token Types
cp workspaces.example.json workspaces.jsonEdit workspaces.json with your workspace name and team ID. Tokens are not stored here:
{
"workspaces": [
{
"name": "my-company",
"team_id": "T_YOUR_TEAM_ID"
}
],
"default": "my-company"
}Find your team ID by running npm run auth -- --setup or from your Slack workspace URL settings.
Tokens are passed via environment variables, never stored in files. The naming convention is:
SLACK_TOKEN_{NAME}_BOT → Bot token (xoxb-...)
SLACK_TOKEN_{NAME}_USER → User token (xoxp-...)
Where {NAME} is the workspace name uppercased with non-alphanumeric characters replaced by underscores.
Examples:
| Workspace name | Bot env var | User env var |
|---|---|---|
my-company |
SLACK_TOKEN_MY_COMPANY_BOT |
SLACK_TOKEN_MY_COMPANY_USER |
voyage |
SLACK_TOKEN_VOYAGE_BOT |
SLACK_TOKEN_VOYAGE_USER |
acme-corp |
SLACK_TOKEN_ACME_CORP_BOT |
SLACK_TOKEN_ACME_CORP_USER |
Add to your project .mcp.json or ~/.claude.json:
{
"mcpServers": {
"slack": {
"type": "stdio",
"command": "npx",
"args": ["tsx", "/absolute/path/to/slack-mcp/src/server.ts"],
"env": {
"SLACK_TOKEN_MY_COMPANY_BOT": "xoxb-your-bot-token",
"SLACK_TOKEN_MY_COMPANY_USER": "xoxp-your-user-token"
}
}
}
}For multiple workspaces, add all tokens to the same env block:
{
"mcpServers": {
"slack": {
"type": "stdio",
"command": "npx",
"args": ["tsx", "/absolute/path/to/slack-mcp/src/server.ts"],
"env": {
"SLACK_TOKEN_VOYAGE_BOT": "xoxb-...",
"SLACK_TOKEN_VOYAGE_USER": "xoxp-...",
"SLACK_TOKEN_INDIGO_BOT": "xoxb-...",
"SLACK_TOKEN_INDIGO_USER": "xoxp-..."
}
}
}
}Important: Use the absolute path to
src/server.ts. Never commit tokens to any tracked file.
npm run auth:checkThis validates all configured tokens against the Slack API and reports their status.
In each Slack channel you want to access, invite the bot:
/invite @Claude MCP
This is required for the bot token to read/write in channels. User tokens can access any channel the token owner is already a member of.
This server supports two types of Slack tokens per workspace:
- Created when you install a Slack App to a workspace
- Messages appear as the app (e.g. "Claude MCP"), not as a person
- Must be explicitly invited to channels with
/invite - Cannot use
search:read(Slack API limitation) - Good for: automated notifications, bot-style interactions
- Generated from the User OAuth Token on the OAuth & Permissions page
- Messages appear as the token owner (e.g. "Corey Epstein") — your real name and avatar
- Has access to any channel the token owner is a member of
- Required for
search_messages(search:readscope) - Good for: acting as yourself, search, accessing channels without
/invite
The server automatically selects the best token for each operation:
| Scenario | Token used |
|---|---|
| User token available | User token (preferred for all operations) |
| User token missing, bot token available | Bot token (automatic fallback) |
| Neither token available | Error with setup instructions |
search_messages |
User token only (hard requirement — no fallback) |
You can start with just a bot token and add a user token later. All operations except search_messages work with either token type.
When a user token (xoxp-...) is configured, all messages sent through the server appear as if you sent them — your name, your profile picture, your identity. This applies to:
send_message— channel messages show your namereply_thread— thread replies show your namesend_dm— DMs come from you, not a bot
This happens automatically. The Slack API posts as the token owner when using a user token. No special configuration or as_user parameter is needed.
If only a bot token is available, messages appear as the Slack App instead.
Add these under OAuth & Permissions > Bot Token Scopes in your Slack App:
| Scope | Description |
|---|---|
channels:read |
List public channels |
channels:history |
Read messages in public channels |
chat:write |
Send messages |
groups:read |
List private channels |
groups:history |
Read messages in private channels |
im:write |
Send direct messages |
users:read |
List workspace members |
users:read.email |
Access user email addresses |
files:write |
Upload files |
reactions:write |
Add emoji reactions |
Add these under OAuth & Permissions > User Token Scopes for full functionality:
| Scope | Description |
|---|---|
chat:write |
Send messages as yourself |
channels:read |
List public channels |
channels:history |
Read messages in public channels |
groups:read |
List private channels |
groups:history |
Read messages in private channels |
im:read |
Read direct message history |
im:write |
Send direct messages |
mpim:read |
Read group DM history |
mpim:write |
Send group DMs |
users:read |
List workspace members |
users:read.email |
Access user email addresses |
files:write |
Upload files |
reactions:write |
Add emoji reactions |
search:read |
Search messages and files |
After adding user token scopes, click Reinstall to Workspace to generate the user token.
| Tool | Description | Token requirement |
|---|---|---|
list_channels |
List channels in a workspace (public and optionally private) | Bot or user |
read_channel |
Read recent messages from a channel | Bot or user |
read_thread |
Read all replies in a thread | Bot or user |
get_channel_info |
Get channel details (topic, purpose, member count) | Bot or user |
send_message |
Send a message to a channel | Bot or user |
reply_thread |
Reply to a specific thread | Bot or user |
send_dm |
Send a direct message to a user (by name, email, or ID) | Bot or user |
list_users |
List all workspace members | Bot or user |
find_user |
Find a user by name, display name, email, or ID | Bot or user |
add_reaction |
Add an emoji reaction to a message | Bot or user |
search_messages |
Search messages across the workspace | User token required |
upload_file |
Upload a file to a channel | Bot or user |
All tools accept an optional workspace parameter (name or team ID). If omitted, uses the default workspace from workspaces.json.
Configure multiple workspaces in workspaces.json and set tokens for each:
{
"workspaces": [
{ "name": "voyage", "team_id": "T7V83HY5B" },
{ "name": "indigo", "team_id": "T_INDIGO_ID" }
],
"default": "voyage"
}Then use the workspace parameter in any tool:
send_message(channel: "general", text: "hello", workspace: "voyage")
send_message(channel: "team", text: "hello", workspace: "indigo")
If workspace is omitted, uses the default from workspaces.json.
The auth CLI helps with setup and health checks:
# Interactive setup — walks through token configuration
npm run auth -- --setup
# Health check — validates all tokens for all workspaces
npm run auth:checkThe --check command tests each token against the Slack API and reports:
Workspace Health Check:
──────────────────────────────────────────────────────────────────────────
Workspace: voyage (default)
Bot token: + connected as @claude-mcp in Voyage
User token: + connected as @corey in Voyage
Workspace: indigo
Bot token: + connected as @claude-mcp in Indigo
User token: - missing (optional — needed for search:read)
Set env: SLACK_TOKEN_INDIGO_USER=xoxp-...
An end-to-end verification script is included at scripts/verify-e2e.ts:
npx tsx scripts/verify-e2e.ts
# Or with a specific test channel:
TEST_CHANNEL=bot-testing npx tsx scripts/verify-e2e.tsThis verifies token connectivity, message posting identity, search functionality, and bot-token fallback across all configured workspaces.
| Error | Cause | Fix |
|---|---|---|
workspaces.json not found |
Config file missing | Run cp workspaces.example.json workspaces.json and edit it |
No token available for workspace "X" |
No env vars set for this workspace | Set SLACK_TOKEN_X_BOT and/or SLACK_TOKEN_X_USER env vars |
invalid_auth |
Token is expired or incorrect | Regenerate the token from your Slack App's OAuth & Permissions page |
channel_not_found |
Bot is not in the channel | Invite the bot: /invite @Claude MCP |
missing_scope |
Token lacks a required OAuth scope | Add the scope in your Slack App's OAuth & Permissions settings, then reinstall |
not_allowed_token_type |
Using a bot token for a user-token-only operation | search_messages requires a user token (xoxp-). Set SLACK_TOKEN_X_USER |
search.messages requires a user token |
No user token configured for this workspace | Obtain a user token (see Token Types) and set the _USER env var |
not_in_channel |
Bot token cannot access this channel | Invite the bot to the channel, or use a user token (which can access any channel the owner is in) |
Unknown workspace: "X" |
Workspace name not in workspaces.json |
Add a workspace entry to workspaces.json with the correct name and team_id |
| Messages appear as the bot, not as me | Using bot token instead of user token | Set SLACK_TOKEN_X_USER with your user OAuth token (xoxp-...) |
Token in git history: An earlier version of this repo stored a Slack bot token in
workspaces.json. That token has been rotated and is no longer valid, but it may still appear in git commit history. If you forked or cloned this repo before the token was removed, the old token in your local history is already invalidated.Best practice: Always pass tokens via environment variables in the
.mcp.jsonenvblock. Never commit tokens toworkspaces.jsonor any other tracked file. The.gitignoreexcludesworkspaces.jsonto prevent accidental commits.
src/
server.ts — MCP server entry point
config.ts — workspace + token resolution from env vars
auth.ts — setup and health check CLI
slack/
client.ts — Slack Web API wrapper with dual-token client caching
types.ts — shared TypeScript types
tools/
*.ts — one file per MCP tool (12 tools)
scripts/
verify-e2e.ts — end-to-end verification script
MIT