Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mcp-slack

An MCP server for reading Slack through your own browser session, for workspaces where installing a Slack app isn't an option. Ten tools: six primitives, three multi-call operations, one write that is off by default.

It authenticates as you, not as a bot. Everything you can see, it can read; anything it posts is indistinguishable from a message you typed. Browser-session auth is not an officially supported Slack integration path, so check your workspace's policies first.

The tools take explicit ranges and neutral defaults — no assumed reporting cadence, channel naming scheme, or truncation limit — so workflows can be built on top rather than baked in.

Install

Copy the d cookie from your browser (developer tools → Application → Cookies → https://app.slack.com) into ~/.slack-tokens.yml:

slack:
  - name: myworkspace.slack.com
    token: xoxd-your-cookie-value-here
    xoxc: null # auto-populated on first run

The short-lived xoxc API token is derived automatically and written back, so later runs skip that step. Both values are session credentials — chmod 600 the file, and expect to recopy the cookie whenever your browser session ends.

Then install the server and register it:

uv tool install --editable .
{
  "mcpServers": {
    "slack": {
      "command": "/Users/you/.local/bin/mcp-slack",
      "args": [],
      "lifecycle": "lazy"
    }
  }
}

To skip installing, point at the repo-root shim instead — it carries a PEP 723 header, so uv resolves dependencies on the fly: "command": "uv", "args": ["run", "/path/to/mcp-slack/server.py"].

Tools

Tool Purpose
slack_search Native Slack search syntax (from:@user, in:#channel, after:, has:link)
slack_channel_history Messages from one channel over a time window
slack_thread Every reply in a thread
slack_dm_history DM history with one person
slack_user Resolve a username or user ID to a profile
slack_list_channels Channel discovery by glob and member count (expensive)

Three tools stitch many calls into one result. They exist because their deduplication isn't reproducible from outside: a message found by search, by channel history, and by thread expansion is the same message, and only the server sees all three passes.

Tool Purpose
slack_user_activity Everything one person said or received in a range, with optional surrounding context and thread expansion, grouped by channel
slack_channels_history History for many channels at once, by list or glob, with replies nested under their parents
slack_profiles Batch profiles with custom fields resolved to labels

Time ranges accept YYYY-MM-DD, an epoch, or a relative offset like -7d.

slack_post_message posts as you, and refuses unless SLACK_MCP_ALLOW_WRITE=1 is set in the server's environment:

"env": { "SLACK_MCP_ALLOW_WRITE": "1" }

Behavior worth knowing

  • A channel with no messages can't be resolved by name. Names resolve via search.messages, because conversations.list is throttled to the point of uselessness on Enterprise Grid — measured at 11m48s of consecutive 429 backoffs without reaching the target channel. Pass a channel ID (C…) for empty or archived channels, and prefer a channel name over slack_list_channels, which still enumerates and may return rate_limited.

  • Glob discovery only sees channels you've joined. It uses users.conversations for the same throttling reason.

  • Failures come back as data, not exceptions: {"error": "not_found", ...}. Codes are not_found, rate_limited, auth_failed, and write_disabled. An expired cookie shows up as auth_failed.

  • Rate-limit waits are bounded. A cumulative sleep budget (45s, reset each tool call) means a call returns rate_limited rather than hanging. Library callers who don't mind waiting can raise it: SlackClient(ws, wait_budget=600).

  • Messages are projected, not passed through. Raw Slack records run to several KB each; tools return ts, time, user, user_name, text, and permalink, plus thread fields when meaningful. Mentions and links are rewritten to readable text, and permalinks are built locally, so citing a message costs no extra call.

  • Lookups are cached, message content is not. One JSON file per workspace, with a timestamp per entry:

    Cached TTL
    DM channel ID never assigned once per pair of users
    user name → ID 30d only a handle change invalidates it
    user ID → name 7d display names change occasionally
    channel name → ID 7d renames are rare but real
    team profile schema 30d effectively static
    channel member counts 24h drifts slowly, only gates a filter
    failed lookups 1h stops a typo being re-searched in a loop

    A negative is only recorded after a search completes and matches nothing, so a rate limit or transport error is never cached as "does not exist".

Library use

The multi-call operations are plain functions in slack_mcp/aggregate.py (user_activity, channels_history, profiles) taking an explicit SlackClient. Import them directly rather than speaking MCP to a subprocess.

License

MIT

About

user oriented slack mcp

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages