Skip to main content
Glama
tomfunk

slack-readonly-mcp

by tomfunk
README.md
# slack-readonly-mcp

A self-hosted, **read-only** Slack MCP server for Claude Code (and any MCP client).

## Why this exists

Hosted Slack MCP connectors route your Slack message content through a
third-party hosted MCP layer. If you care about where that data goes, that hop
sits outside your control. This server avoids it:

- It runs **locally** as a stdio subprocess that the MCP client launches.
- It calls the **Slack Web API directly** with your own token.
- Tool results flow only into your MCP client's context → whatever model
  endpoint you've configured (e.g. an org with zero data retention).

So the full path is: your machine → Slack API → your MCP client → your model
endpoint. No third-party MCP intermediary. Data-retention guarantees are a
property of the model endpoint you point the client at — this server doesn't
change them, it only adds tools.

> **Note:** Data that lives *in Slack* is governed by your Slack plan, not by
> this server. This server only governs the path between Slack and your client.

## Tools (all read-only)

| Tool | Purpose |
|---|---|
| `slack_list_channels` | List channels (id, name, topic, members) |
| `slack_channel_history` | Recent messages in a channel |
| `slack_thread_replies` | All replies in a thread |
| `slack_conversations_info` | Metadata for one channel |
| `slack_user_info` | Look up a user (email omitted) |
| `slack_list_users` | List workspace users (email omitted) |
| `slack_search_messages` | Search messages — **requires a user token** (see below) |

## Setup

### 1. Create a Slack app with read-only scopes

At <https://api.slack.com/apps> → **Create New App → From a manifest**, paste:

```yaml
display_information:
  name: Claude Read-Only
oauth_config:
  scopes:
    bot:
      - channels:read
      - channels:history
      - groups:read
      - groups:history
      - im:read
      - im:history
      - mpim:read
      - mpim:history
      - users:read
    user:
      - search:read   # optional — only needed for slack_search_messages
settings:
  org_deploy_enabled: false
  socket_mode_enabled: false
```

Install it to the workspace, then copy the **Bot User OAuth Token** (`xoxb-…`).
If you want search, also copy the **User OAuth Token** (`xoxp-…`). Invite the bot
to any private channels you want it to read (`/invite @Claude Read-Only`).

### 2. Build

```sh
npm install
npm run build
```

### 3. Register with Claude Code

```sh
claude mcp add slack-readonly \
  --env SLACK_BOT_TOKEN=xoxb-your-token \
  -- node /path/to/slack-readonly-mcp/dist/index.js
```

Or, for a project-scoped `.mcp.json` (keep the token in your shell env, not in
the file — Claude Code expands `${VAR}`):

```json
{
  "mcpServers": {
    "slack-readonly": {
      "command": "node",
      "args": ["/path/to/slack-readonly-mcp/dist/index.js"],
      "env": {
        "SLACK_BOT_TOKEN": "${SLACK_BOT_TOKEN}",
        "SLACK_USER_TOKEN": "${SLACK_USER_TOKEN}"
      }
    }
  }
}
```

## Search caveat

Slack's `search.messages` endpoint **cannot be called with a bot token** — it
requires a user token. Set `SLACK_USER_TOKEN` (`xoxp-…`, `search:read`) to enable
`slack_search_messages`; without it, the other six tools work and search returns
a clear error.

## Notes

- All logging goes to stderr; stdout is the JSON-RPC channel.
- The server fails fast (exit 1) if `SLACK_BOT_TOKEN` is unset.
- Read-only by design. Adding write tools (post/reply/react) means adding write
  scopes — a deliberately separate, larger-blast-radius change.

## License

MIT

TDQS

A4.2/5.0

Scored across 7 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: listing vs single item, history vs search, threads vs general messages, users vs user info. No overlap.

Naming Consistency5/5

All tools follow the consistent 'slack_verb_noun' pattern (e.g., slack_list_channels, slack_user_info). Minor variation between 'channel_history' and 'conversations_info' but both are noun phrases in the same style.

Tool Count5/5

7 tools is well-scoped for a read-only Slack server, covering channel exploration, history, threads, user info, and search without being excessive.

Completeness4/5

Covers core read operations (channel list, history, threads, users, search). Minor gaps like reading pinned messages or files, but these are less critical for a read-only interface.

Maintenance

ActivityStale
ResponsivenessNo issues