[BUG] - Hardcoded OAuth callback port 3118 prevents authentication when multiple Claude Code sessions run in parallel

Resolved 💬 2 comments Opened Jun 1, 2026 by ercquest Closed Jun 1, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

I am resubmitting this because it was closed as duplicate, but it is not a duplicate. This is a particularly major issue if you are using devcontainers. I have to bind the port in order to use the Slack MCP. If I want to run multiple devcontainers in different repos (which is something I frequently do), then having the port hardcoded to 3118 means the port binding fails and the container will not build. This makes it not just impossible to use the Slack MCP in multiple Claude sessions, but actually impossible to run two containers which are configured to run the MCP. The only way to start the other container is to remove the port binding, otherwise you get this error on build:

Bind for 127.0.0.1:3118 failed: port is already allocated

Summary

The Slack MCP plugin's OAuth config hardcodes callbackPort: 3118. Because the OAuth callback server binds to this single fixed port, only one Claude Code session on the machine can complete Slack OAuth at a time. Users running multiple parallel sessions (per-project, cmux-managed, detached terminals) hit unrecoverable auth failures whenever another session is already listening on 3118.

Reproduction

  1. Start a Claude Code session (A) that has loaded the Slack plugin. It binds localhost:3118 at some point during Slack MCP lifecycle.
  2. In another terminal, start session B.
  3. In session B, run /mcp and select Slack → Authenticate.
  4. Auth fails with:
Error: OAuth callback port 3118 is already in use — another process may be holding it.
Run `lsof -ti:3118 -sTCP:LISTEN` to find it.
  1. lsof reveals the port is held by another Claude Code process — a sibling session, not malware — with no way to proceed without killing that session.

Config

~/.claude/plugins/cache/claude-plugins-official/slack/1.0.0/.mcp.json:

{
  "mcpServers": {
    "slack": {
      "type": "http",
      "url": "https://mcp.slack.com/mcp",
      "oauth": {
        "clientId": "1601185624273.8899143856786",
        "callbackPort": 3118
      }
    }
  }
}

Root Cause

OAuth 2.0 requires redirect_uri to match a pre-registered value in the Slack OAuth app configuration. The Slack app (client_id: 1601185624273.8899143856786) has http://localhost:3118/callback registered as the only loopback redirect URI, so the MCP client cannot fall back to a different port.

Proposed Solutions (in order of preference)

1. RFC 8252 loopback redirect with wildcard port (recommended)

Per RFC 8252 §7.3, loopback redirect URIs SHOULD allow any port. Register http://127.0.0.1/callback (no port) in the Slack OAuth app and have the MCP client bind to an OS-assigned ephemeral port. This is the idiomatic modern approach and eliminates port collision entirely.

2. Port range fallback (GitHub CLI pattern)

Register a range (e.g., 3118-3127) in the Slack OAuth app, and have the client try each sequentially until one is free. This is what gh, gcloud, heroku, flyctl and many other dev-CLIs do.

3. Device Authorization Grant (RFC 8628)

No callback server needed. User copies a short code from terminal into browser. More user-friction but entirely port-independent. Good fallback if ①/② are blocked by Slack app policy.

4. Short-term UX improvement

The current error message points to lsof -ti:3118 -sTCP:LISTEN but doesn't tell the user that the port is almost always held by a sibling Claude Code session. Adding this context — and ideally offering to SIGTERM the blocking Claude process after confirmation — would reduce frustration significantly while ①/②/③ are being evaluated.

Environment

  • Claude Code: 2.1.114
  • Plugin: claude-plugins-official/slack@1.0.0
  • OS: macOS (Darwin 25.3.0)
  • Usage pattern: 5-10 parallel Claude Code sessions per day (cmux-managed + ad-hoc terminals). Common among heavy users.

Workaround

# Find the blocking Claude session
lsof -i:3118 -sTCP:LISTEN -n -P
# Kill it (destructive to that session)
lsof -ti:3118 -sTCP:LISTEN | xargs kill
# Then retry OAuth in the current session

This works but is destructive to the other session and counterintuitive — nothing in the error message hints that you're being blocked by your own previous Claude process.

Related Issues

  • #37714 — Slack MCP plugin OAuth fails: redirect_uri not registered (different root cause, resolved by Slack OSS team)
  • #37747 — MCP OAuth regression: client metadata document redirect_uris missing port
  • #48993 — Remote HTTP MCP (Slack): forces frequent re-OAuth despite valid refresh tokens

Impact

This affects any user who runs multiple Claude Code sessions simultaneously — a workflow that Anthropic actively supports (project-scoped sessions, cmux, background agents). Without a fix, users must serialize all Slack MCP auth attempts, which contradicts the parallel-session design of the product.

What Should Happen?

The Slack MCP should not be hardcoded against a single port. You should be able to run multiple Claude sessions with the Slack MCP.

Error Messages/Logs

Steps to Reproduce

  1. Create a dev container with the port binding for the Slack MCP (3118)
  2. Build the container
  3. Create a second dev container with the port binding for the Slack MCP (3118)
  4. Attempt to build the second container. It fails

Claude Model

Not sure / Multiple models

Is this a regression?

No, this never worked

Last Working Version

_No response_

Claude Code Version

2.1.140

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Windows Terminal

Additional Information

_No response_

View original on GitHub ↗

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