
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-cli is the engine. It authenticates to Slack, encrypts and stores the credentials, and makes the actual API calls, which also makes it usable on its own from a terminal or a script. slack-mcp is a thin MCP layer on top: it exposes the same capabilities as MCP tools over stdio, so any MCP-aware agent (Claude, Cursor, and the rest) 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