npx -y @jtalk22/slack-mcp --setupThe trick: session tokens, not OAuth
Slack's official MCP server is OAuth-first — a registered app, admin approval, and (for several clients) compatibility workarounds that don't exist yet (see the tracked Claude Code / Copilot DCR discussion). For a lot of people the "integration" quietly degrades into screenshotting messages into a chat window. That isn't an integration.
So this server does the obvious thing instead: it reads the xoxc- + xoxd- session tokens your browser is already holding and speaks Slack's own API with them. No app install, no scopes to request, no admin in the loop — and because there's no bot user and no installed app, nothing appears in the workspace admin panel. Your agent's footprint is exactly your open browser tab's: no more, no less.
| Slack Official MCP | This Server | |
|---|---|---|
| OAuth app required | Yes | No |
| Admin approval | Yes | No |
| Claude Code · Cursor · Copilot · Windsurf · Gemini CLI · Codex CLI | Blocked or partial (DCR) | All six, today |
| Setup time | ~30 min | ~2 min |
| Tools | Limited | 21 |
| Visible to admins | Yes | No — session-token transport |
<sub>Same permissions either way — your agent sees exactly what you see. The difference is who has to approve it.</sub>
<details> <summary><b>Is this against Slack's terms?</b></summary> <br>Honest answer: it's a gray area, and you should know exactly what this does before you run it. This server automates <i>your own session</i> — the same class of thing as a browser extension or a userscript. It grants your agent nothing you don't already have: it can't read a channel you can't read, join a workspace you're not in, or act as anyone but you. There is no permission escalation anywhere in this codebase — just your cookie, used from your machine.
What it does <i>not</i> do: it does not evade compliance exports, DLP, or retention. Those run server-side at Slack and see this traffic like any other client's. "Invisible to admins" means there is no <i>app install</i> to review — not that your messages stop being subject to workspace policy.
If your workspace's acceptable-use policy forbids unofficial clients, respect it — the OAuth-based <a href="https://mcp.revasserlabs.com">hosted version</a> exists for exactly that case.
</details>Watch it run
<div align="center"> <a href="https://jtalk22.github.io/slack-mcp-server/public/demo-video.html"> <img src="docs/images/watch-it-run.gif" width="900" alt="Real session: the agent calls slack_conversations_unreads, pulls channel history, and writes the morning briefing"> </a> <p><sub>A real session at 2× — unread counts → history pull → the briefing. <a href="https://jtalk22.github.io/slack-mcp-server/public/demo-video.html">Full 3:24 with chapters →</a></sub></p> </div>Install
Node.js 20+. One command extracts your tokens, validates them, and remembers where to keep them:
npx -y @jtalk22/slack-mcp --setupRegister the server with your client, restart it, then ask your agent to run slack_health_check — a workspace name in the reply means you're live. Pick your client:
Add to ~/.claude.json:
{
"mcpServers": {
"slack": { "type": "stdio", "command": "npx", "args": ["-y", "@jtalk22/slack-mcp"] }
}
}Or in one line: claude mcp add slack -- npx -y @jtalk22/slack-mcp
macOS — ~/Library/Application Support/Claude/claude_desktop_config.json
Windows / Linux — %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"slack": { "command": "npx", "args": ["-y", "@jtalk22/slack-mcp"] }
}
}</details> <details> <summary><strong>Cursor</strong></summary>On Windows and Linux, auto-refresh is unavailable — supply tokens explicitly with an
"env": { "SLACK_TOKEN": "xoxc-…", "SLACK_COOKIE": "xoxd-…" }block.
Add to .cursor/mcp.json:
{
"mcpServers": {
"slack": { "command": "npx", "args": ["-y", "@jtalk22/slack-mcp"] }
}
}Add to .vscode/mcp.json:
{
"servers": {
"slack": { "command": "npx", "args": ["-y", "@jtalk22/slack-mcp"] }
}
}Add to ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"slack": { "command": "npx", "args": ["-y", "@jtalk22/slack-mcp"] }
}
}Add to ~/.gemini/settings.json:
{
"mcpServers": {
"slack": { "command": "npx", "args": ["-y", "@jtalk22/slack-mcp"] }
}
}Add to ~/.codex/config.toml:
[mcp_servers.slack]
command = "npx"
args = ["-y", "@jtalk22/slack-mcp"]Or via CLI: codex mcp add slack -- npx -y @jtalk22/slack-mcp
Anything that speaks stdio MCP works — point it at npx -y @jtalk22/slack-mcp. On macOS, tokens auto-extract from Chrome (no env block needed); elsewhere, pass SLACK_TOKEN / SLACK_COOKIE via env.
docker pull ghcr.io/jtalk22/slack-mcp-server:latest{
"mcpServers": {
"slack": {
"command": "docker",
"args": ["run", "-i", "--rm",
"-v", "~/.slack-mcp-tokens.json:/root/.slack-mcp-tokens.json",
"ghcr.io/jtalk22/slack-mcp-server"]
}
}
}Full walkthrough — including the optional keep-tokens-fresh LaunchAgent — in docs/SETUP.md.
The 21 tools
Every workspace write-path tool carries an MCP destructive annotation so clients can gate it.
| Tool | Description | Safety |
|---|---|---|
| Read the workspace — 12 read-only tools | ||
slack_health_check | Verify token validity and workspace info | read-only |
slack_token_status | Token age, health, and cache stats | read-only |
slack_refresh_tokens | Auto-extract fresh tokens from Chrome | read-only* |
slack_list_conversations | List DMs and channels | read-only |
slack_conversations_history ‡ | Get messages from a channel or DM | read-only |
slack_get_full_conversation ‡ | Export full history with threads | read-only |
slack_search_messages ‡ | Search across the workspace | read-only |
slack_get_thread ‡ | Get thread replies | read-only |
slack_users_info | Get user details | read-only |
slack_list_users | List workspace users (paginated, 500+) | read-only |
slack_users_search | Search users by name, display name, or email | read-only |
slack_conversations_unreads | Get channels/DMs with unread messages | read-only |
| Act in the workspace — 4 write-path tools, all annotated destructive | ||
slack_send_message | Send a message to any conversation | destructive |
slack_add_reaction | Add an emoji reaction to a message | destructive |
slack_remove_reaction | Remove an emoji reaction from a message | destructive |
slack_conversations_mark | Mark a conversation as read | destructive |
| Workflow profiles — 2 tools, local JSON | ||
slack_workflow_save | Save a workflow profile to ~/.slack-mcp-workflows.json | local-write |
slack_workflows | List saved workflow profiles | read-only |
| Hosted-brain stubs — 3 tools | ||
slack_smart_search | Semantic search across indexed channels | hosted-stub† |
slack_catch_me_up | AI-summarized digest of unreads + priority threads | hosted-stub† |
slack_triage | Prioritized action queue across channels | hosted-stub† |
<sub>* slack_refresh_tokens writes the local token file only. † Hosted stubs return a structured upgrade payload (signup_url, free_tier_quota, pro_value_prop) — no Slack call happens from OSS. ‡ Accepts include_rich_message_fields — see Rich message fields.</sub>
Workflows: Slack in, typed JSON out
Reading messages is table stakes. The primitives turn Slack into a typed data source your automation can consume directly. Bind a workflow_kind to a set of channels, priority people, retention, and cadence with slack_workflow_save (stored locally at ~/.slack-mcp-workflows.json). The hosted brain reads those profiles and returns structured JSON per kind — no prompt-parsing, no scraping, feed it straight into Linear, Notion, or a status dashboard.
workflow_kind | Returns |
|---|---|
incident_room | {incident_summary, timeline, open_risks, owner_gaps, next_actions} |
exec_brief | `{summary, decisions, risks, asks, action_i |
…