Skip to main content
Glama
README.md
# 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`:

```yaml
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:

```bash
uv tool install --editable .
```

```json
{
  "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:

```json
"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

TDQS

A4.4/5.0

Scored across 10 tools

Disambiguation4/5

Most tools have clearly distinct purposes: search, channel history, thread expansion, DM history, user lookup, and posting. Minor overlap exists between slack_user_activity and the composition of search/history/threads, and between slack_user vs slack_profiles, but descriptions clarify their intended uses.

Naming Consistency4/5

All tools share the slack_ prefix and use lowercase snake_case, which is consistent. Some names are verbs (search, list, post) while others are nouns (thread, user, profiles), and history variants differ (channel_history vs channels_history), but the pattern is readable and predictable overall.

Tool Count5/5

Ten tools is well within the ideal range for a Slack-focused server. The count covers search, messaging history, threads, DMs, channels, users, profiles, and posting without being bloated or sparse.

Completeness4/5

The tool set provides solid coverage of read operations: search, channel/thread/DM history, multi-channel history, user activity, and profile lookups. Minor gaps exist such as channel metadata, reactions, or message send (disabled by default), but core agent workflows are well supported.

Maintenance

ActivitySlowing
ResponsivenessNo issues