Skip to main content
Glama
README.md
# nomos-slack-mcp

An MCP server that lets AI agents read and write Slack messages **as you** — not as a bot. Messages, reactions, and status updates appear exactly as if you typed them yourself.

Built for [Claude Code](https://docs.anthropic.com/en/docs/claude-code) and any MCP-compatible client. Supports multiple Slack workspaces with independent authentication.

## Why?

Existing Slack integrations send messages as a bot with an `APP` badge. This uses **Slack user tokens** (`xoxp-`) so your agent operates as you — indistinguishable from you being at the keyboard.

## Features

- **Send as you** — no bot badge, no "APP" indicator
- **Multi-workspace** — manage 2+ Slack workspaces with separate tokens and permissions
- **10 tools** — read, write, search, react, set status
- **Smart resolution** — use `#channel-name`, `@username`, or raw channel IDs
- **Local only** — tokens stay on your machine at `~/.nomos/slack/config.json` with `0600` permissions

## Quick Start

### 1. Create a Slack App

For **each** workspace you want to connect:

1. Go to [api.slack.com/apps](https://api.slack.com/apps) → **Create New App** → **From app manifest**
2. Paste the contents of [`slack-app-manifest.yml`](./slack-app-manifest.yml) (or use the JSON version)
3. Click **Create**
4. Go to **Install App** → **Install to Workspace** → **Allow**

> [!TIP]
> The manifest pre-configures all required User Token Scopes and the OAuth redirect URL. No manual scope configuration needed.

### 2. Install

```bash
git clone https://github.com/project-nomos/nomos-slack-mcp.git
cd nomos-slack-mcp
pnpm install
pnpm build
```

### 3. Add Your Workspaces

**Option A: OAuth flow** (recommended)

```bash
pnpm add-workspace
```

You'll be prompted for:

- A workspace alias (e.g. `work`, `side-project`)
- Your Slack App's **Client ID** and **Client Secret** (found under **Basic Information** in your Slack App settings)

The script opens your browser for OAuth authorization and stores the user token automatically.

**Option B: Manual token**

```bash
pnpm add-workspace -- --manual
```

Paste your `xoxp-` token directly. Find it in your Slack App under **OAuth & Permissions** → **User OAuth Token**.

Repeat for each workspace.

### 4. Connect to Claude Code

```bash
claude mcp add nomos-slack -- node /path/to/nomos-slack-mcp/dist/src/index.js
```

Or add to your MCP config manually:

```json
{
  "mcpServers": {
    "nomos-slack": {
      "command": "node",
      "args": ["/path/to/nomos-slack-mcp/dist/src/index.js"]
    }
  }
}
```

## Tools

| Tool                    | Description                                                            |
| ----------------------- | ---------------------------------------------------------------------- |
| `slack_list_workspaces` | List configured workspaces and which is default                        |
| `slack_list_channels`   | Browse channels, DMs, groups — filter by type or name                  |
| `slack_read_messages`   | Read recent messages from any channel or DM                            |
| `slack_read_thread`     | Read all replies in a thread                                           |
| `slack_send_message`    | Send a message as you                                                  |
| `slack_reply_thread`    | Reply in a thread as you                                               |
| `slack_search`          | Search messages with Slack operators (`from:`, `in:`, `before:`, etc.) |
| `slack_list_users`      | List or search workspace members                                       |
| `slack_set_status`      | Set your status emoji and text                                         |
| `slack_react`           | Add a reaction to a message                                            |

### Channel Resolution

All tools that accept a `channel` parameter understand:

- `#general` — public/private channel by name
- `@john` — opens a DM with that user
- `C0123ABCDEF` — raw Slack channel ID

### Multi-Workspace

Every tool accepts an optional `workspace` parameter. Omit it to use your default workspace.

```
"Read my DMs in the side-project workspace"
→ slack_read_messages({ workspace: "side-project", channel: "@alice" })
```

## Configuration

Config is stored at `~/.nomos/slack/config.json`:

```json
{
  "workspaces": {
    "work": {
      "token": "xoxp-...",
      "teamId": "T01ABC123",
      "teamName": "Acme Corp",
      "userId": "U01XYZ789",
      "addedAt": "2026-03-26T10:00:00Z"
    },
    "side-project": {
      "token": "xoxp-...",
      "teamId": "T02DEF456",
      "teamName": "Side Project",
      "userId": "U02UVW012",
      "addedAt": "2026-03-26T11:00:00Z"
    }
  },
  "defaultWorkspace": "work"
}
```

File permissions are set to `0600` (owner read/write only).

## Required Slack Scopes

All scopes are **User Token Scopes** (not Bot Token Scopes). The included [app manifest](./slack-app-manifest.yml) configures these automatically.

| Scope                 | Purpose                           |
| --------------------- | --------------------------------- |
| `channels:history`    | Read messages in public channels  |
| `channels:read`       | List public channels              |
| `groups:history`      | Read messages in private channels |
| `groups:read`         | List private channels             |
| `im:history`          | Read direct messages              |
| `im:read`             | List direct messages              |
| `mpim:history`        | Read group DMs                    |
| `mpim:read`           | List group DMs                    |
| `chat:write`          | Send messages as you              |
| `users:read`          | List workspace members            |
| `users:read.email`    | See member emails                 |
| `search:read`         | Search messages                   |
| `users.profile:write` | Set your status                   |
| `reactions:write`     | Add reactions                     |
| `reactions:read`      | Read reactions                    |

## Development

```bash
# Install dependencies
npm install

# Build
npm run build

# Type-check without emitting
pnpm check

# Watch mode
pnpm dev
```

### Project Structure

```
src/
├── index.ts                 # MCP server entry point (stdio transport)
├── config/
│   ├── config-manager.ts    # Read/write ~/.nomos/slack/config.json
│   └── types.ts             # TypeScript interfaces
├── slack/
│   ├── client-manager.ts    # Per-workspace WebClient instances + channel/user resolution
│   └── formatters.ts        # Format Slack API responses for LLM consumption
├── tools/
│   ├── index.ts             # Tool registry
│   ├── list-workspaces.ts
│   ├── list-channels.ts
│   ├── read-messages.ts
│   ├── read-thread.ts
│   ├── send-message.ts
│   ├── reply-thread.ts
│   ├── search.ts
│   ├── list-users.ts
│   ├── set-status.ts
│   └── react.ts
├── oauth/
│   ├── flow.ts              # OAuth 2.0 token exchange
│   └── server.ts            # Local callback server for OAuth
scripts/
└── add-workspace.ts         # CLI for adding workspaces
```

## Security

- **Tokens are stored locally** at `~/.nomos/slack/config.json` with `0600` file permissions
- **User tokens (`xoxp-`) are sensitive** — they can act as you. Treat them like passwords
- **No data leaves your machine** except Slack API calls and whatever you send to your LLM provider as context
- **Bot tokens are rejected** — the config manager validates that tokens start with `xoxp-`

## Troubleshooting

**"No workspaces configured"**
Run `pnpm add-workspace` to add a workspace.

**"Token must be a user token (xoxp-...)"**
You're using a bot token (`xoxb-`). Go to your Slack App → OAuth & Permissions → copy the **User OAuth Token**, not the Bot User OAuth Token.

**"Channel #foo not found"**
The user token can only see channels you've joined. Join the channel in Slack first.

**"missing_scope" errors**
Your Slack App is missing required scopes. Re-create the app using the provided [manifest](./slack-app-manifest.yml) or manually add the missing scope under OAuth & Permissions → User Token Scopes, then reinstall the app.

**Rate limiting**
The Slack SDK handles `429` responses with automatic retry. If you hit persistent rate limits, reduce the frequency of requests. History endpoints are Tier 2 (~20 req/min), most others are Tier 3 (~50 req/min).

## License

MIT

TDQS

A3.7/5.0

Scored across 10 tools

Disambiguation5/5

Each tool targets a distinct Slack operation: listing, reading, sending, replying, searching, status, and reactions. There is no meaningful overlap between tools; even read_messages and read_thread are clearly separated by message stream vs. thread replies.

Naming Consistency4/5

All tools follow the slack_ prefix with snake_case and mostly use a verb_noun pattern like slack_list_channels and slack_send_message. The only minor deviation is slack_search, which omits an explicit object, but it remains clear and consistent in style.

Tool Count5/5

Ten tools is well-scoped for a Slack integration server. Each tool covers a distinct common Slack action without unnecessary redundancy or bloat.

Completeness4/5

The toolset covers the core Slack workflows: reading, sending, replying, searching, listing users/channels/workspaces, setting status, and reacting. Minor gaps like file uploads, channel creation, or message deletion exist but do not break typical assistant use cases.

Maintenance

ActivityNo data
ResponsivenessNo issues