claude-code - 💡(How to fix) Fix [BUG] MCP client ignores MacOS keychain client secret, only uses value of MCP_CLIENT_SECRET environment variable [2 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
anthropics/claude-code#51716Fetched 2026-04-22 07:54:45
View on GitHub
Comments
2
Participants
2
Timeline
8
Reactions
2
Author
Participants
Timeline (top)
labeled ×5commented ×2subscribed ×1

Error Message

Error Messages/Logs

Fix Action

Workaround

Setting MCP_CLIENT_SECRET in the shell environment at Claude Code launch time works: MCP_CLIENT_SECRET="my-secret" claude or via ~/.zprofile: export MCP_CLIENT_SECRET="my-secret"

However this is a single global variable, so it cannot support multiple MCP servers with different client secrets simultaneously.

Code Example

{
  "issuer": "<host>",
  "authorization_endpoint": "<host>/authorize",
  "token_endpoint": "<host>/token",
  "jwks_uri": "<host>/.well-known/jwks.json",
  "token_endpoint_auth_methods_supported": [
     "client_secret_post"
  ],
  "grant_types_supported": [
     "authorization_code"
  ],
  "code_challenge_methods_supported": [
     "S256"
  ],
  "response_types_supported": [
     "code"
  ]
}

---

# Log from oauth server

[token] request {
  grant_type: 'authorization_code',
  client_id: '<client id>',
  redirect_uri: '<callback uri>',
  has_code: true,
  has_verifier: true,
  has_secret: false
}

---

MCP_CLIENT_SECRET="my-secret" claude mcp add-json my-server \
    '{"type":"http","url":"http://localhost:abc/","oauth":{"clientId":"my-client-id"}}' \
    --client-secret

---

security find-generic-password -s "Claude Code-credentials" -w
  # Returns JSON containing:
  # { "mcpOAuthClientConfig": { "my-server|<hash>": { "clientSecret": "..." } } }
RAW_BUFFERClick to expand / collapse

Preflight Checklist

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

What's Wrong?

When adding an HTTP MCP server with --client-secret, Claude Code correctly stores the client secret in the macOS keychain under "Claude Code-credentials". However, during the OAuth token exchange, the client_secret parameter is not included in the POST to the authorization server's /token endpoint, causing the exchange to fail.

The secret is present in the keychain but never retrieved at runtime.

This is for an oauth server with a ASM document with content:

{
  "issuer": "<host>",
  "authorization_endpoint": "<host>/authorize",
  "token_endpoint": "<host>/token",
  "jwks_uri": "<host>/.well-known/jwks.json",
  "token_endpoint_auth_methods_supported": [
     "client_secret_post"
  ],
  "grant_types_supported": [
     "authorization_code"
  ],
  "code_challenge_methods_supported": [
     "S256"
  ],
  "response_types_supported": [
     "code"
  ]
}

Note that this OAuth server does not support DCR.

What Should Happen?

The client_secret stored in the keychain is retrieved and included as client_secret in the POST body of the token exchange request, satisfying client_secret_post authentication.

Error Messages/Logs

# Log from oauth server

[token] request {
  grant_type: 'authorization_code',
  client_id: '<client id>',
  redirect_uri: '<callback uri>',
  has_code: true,
  has_verifier: true,
  has_secret: false
}

Steps to Reproduce

  1. Add an HTTP MCP server that requires client_secret_post OAuth authentication:
 MCP_CLIENT_SECRET="my-secret" claude mcp add-json my-server \
   '{"type":"http","url":"http://localhost:abc/","oauth":{"clientId":"my-client-id"}}' \
   --client-secret
  1. Confirm the secret was stored — it appears in the keychain:
security find-generic-password -s "Claude Code-credentials" -w
# Returns JSON containing:
# { "mcpOAuthClientConfig": { "my-server|<hash>": { "clientSecret": "..." } } }
  1. Start Claude Code and trigger the OAuth flow via /mcp → Authenticate.
  2. Complete the browser-based authorization and observe the token exchange request on the authorization server. The client_secret field is absent from the POST body.

The token exchange POST is sent without client_secret. Authorization servers enforcing client_secret_post reject the request with invalid_request / missing required parameters.

Environment

  • macOS (Darwin 25.4.0)
  • Claude Code (claude-sonnet-4-6)
  • Transport: HTTP with OAuth (client_secret_post)

Claude Model

Sonnet (default)

Is this a regression?

I don't know

Last Working Version

No response

Claude Code Version

2.1.116

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

iTerm2

Additional Information

Workaround

Setting MCP_CLIENT_SECRET in the shell environment at Claude Code launch time works: MCP_CLIENT_SECRET="my-secret" claude or via ~/.zprofile: export MCP_CLIENT_SECRET="my-secret"

However this is a single global variable, so it cannot support multiple MCP servers with different client secrets simultaneously.

extent analysis

TL;DR

The most likely fix is to modify the Claude Code to retrieve the client secret from the keychain and include it in the token exchange request.

Guidance

  • The issue seems to be related to the client secret not being retrieved from the keychain during the OAuth token exchange.
  • Verify that the client secret is correctly stored in the keychain by running the command security find-generic-password -s "Claude Code-credentials" -w.
  • To mitigate the issue, a temporary workaround is to set the MCP_CLIENT_SECRET environment variable at Claude Code launch time, but this only supports a single global variable and cannot be used for multiple MCP servers with different client secrets.
  • Investigate the Claude Code source code to determine why the client secret is not being retrieved from the keychain during the OAuth token exchange.

Example

No code snippet is provided as the issue does not contain enough information to create a specific example.

Notes

The provided workaround using the MCP_CLIENT_SECRET environment variable is not a permanent solution as it only supports a single global variable. A more robust solution would be to modify the Claude Code to retrieve the client secret from the keychain for each MCP server.

Recommendation

Apply the workaround by setting the MCP_CLIENT_SECRET environment variable at Claude Code launch time, but note that this is a temporary solution and a more permanent fix is needed to support multiple MCP servers with different client secrets.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

claude-code - 💡(How to fix) Fix [BUG] MCP client ignores MacOS keychain client secret, only uses value of MCP_CLIENT_SECRET environment variable [2 comments, 2 participants]