Skip to main content
Glama
epdlr
by epdlr

slack-stdio-mcp

Local MCP stdio bridge to Slack’s hosted MCP server (https://mcp.slack.com/mcp).

Proxies the official tool catalog (slack_send_message, search, history, canvas, …) after user OAuth (PKCE) and keeps tokens fresh. It does not reimplement Slack tools.

Approach

Typical result

Host → HTTP mcp.slack.com with built-in OAuth

Often stuck authenticating

Claude Code Slack plugin

Works (partner app + host OAuth)

This bridge (stdio + local OAuth/refresh)

Works for Grok, Cursor, Open Code, Codex, Claude, …

Agent  ──stdio MCP──►  slack-stdio-mcp  ──Bearer──►  mcp.slack.com
                              │
                              ├─ valid access token → reuse
                              ├─ expired + refresh_token → silent refresh
                              └─ no token → browser OAuth (PKCE)

Requirements

  • Node.js ≥ 20 (Windows, macOS, Linux)

  • Default OAuth app: Claude’s partner Slack app (no app setup required)

    • Client ID: 1601185624273.8899143856786

    • Redirect: http://localhost:3118/callback

  • Own app is optional — see Own Slack app

Related MCP server: Slack

Install

npx -y slack-stdio-mcp

First run may open a browser for Slack Allow. Later runs reuse or refresh tokens under the platform credentials directory (see Auth).

Alternative

Command

Latest git main

npx -y github:epdlr/slack-stdio-mcp

From clone

git clone … && npm install && npm start

Configure a host

Prefer npx so you never hardcode a machine path. Put knobs in args (CLI flags beat env; see Configuration).

Set startup_timeout_sec (or equivalent) ≥ 180 so the first OAuth Allow is not killed by the host.

Grok Build (~/.grok/config.toml)

[mcp_servers.slack-stdio]
command = "npx"
args = ["-y", "slack-stdio-mcp"]
enabled = true
startup_timeout_sec = 180

Own Slack app:

[mcp_servers.slack-stdio]
command = "npx"
args = [
  "-y", "slack-stdio-mcp",
  "--client-id", "YOUR.CLIENT.ID",
  "--oauth-host", "127.0.0.1",
  "--oauth-path", "/oauth/callback",
]
enabled = true
startup_timeout_sec = 180

Claude Code / Cursor / similar (JSON)

{
  "mcpServers": {
    "slack-stdio": {
      "command": "npx",
      "args": ["-y", "slack-stdio-mcp"]
    }
  }
}

Add the same optional flags as in the Grok example when using your own app.

Local clone

{
  "mcpServers": {
    "slack-stdio": {
      "command": "node",
      "args": ["/absolute/path/to/slack-stdio-mcp/src/server.mjs"]
    }
  }
}

Auth

On start, if there is no usable token for the active client_id, the bridge opens a browser (PKCE). Credentials are stored per client_id:

OS

Default root

macOS / Linux

~/.config/slack-stdio-mcp ($XDG_CONFIG_HOME honored)

Windows

%APPDATA%\slack-stdio-mcp

Path: …/by-client/<client_id>.json. Override with --creds-dir / SLACK_STDIO_CREDS_DIR. Unix modes 0600/0700 when supported.

Action

How

OAuth only (no MCP)

npm run auth (from a clone)

Skip browser (CI)

--skip-oauth / SLACK_SKIP_OAUTH=1

Inject token

--token / SLACK_MCP_TOKEN

Token lifecycle

  1. Load credentials for the current client_id

  2. Reuse access token if valid (5‑minute skew before expires_at)

  3. Else refresh via oauth.v2.access (grant_type=refresh_token)

  4. On refresh failure: clear that app’s file → OAuth (or fail if skip-oauth)

Mid-session session loss

If a Slack tool fails with an auth error (isError: true or thrown error):

  1. Silent force-refresh + reconnect + one retry

  2. Else open browser and return SLACK_REAUTH_REQUIRED plus the authorize URL in the tool result (clickable in chat)

  3. After Allow, the bridge reconnects in the background — retry the tool

Successful tool payloads are never scanned for auth keywords. Settled re-auth flows are not reused; the next start gets a fresh URL.

Local tool

Purpose

slack_stdio_reauth

Start re-auth; optional wait: true until Allow

slack_stdio_session_status

Pending re-auth + authorize URL if any

Startup OAuth waits up to SLACK_OAUTH_TIMEOUT_MS (default 180000). On timeout the process exits 1 (host must restart). Keep host startup timeout above that value. The authorize URL is always printed on stderr.

Configuration

Precedence: CLI flags > environment > built-in defaults.

CLI flag

Env

Purpose

--client-id <id>

SLACK_CLIENT_ID

OAuth app id (default: Claude partner)

--client-secret <s>

SLACK_CLIENT_SECRET

Confidential apps only

--oauth-host <host>

SLACK_OAUTH_HOST

Redirect host (localhost)

--oauth-path <path>

SLACK_OAUTH_PATH

Redirect path (/callback)

--oauth-port <port>

SLACK_OAUTH_PORT

Loopback port (3118)

--mcp-url <url>

SLACK_MCP_URL

MCP endpoint

--profile <name>

SLACK_STDIO_PROFILE

Named store: ~/.slack-stdio-mcp/profiles/<name> (share across repos)

--creds-dir <dir>

SLACK_STDIO_CREDS_DIR

Absolute credentials root (wins over --profile)

--skip-oauth

SLACK_SKIP_OAUTH=1

Never open browser

--token / --mcp-token

SLACK_MCP_TOKEN

Inject Bearer (tests/CI)

-h / --help

Help on stderr

Env only: SLACK_OAUTH_TIMEOUT_MS, SLACK_ALLOW_LEGACY_TOKEN=1 (flat legacy JSON without client_id).

npx -y slack-stdio-mcp -- --profile user_cl
npx -y slack-stdio-mcp -- --client-id 123.456 --oauth-path /oauth/callback
npx -y slack-stdio-mcp -- --skip-oauth --creds-dir /tmp/empty-creds

Profiles: the same --profile name in every host/repo reuses ~/.slack-stdio-mcp/profiles/<name>/… (no absolute paths in config). Grok does not inject the MCP server key into the process — put the profile string in args yourself (convention: match your team/workspace name).

Platforms

Windows

macOS / Linux

Credentials

%APPDATA%\slack-stdio-mcp

~/.config/… or $XDG_CONFIG_HOME

Open browser

cmd /c start "" "<url>" (URL quoted for &)

open / xdg-open

File modes

omitted (profile ACL)

0600 / 0700

CI: npm test on Ubuntu, Windows, macOS (Node 20 + 22). If the browser cannot open, paste the authorize URL from stderr.

Own Slack app (optional)

Only if you are not using the default Claude partner app.

  1. Slack app → OAuth & Permissions → Redirect URLs must match your --oauth-* / SLACK_OAUTH_* (e.g. http://localhost:3118/callback)

  2. PKCE Opt In (recommended without client_secret)

  3. Enable MCP under App Assistant / Agents & AI Apps
    (else: App is not enabled for Slack MCP server access)

  4. User Token Scopes must match USER_SCOPES in src/oauth-flow.mjs (source of truth; CI checks the README list below)

Scope

Used for

search:read.public

Search public channels

search:read.private

Search private channels

search:read.mpim

Search multi-person DMs

search:read.im

Search 1:1 DMs

search:read.files

Search files

search:read.users

Search users

chat:write

Send messages

channels:history

Public channel history

groups:history

Private channel history

mpim:history

Multi-person DM history

im:history

1:1 DM history

canvases:read / canvases:write

Canvases

users:read / users:read.email

Profiles

reactions:write / reactions:read

Reactions

emoji:read

Custom emoji

files:read

Files

channels:write / groups:write / im:write / mpim:write

Open/manage conversations

channels:read / groups:read / mpim:read

List/metadata

Copy-paste (comma-separated; authorize uses space-separated scope, not user_scope):

search:read.public,search:read.private,search:read.mpim,search:read.im,search:read.files,search:read.users,chat:write,channels:history,groups:history,mpim:history,im:history,canvases:read,canvases:write,users:read,users:read.email,reactions:write,reactions:read,emoji:read,files:read,channels:write,groups:write,im:write,mpim:write,channels:read,groups:read,mpim:read

These are user scopes (xoxp / xoxe.xoxp), not bot scopes. A subset is fine if you only need some tools. Set SLACK_CLIENT_SECRET only if Slack rejects public PKCE exchange.

npx -y slack-stdio-mcp -- \
  --client-id your.client.id \
  --oauth-host 127.0.0.1 \
  --oauth-path /oauth/callback

Scripts

Script

Command

Start bridge

npm start

OAuth only

npm run auth

Tests

npm test

Syntax + English gate

npm run check

Security

See SECURITY.md.

  • Never commit credentials, .env, or token dumps

  • Tokens act as the authorizing user — revoke the app in Slack when done

  • stdout = MCP JSON-RPC only; human logs go to stderr

Contributing

CONTRIBUTING.md · CHANGELOG.md · docs/ARCHITECTURE.md

License

MIT

A
license - permissive license
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    B
    quality
    C
    maintenance
    The most powerful MCP server for Slack Workspaces. This integration supports both Stdio and SSE transports, proxy settings and does not require any permissions or bots being created or approved by Workspace admins 😏.
    2
    1,766
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Interact with Slack Workspaces over the Slack API. Supports stdio and Streamable HTTP transport. Extended from Anthropic's archived server
    8
    912
    75
    MIT

View all related MCP servers

Related MCP Connectors

  • Telegram bridge for your MCP-compatible agent. Bidirectional, no LLM in our stack.

  • Artifact store for AI agents. Hosted OAuth at mcp.artifacta.io/mcp; local stdio via npm/PyPI.

  • MCP connector for iMessage & Contacts via a local Mac agent + Vercel relay

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/epdlr/slack-stdio-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server