Slack MCP (mcp.slack.com) OAuth stores empty accessToken after completing flow; complete_authentication also broken

Resolved 💬 4 comments Opened May 16, 2026 by Panoplos Closed Jun 15, 2026

Summary

The Slack MCP (https://mcp.slack.com/mcp) cannot be authenticated. The OAuth flow appears to complete successfully (success page shown in browser), but the stored accessToken is always empty. The manual fallback via mcp__slack__complete_authentication also fails. This worked previously (confirmed working on May 13, 2026 via debug logs).

Environment

  • Claude Code version: 2.1.139 (also reproduced after updating)
  • OS: macOS 24.6.0 (Darwin)
  • MCP server: https://mcp.slack.com/mcp

Bug 1: Empty accessToken after OAuth flow

After completing the Slack OAuth flow (clicking Allow, browser shows success page), the token stored in the macOS keychain has an empty accessToken:

security find-generic-password -s "Claude Code-credentials" -w | \
  python3 -c "import sys,json; d=json.loads(sys.stdin.read()); print(d['mcpOAuth'])"

Output:

{'slack|38801a7d845718b3': {'serverName': 'slack', 'serverUrl': 'https://mcp.slack.com/mcp', 'accessToken': '', 'discoveryState': {...}}}

Root cause hypothesis: Slack's oauth/v2_user/authorize endpoint returns the user token nested under authed_user.access_token in the token exchange response, not at the top-level access_token field. If Claude Code's OAuth client reads the top-level field, it stores an empty string.

Debug logs from a working session (May 13) show Token length: 82 and successful connection. After the token expired/was revoked, re-authentication consistently produces accessToken: "".

Bug 2: complete_authentication loses session state between calls

The manual fallback (mcp__slack__complete_authentication) reports "No OAuth flow is in progress for slack" even when called immediately after mcp__slack__authenticate in the same conversation with a matching state parameter.

The state from mcp__slack__authenticate and the captured callback URL match:

  • Generated state: CAz80-nwEtCH5Cq9fpDO2iZ3eFzsOmvxG2VnsR74Fqg
  • Callback URL state: CAz80-nwEtCH5Cq9fpDO2iZ3eFzsOmvxG2VnsR74Fqg

Yet complete_authentication still fails. The session state appears to be lost between the two tool calls, likely because each tool call opens a fresh connection to mcp.slack.com and session state is connection-scoped.

Steps to Reproduce

  1. Add Slack MCP (https://mcp.slack.com/mcp) in Claude Code settings
  2. Attempt to authenticate via the MCP settings dialog or mcp__slack__authenticate
  3. Complete the Slack OAuth flow in browser
  4. Observe success page in browser
  5. Check keychain: accessToken is ""
  6. Slack MCP shows as unauthenticated; repeating auth has same result

Expected Behavior

  • OAuth flow completes and a valid accessToken is stored
  • OR mcp__slack__complete_authentication works as a fallback for cases where localhost:8085 is not reachable

Additional Context

  • mcp-needs-auth-cache.json correctly records Slack as needing auth, but no id field is ever written (unlike other successfully-authenticated MCPs like claude.ai Gmail which get an id field)
  • The automatic localhost:8085 callback handler appears to run (browser redirects away from localhost), but token exchange result is stored incorrectly
  • Other MCPs (Gmail, Google Calendar) authenticate successfully, suggesting the issue is specific to Slack's OAuth token response format

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗