Skip to main content
Glama
iskifogl

Slack MCP Server

by iskifogl
README.md
# Slack MCP Server

A Model Context Protocol (MCP) server for Slack API integration. This server allows AI assistants to interact with Slack workspaces through OAuth 2.0 authenticated user tokens.

## Features

- **Channel Operations**: List channels, get channel info, get channel members
- **Message Operations**: Read messages, send messages, reply to threads, search messages
- **User Operations**: List users, get user info, get user profiles
- **File Operations**: List files, get file info, upload files
- **Reaction Operations**: Add/remove reactions, get message reactions

## Prerequisites

- Node.js 18+
- A Slack App with OAuth 2.0 configured
- User token (xoxp-...) with appropriate scopes

## Installation

```bash
npm install
npm run build
```

## Slack App Setup

### 1. Create a Slack App

1. Go to [api.slack.com/apps](https://api.slack.com/apps)
2. Click "Create New App" → "From scratch"
3. Enter app name and select workspace

### 2. Configure OAuth Scopes

Add these **User Token Scopes** under "OAuth & Permissions":

```
channels:read        # List channels
channels:history     # Read channel messages
groups:read          # List private channels
groups:history       # Read private channel messages
im:read              # List direct messages
im:history           # Read direct messages
mpim:read            # List group DMs
mpim:history         # Read group DMs
chat:write           # Send messages
users:read           # List users
users.profile:read   # Read user profiles
files:read           # List files
files:write          # Upload files
reactions:read       # Read reactions
reactions:write      # Add/remove reactions
search:read          # Search messages
```

### 3. Configure Redirect URI

Add your platform's callback URL under "OAuth & Permissions" → "Redirect URLs":

```
https://your-platform.com/oauth/slack/callback
```

### 4. Get Client Credentials

Note down your:
- Client ID
- Client Secret

## Environment Variables

The MCP server reads credentials from environment variables:

```bash
# Required
SLACK_ACCESS_TOKEN=xoxp-your-user-token

# Optional
SLACK_TEAM_ID=T0123456789
```

## OAuth 2.0 Flow (Platform Implementation)

### Step 1: Redirect User to Slack Authorization

```typescript
const SLACK_CLIENT_ID = 'your-client-id';
const REDIRECT_URI = 'https://your-platform.com/oauth/slack/callback';
const SCOPES = 'channels:read,channels:history,chat:write,users:read,files:read,files:write,reactions:read,reactions:write,search:read,groups:read,groups:history,im:read,im:history,mpim:read,mpim:history,users.profile:read';

const authUrl = `https://slack.com/oauth/v2/authorize?client_id=${SLACK_CLIENT_ID}&user_scope=${SCOPES}&redirect_uri=${encodeURIComponent(REDIRECT_URI)}&state=${generateRandomState()}`;

// Redirect user to authUrl
```

### Step 2: Handle OAuth Callback

```typescript
// In your callback handler
app.get('/oauth/slack/callback', async (req, res) => {
  const { code, state } = req.query;

  // Verify state to prevent CSRF
  if (!verifyState(state)) {
    return res.status(400).send('Invalid state');
  }

  // Exchange code for token
  const response = await fetch('https://slack.com/api/oauth.v2.access', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    body: new URLSearchParams({
      client_id: SLACK_CLIENT_ID,
      client_secret: SLACK_CLIENT_SECRET,
      code,
      redirect_uri: REDIRECT_URI,
    }),
  });

  const data = await response.json();

  if (data.ok) {
    // Save user token to your database
    const userToken = data.authed_user.access_token; // xoxp-...
    const userId = data.authed_user.id;
    const teamId = data.team.id;

    await db.saveSlackToken(currentUserId, {
      token: userToken,
      slackUserId: userId,
      teamId: teamId,
    });

    res.redirect('/success');
  } else {
    res.status(400).send(`OAuth error: ${data.error}`);
  }
});
```

### Step 3: Start MCP Server with User Token

```typescript
// When starting the MCP server for a user, inject their token as env var
const userSlackToken = await db.getSlackToken(currentUserId);

const mcpProcess = spawn('node', ['/path/to/slack-mcp/dist/index.js'], {
  env: {
    ...process.env,
    SLACK_ACCESS_TOKEN: userSlackToken,
  },
});
```

## MCP Configuration

Add to your Claude Code configuration (`~/.claude/claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "slack": {
      "command": "node",
      "args": ["/path/to/slack-mcp/dist/index.js"],
      "env": {
        "SLACK_ACCESS_TOKEN": "xoxp-your-token"
      }
    }
  }
}
```

## Available Tools

### Channel Tools

| Tool | Description |
|------|-------------|
| `slack_list_channels` | List all accessible channels |
| `slack_get_channel_info` | Get channel details |
| `slack_get_channel_members` | Get channel member list |

### Message Tools

| Tool | Description |
|------|-------------|
| `slack_get_messages` | Get messages from a channel |
| `slack_get_thread_replies` | Get replies in a thread |
| `slack_send_message` | Send a message to a channel |
| `slack_reply_to_thread` | Reply to a thread |
| `slack_search_messages` | Search messages (requires user token) |

### User Tools

| Tool | Description |
|------|-------------|
| `slack_list_users` | List workspace users |
| `slack_get_user_info` | Get user details |
| `slack_get_user_profile` | Get user profile |

### File Tools

| Tool | Description |
|------|-------------|
| `slack_list_files` | List shared files |
| `slack_get_file_info` | Get file details |
| `slack_upload_file` | Upload a file |

### Reaction Tools

| Tool | Description |
|------|-------------|
| `slack_add_reaction` | Add emoji reaction |
| `slack_remove_reaction` | Remove emoji reaction |
| `slack_get_reactions` | Get message reactions |

## Example Usage

### List Channels
```json
{
  "tool": "slack_list_channels",
  "arguments": {
    "types": "public_channel,private_channel",
    "limit": 50
  }
}
```

### Send Message
```json
{
  "tool": "slack_send_message",
  "arguments": {
    "channel_id": "C1234567890",
    "text": "Hello from MCP!"
  }
}
```

### Search Messages
```json
{
  "tool": "slack_search_messages",
  "arguments": {
    "query": "from:@user in:#channel important",
    "count": 20
  }
}
```

## Error Handling

The server returns structured error responses:

```json
{
  "error": "Slack API Error (invalid_auth): Invalid authentication token."
}
```

Common error codes:
- `invalid_auth`: Token is invalid
- `token_revoked`: Token has been revoked
- `missing_scope`: Token lacks required scope
- `channel_not_found`: Channel doesn't exist
- `ratelimited`: Rate limit exceeded

## Security Considerations

- Never expose user tokens in client-side code
- Store tokens securely in your database (encrypted)
- Use HTTPS for all OAuth redirects
- Validate state parameter to prevent CSRF
- Rotate tokens periodically using refresh tokens
- Request only necessary scopes

## License

MIT

TDQS

A3.5/5.0

Scored across 20 tools

Disambiguation5/5

Every tool has a clearly distinct purpose with no ambiguity, as each targets a specific resource (e.g., channel, user, message, file) and action (e.g., get, list, send, upload). Overlap is minimal, such as slack_get_user_info and slack_get_user_profile, but their descriptions clarify distinct focuses on general info versus profile details.

Naming Consistency5/5

Tool names follow a highly consistent verb_noun pattern throughout, all using snake_case with a 'slack_' prefix and clear action-resource combinations (e.g., slack_get_channel_info, slack_send_message). There are no deviations in style or convention, making them predictable and readable.

Tool Count4/5

With 20 tools, the count is slightly high but reasonable for a comprehensive Slack integration covering channels, users, messages, files, and workspaces. It feels a bit heavy but not excessive, as each tool serves a specific function without obvious redundancy.

Completeness5/5

The tool set provides complete CRUD/lifecycle coverage for the Slack domain, including operations for channels (list, get, send), users (list, get info/profile), messages (send, get, search, react, thread), files (upload, list, get), and workspaces (list, switch, get). No significant gaps are apparent, enabling full agent workflows.

Maintenance

ActivityInactive
ResponsivenessSyncing