
slack-mcp & slack-cli: Give Your AI Assistant Read Access to Slack
- Published on
- • 5 mins read•--- views

So much of the context an AI assistant needs lives in Slack — the conversation behind a ticket, the back-and-forth that explains a bug, the thread where a decision actually got made. The model can't see any of it. So I built a pair of tools that fix that: slack-mcp, a Model Context Protocol server, and slack-cli, the Go command-line tool that powers it.
Together they give your AI assistant read access to Slack — search messages, unroll threads, and resolve who said what — and pull that real context straight into its working memory.
Two Repos, One Tool
These ship as two binaries on purpose:
slack-cliis the engine. It authenticates to Slack, encrypts and stores credentials, and does the actual API calls — usable on its own from a terminal or a script.slack-mcpis a thin MCP layer on top. It exposes the same capabilities as MCP tools over stdio so any MCP-aware agent (Claude, Cursor, etc.) can call them.
Splitting it this way means the auth-and-Slack logic lives in one well-tested place, and the MCP server stays small. You can drive Slack from a shell script and from your AI assistant with the same credentials.
MCP Tools
The server exposes nine read-and-auth tools. load_slack_context is the headline:
| Tool | Parameters | Description |
|---|---|---|
search_messages | workspace, query, count?, start_from? | Search messages across all channels — returns channel, author, snippet, timestamp, permalink |
load_slack_context | workspace, channel_id, thread_ts, permalink?, channel_name?, search_query?, start_from? | Primary tool — load a thread with every user resolved, formatted as markdown |
load_thread | workspace, channel_id, thread_ts, start_from? | Load every message in a thread (raw user IDs; paginates up to ~2000) |
get_user_info | workspace, user_id | Resolve a user ID to a display name |
list_workspaces | — | List workspaces with saved credentials |
get_credentials | workspace | Check whether credentials exist (never exposes tokens) |
auth_start | workspace? | Open Slack + return token-extraction instructions |
auth_complete | workspace, token, cookie | Validate and save credentials |
delete_credentials | workspace | Remove stored credentials |
load_slack_context is the one I designed everything around: give it a channel and a thread, and it returns the full conversation with every user resolved to a display name, formatted as markdown — exactly what an LLM wants to read. No raw U01ABCD IDs, no JSON soup.
📅
start_fromaccepts aYYYY-MM-DDdate — only messages on or after it are returned. Works onsearch_messages,load_thread, andload_slack_context.
CLI Commands
Everything the server does, slack-cli exposes directly — handy for auth and for scripting:
| Command | Parameters | Description |
|---|---|---|
auth | [workspace] | Interactive auth — opens browser, prompts for token + cookie |
auth-start | [workspace] | Print DevTools extraction instructions without saving |
auth-complete | <workspace> --token --cookie | Save credentials non-interactively |
list-workspaces | — | List all saved workspace names |
get-credentials | <workspace> | Show whether token + cookie are present |
test-creds | [workspace] | Validate stored credentials against Slack auth.test |
remove-creds | [workspace] | Delete stored credentials for a workspace |
show-creds | — | Print the path to the credentials file |
Authentication Without a Slack App
This is the part that makes it actually usable. slack-cli authenticates with a browser-session token (xoxc-…) plus cookie (xoxd-…) — no Slack app to register, no admin approval, no OAuth scopes to beg for. You sign into the workspace you already use, extract the pair once, and you're done.
slack-cli auth acme # interactive — opens the browser, prompts for token + cookie
# or, non-interactively:
export SLACK_MCP_PASSPHRASE=your-passphrase-here
slack-cli auth-complete acme --token xoxc-... --cookie xoxd-...
Credentials are encrypted at rest with a passphrase read from SLACK_MCP_PASSPHRASE (or an interactive prompt). The passphrase that saved them must match the one that reads them — the MCP server uses the same env var, so the agent decrypts and never sees the raw tokens in a transcript.
Setup
Prerequisites
- Go 1.26+ — to build or
go install slack-clion yourPATH(or point to it withSLACK_CLI_PATH=/abs/path/to/slack-cli) — it's the companion binary that stores credentials and calls Slack
Install
# the CLI engine
go install github.com/artschekoff/slack-cli/cmd/slack-cli@latest
# the MCP server
go install github.com/artschekoff/slack-mcp/cmd/slack-mcp@latest
Both also build from source with git clone … && make install.
Wire it into your MCP client
Add a stdio server entry — the passphrase goes in env so credentials decrypt at runtime:
{
"mcpServers": {
"slack": {
"type": "stdio",
"command": "slack-mcp",
"env": {
"SLACK_MCP_PASSPHRASE": "your-passphrase"
}
}
}
}
Or with the Claude Code CLI:
claude mcp add slack --env SLACK_MCP_PASSPHRASE=your-passphrase -- slack-mcp
Why Read-Only, and Why Split the Binary
I deliberately scoped this to reading. An agent that can post to Slack on your behalf is a different, scarier risk profile; an agent that can pull the context behind a ticket is just useful. Keeping it read-only means you can hand it to your assistant without worrying it'll message a channel.
Splitting the CLI from the MCP server follows the same principle behind my other MCP tools — put the real work in a mature, testable binary, then wrap exactly the operations an agent needs in a thin MCP layer. Credentials stay encrypted, tokens never hit the transcript, and the same engine serves both your shell and your AI assistant.
Both projects are open on GitHub — slack-mcp and slack-cli — pure Go, running over stdio. Issues and pull requests welcome.
Open for contract collaboration
I am available for contract-based collaboration. If you have an interesting project idea, schedule a call via Calendly.
Schedule a 30-min call