slack-mcp & slack-cli: Give Your AI Assistant Read Access to Slack
← Back to blog

slack-mcp & slack-cli: Give Your AI Assistant Read Access to Slack

Published on
5 mins read
--- views
slack-mcp, an AI assistant searching Slack messages, threads, and users

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:

ToolParametersDescription
search_messagesworkspace, query, count?, start_from?Search messages across all channels, returns channel, author, snippet, timestamp, permalink
load_slack_contextworkspace, channel_id, thread_ts, permalink?, channel_name?, search_query?, start_from?Primary tool, load a thread with every user resolved, formatted as markdown
load_threadworkspace, channel_id, thread_ts, start_from?Load every message in a thread (raw user IDs; paginates up to ~2000)
get_user_infoworkspace, user_idResolve a user ID to a display name
list_workspaces-List workspaces with saved credentials
get_credentialsworkspaceCheck whether credentials exist (never exposes tokens)
auth_startworkspace?Open Slack + return token-extraction instructions
auth_completeworkspace, token, cookieValidate and save credentials
delete_credentialsworkspaceRemove 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_from accepts a YYYY-MM-DD date. Only messages on or after it are returned. Works on search_messages, load_thread, and load_slack_context.

CLI Commands

Everything the server does, slack-cli exposes directly, handy for auth and for scripting:

CommandParametersDescription
auth[workspace]Interactive auth, opens browser, prompts for token + cookie
auth-start[workspace]Print DevTools extraction instructions without saving
auth-complete<workspace> --token --cookieSave 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-cli on your PATH (or point to it with SLACK_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