slack
by gustavonline
README.md
# Slack MCP Server for Private Channels
An independently maintained [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server for Slack. It supports public and private channel discovery, channel history, thread history, messages, reactions, and user profiles.
This is **not** the official `@modelcontextprotocol/server-slack` package and is not affiliated with Anthropic, Slack, or the Model Context Protocol project. It is derived from Anthropic's archived MIT-licensed Slack server; see [Attribution](#attribution).
## Requirements
- Node.js 20 or newer
- A Slack app with a bot token (`xoxb-...`)
- The Slack app installed in the target workspace
- The app invited to every private channel it needs to access
## Slack scopes
Grant only the scopes needed for the tools you intend to use:
| Capability | Public channel scope | Private channel scope |
| --- | --- | --- |
| List channels | `channels:read` | `groups:read` |
| Read channel and thread history | `channels:history` | `groups:history` |
| Post messages and thread replies | `chat:write` | `chat:write` |
| Add reactions | `reactions:write` | `reactions:write` |
| List users | `users:read` | — |
| Read detailed profiles | `users.profile:read` | — |
Scopes alone do not expose private channels: invite the Slack app to each private channel first. After changing scopes, reinstall the app to the workspace.
## Install
Run directly with npm:
```bash
npx -y @gustavonline/slack-mcp-server-private-channels
```
Or install globally:
```bash
npm install --global @gustavonline/slack-mcp-server-private-channels
slack-mcp-private-channels
```
### MCP client configuration
```json
{
"mcpServers": {
"slack-private-channels": {
"command": "npx",
"args": [
"-y",
"@gustavonline/slack-mcp-server-private-channels"
],
"env": {
"SLACK_BOT_TOKEN": "xoxb-your-bot-token",
"SLACK_TEAM_ID": "T01234567",
"SLACK_CHANNEL_IDS": "C01234567,G76543210"
}
}
}
}
```
`SLACK_CHANNEL_IDS` is optional. When present, it is an enforced allowlist for every channel-specific tool, not merely a filter for channel listing. Leave it unset to let Slack permissions and channel membership determine access.
Never commit a real Slack token to source control. Prefer your MCP client's secret storage or an environment-injection mechanism.
## Tools
- `slack_list_channels` — list public and private channels, with cursor pagination
- `slack_get_channel_history` — read messages in a channel, with cursor pagination
- `slack_get_thread_replies` — read a complete thread page, with cursor pagination
- `slack_post_message` — post a channel message
- `slack_reply_to_thread` — reply to a thread
- `slack_add_reaction` — add an emoji reaction
- `slack_get_users` — list workspace users, with cursor pagination
- `slack_get_user_profile` — read a user's detailed profile
Slack responses are returned as JSON text. Slack API failures are marked as MCP tool errors. Missing private-channel scopes include actionable guidance for `groups:read` or `groups:history`.
## Environment variables
| Variable | Required | Description |
| --- | --- | --- |
| `SLACK_BOT_TOKEN` | Yes | Bot User OAuth Token; normally starts with `xoxb-` |
| `SLACK_TEAM_ID` | Yes | Workspace/team ID; starts with `T` |
| `SLACK_CHANNEL_IDS` | No | Comma-separated channel allowlist, enforced on reads and writes |
The server keeps the MCP connection available when required configuration is missing and returns a configuration error for tool calls. It does not log tokens, message text, or complete tool arguments.
## Docker
Build from the repository root:
```bash
docker build -t slack-mcp-private-channels .
```
Run it as a stdio MCP server:
```bash
docker run --rm -i \
-e SLACK_BOT_TOKEN \
-e SLACK_TEAM_ID \
-e SLACK_CHANNEL_IDS \
slack-mcp-private-channels
```
The image runs as the unprivileged `node` user.
## Development
```bash
npm ci
npm run check
npm pack --dry-run
npm publish --dry-run
```
Tests mock Slack's HTTP API and specifically cover private channel discovery, `conversations.history`, `conversations.replies`, scope errors, pagination, and allowlist enforcement. No real Slack credentials are required.
## Release bootstrap
Publishing is intentionally separate from CI. The
[`Publish to npm` workflow](.github/workflows/release.yml) runs only after a
manual `workflow_dispatch` and targets the protected GitHub Environment
`npm-publish`. It requests only `contents: read` and `id-token: write`, stores
no npm token, verifies the package again, and publishes with npm provenance.
Before using the workflow, the package owner must:
1. Approve the exact package name and version and confirm that the version is
not already present in the npm registry.
2. Establish the package under the `@gustavonline` scope using an
owner-authorized npm first-publish/bootstrap path. If npm requires an
authenticated first publication before a Trusted Publisher can be added,
that one-time action must be performed explicitly by the owner; this
workflow does not bootstrap ownership.
3. In npm package settings, configure a GitHub Actions Trusted Publisher for
owner `gustavonline`, repository `slack-mcp-server-private-channels`,
workflow filename `release.yml`, and environment `npm-publish`.
4. In GitHub repository settings, create the `npm-publish` Environment, limit
it to the intended release branch, and add an owner as required reviewer.
5. Confirm that npm Trusted Publisher access, GitHub Environment approval, and
repository push authority are all active before running the workflow.
The workflow must not be run merely to test publishing. Use
`npm publish --dry-run` locally or in CI for payload validation. A workflow run
performs a real public npm publication after the environment approval gate.
## Troubleshooting private channels
If a private channel is missing or history fails:
1. Add `groups:read` for discovery and `groups:history` for channel/thread history.
2. Reinstall the Slack app after changing OAuth scopes.
3. Invite the app to the private channel.
4. If `SLACK_CHANNEL_IDS` is set, include that channel's ID (often starting with `G`).
5. Inspect the returned Slack error such as `missing_scope` or `not_in_channel`.
## Security
Use the smallest practical Slack scope set and optionally configure `SLACK_CHANNEL_IDS` as a defense-in-depth allowlist. See [SECURITY.md](SECURITY.md) for private vulnerability reporting.
## Attribution
This project is derived from the Slack server in the archived [Model Context Protocol servers repository](https://github.com/modelcontextprotocol/servers-archived/tree/main/src/slack), originally Copyright © 2024 Anthropic, PBC and released under the MIT License. Subsequent private-channel support and maintenance are by Gustav Anderson.
The package identity, maintainer, repository, and documentation describe this fork rather than implying that it is the official upstream package. See [NOTICE](NOTICE) and [LICENSE](LICENSE).
TDQS
A3.6/5.0
Scored across 8 tools
Disambiguation5/5
Each tool targets a distinct action: adding reactions, fetching history, retrieving threads, user profiles, user lists, channel lists, posting messages, and replying to threads. There is no ambiguity between tools.
Naming Consistency5/5
All tool names follow the consistent pattern 'slack_verb_noun' using snake_case, such as slack_get_channel_history and slack_post_message. No deviations.
Tool Count5/5
8 tools is well-suited for a Slack integration, covering core messaging, reactions, user and channel info, and threads. The count is neither too sparse nor excessive.
Completeness3/5
The set covers essential read and write operations but lacks message update/delete, channel creation, file uploads, and direct messaging. Notable gaps that agents may encounter.
Maintenance
ActivityMaintained
ResponsivenessNo issues