Slack MCP Server

Current Config

Entry in ~/.claude.json (HTTP type with static Bearer token):

"slack": {
  "type": "http",
  "url": "https://mcp.slack.com/mcp",
  "headers": {
    "Authorization": "Bearer xoxp-2333731943-2334562442-10676586932945-06c5f078171263519ccc1ba0e6fb7f76"
  }
}

Workspace: Grain & Mortar App Name: Claude MCP (App ID: A0AKE2U68LD) Token type: User token (xoxp-) — allows acting as Eric

User Token Scopes

Scope Purpose
search:read.public Search public channels
search:read.private Search private channels
search:read.files Search files
canvases:read Read Slack canvases
canvases:write Write Slack canvases
channels:history Read public channel history
chat:write Send messages
groups:history Read private channel history
im:history Read DM history
mpim:history Read group DM history
users:read Read user info
users:read.email Read user email addresses

Why This Setup Is Unusual

Most HTTP MCPs use OAuth with mcp-remote as the transport (e.g., Google services). Slack does not support this pattern. Here's why:

  1. mcp-remote requires the auth server to support dynamic client registration (RFC 7591)
  2. Slack's OAuth server only supports client_secret_post token exchange
  3. You can confirm this: curl https://slack.com/.well-known/oauth-authorization-server | jq .token_endpoint_auth_methods_supported
  4. Result: ["client_secret_post"] — PKCE-only dynamic registration is not supported

Therefore: Slack requires a static Bearer token in the HTTP headers. There is no refresh — if the token expires or is revoked, you have to regenerate it.

If the Token Stops Working

  1. Go to api.slack.com/apps/A0AKE2U68LD
  2. Navigate to OAuth & Permissions
  3. Under OAuth Tokens for Your Workspace, click Reinstall to Grain & Mortar
  4. Complete the OAuth flow
  5. Copy the new xoxp- token
  6. Update ~/.claude.json:
# Remove and re-add with new token
claude mcp remove slack -s user
claude mcp add-json slack '{"type":"http","url":"https://mcp.slack.com/mcp","headers":{"Authorization":"Bearer xoxp-NEW-TOKEN-HERE"}}' -s user

How to Create This From Scratch

If the app gets deleted or you need to set this up in a new workspace:

  1. Go to api.slack.com/apps → Create New AppFrom scratch
  2. Name it "Claude MCP", select the target workspace
  3. Go to OAuth & Permissions → scroll to User Token Scopes → add all scopes listed above - Do NOT add Bot Token Scopes — user token scopes are what matters here - Do NOT add admin.users:read — it's Enterprise-only and blocks install
  4. Click Install to Workspace
  5. Copy the xoxp- token from the OAuth Tokens section
  6. Register with Claude Code:
claude mcp add-json slack '{"type":"http","url":"https://mcp.slack.com/mcp","headers":{"Authorization":"Bearer xoxp-TOKEN"}}' -s user

Lessons Learned (the hard way)

Don't try mcp-remote first. The error Incompatible auth server: does not support dynamic client registration is definitive — Slack will never support this. When you see that error, go straight to static Bearer token.

Check /.well-known/oauth-authorization-server before picking an auth strategy. If token_endpoint_auth_methods_supported includes only client_secret_post (not none), mcp-remote won't work. Go Bearer token.

app.slack.com/app-settings/ won't load directly. If you need Chrome MCP to interact with Slack app settings, navigate from within an already-authenticated workspace tab (app.slack.com/client/...), not by opening app-settings directly.

ReactVirtualized dropdowns need mouse events. Slack's scope dropdown uses a virtual list. Standard click events don't work — use Input.dispatchMouseEvent targeting [role="option"] elements by text content.

Enterprise-only scopes block install. admin.users:read silently breaks the install flow. If "Allow" fails, check for orange warning icons on any scope and remove them.

OAuth form submit via CDP: If the Allow button is at the viewport edge and click doesn't register, use document.querySelector('form').submit() instead.