slack-stdio-mcp
Local MCP stdio bridge to Slack's hosted MCP server, enabling agents to use Slack tools (send messages, search, history, canvas, etc.) via local OAuth and token refresh.
README
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
- Client ID:
- Own app is optional — see Own Slack app
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
- Load credentials for the current
client_id - Reuse access token if valid (5‑minute skew before
expires_at) - Else refresh via
oauth.v2.access(grant_type=refresh_token) - 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):
- Silent force-refresh + reconnect + one retry
- Else open browser and return
SLACK_REAUTH_REQUIREDplus the authorize URL in the tool result (clickable in chat) - 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.
- Slack app → OAuth & Permissions → Redirect URLs must match your
--oauth-*/SLACK_OAUTH_*(e.g.http://localhost:3118/callback) - PKCE Opt In (recommended without
client_secret) - Enable MCP under App Assistant / Agents & AI Apps
(else: App is not enabled for Slack MCP server access) - User Token Scopes must match
USER_SCOPESinsrc/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
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。
mcp-server-qdrant
这个仓库展示了如何为向量搜索引擎 Qdrant 创建一个 MCP (Managed Control Plane) 服务器的示例。