mcp-client-credentials-auth
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-client-credentials-authList all available tools"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-client-credentials-auth
A local stdio MCP server that authenticates to remote OAuth-protected MCP servers using the client_credentials grant, as defined in the MCP OAuth Client Credentials extension.
Drop it into any MCP client configuration and it transparently handles MCP Authorization-based OAuth discovery of the remote MCP Server and its announced Authorization server (IdP), access token acquisition, and MCP request forwarding. Throughout this document, we refer to it as the auth proxy.
This implements the client secrets variant of the MCP OAuth Client Credentials extension, designed for autonomous AI agents, background services, CI/CD pipelines, server-to-server integrations, and daemon processes that need MCP access without the user in the loop.
To obtain the required client_id and client_secret, look for a "Service Account", "API Key", or "Machine-to-Machine Application" option in the account management or developer settings UI provided by the remote MCP service or platform. Most services let end users create these credentials self-service, the exact location and naming varies by provider. The service also controls which scopes and permissions the credentials are granted.
Features
Zero-config OAuth - token endpoint and scopes auto-discovered via MCP Authorization and RFC 9728 / RFC 8414
Transparent forwarding - all MCP methods forwarded bidirectionally (tools, resources, prompts, sampling, notifications)
Proactive token refresh - tokens refreshed before expiry using
refreshSkewSeconds(default 30s) with automatic retries, no MCP request latency spikesTransport fallback - Streamable HTTP with automatic SSE fallback
Resilient startup - starts even when the remote MCP server or IdP is unavailable, connecting automatically when they become reachable
Automatic reconnection - detects remote server disconnects and reconnects with exponential backoff, preserving client identity and capabilities
Live change detection - polls the remote server for capability changes (tools, resources, prompts) and notifies your MCP client automatically
Identity forwarding - remote server name and capabilities forwarded to your MCP client, your client's real identity and capabilities forwarded to the remote MCP server
Timeouts on all network calls - all outgoing connections (MCP requests, OAuth discovery, token acquisition) enforce
requestTimeoutMsto prevent hangsForward-compatible - generic pass-through design (no hardcoded method tables) means new MCP spec versions should work by bumping the SDK dependency only
Related MCP server: IFTTT MCP Proxy
How It Works
MCP Client ←→ [stdio] ←→ mcp-client-credentials-auth ←→ [HTTP/SSE + Bearer] ←→ Remote MCP Server
↓
IdP Token Endpoint
(client_credentials grant)The auth proxy sits between your MCP client and the remote MCP server:
Discovers OAuth metadata from the remote MCP server via RFC 9728 protected resource metadata
Resolves the authorization server (uses the first entry from the
authorization_serversarray in the resource metadata)Acquires tokens using OAuth
client_credentialsgrantForwards all MCP requests/responses with
BearerauthenticationHandles token refresh and 401 retry transparently
If the IdP is temporarily unavailable at startup, the auth proxy will periodically retry OAuth discovery with exponential backoff (5s to 60s) and begin serving requests as soon as discovery succeeds. If the remote MCP server is unreachable at startup, the auth proxy will still start and accept connections from your MCP client, advertising default capabilities (tools, resources, prompts). It will automatically connect to the remote server when it becomes available.
Quick Start
{
"mcpServers": {
"my-remote-server": {
"command": "npx",
"args": ["-y", "mcp-client-credentials-auth"],
"env": {
"MCP_CC_PROXY_REMOTE_MCP_URL": "https://mcp.example.com/mcp",
"MCP_CC_PROXY_CLIENT_ID": "my-service",
"MCP_CC_PROXY_CLIENT_SECRET": "s3cr3t"
}
}
}
}That's it. Token endpoint, auth method, and scopes are all auto-discovered.
Security note: npx command downloads npm package and runs it on your local machine. Use it with trusted packages only!
Configuration
All configuration via MCP_CC_PROXY_* environment variables:
Variable | Required | Default | Description |
| Yes | — | Remote MCP server URL ( |
| Yes | — | OAuth client_id |
| Yes | — | OAuth client_secret |
| No | auto-discovered | Override OAuth scopes sent in the token request (space-separated). When set, discovered |
| No |
| Enable debug logging to stderr |
| No |
| Proactive token refresh window (seconds before token expiry) |
| No |
| Timeout for all outgoing network calls: MCP requests, OAuth discovery, and token acquisition (ms) |
| No |
| Interval to poll remote MCP server for capability changes (0 = disabled) |
Security
Protecting Secrets with Vaults
The Quick Start example puts secrets directly in the MCP client config. These are typically stored on disc as plain text. For better security, fetch them at launch time from a vault or keychain.
1Password CLI
Create a 1Password vault item (e.g. named "My MCP Credentials") with fields client-id and client-secret, then use op run with a template file that contains op:// references to those fields:
# ~/.config/mcp/my-server.env.tpl
MCP_CC_PROXY_REMOTE_MCP_URL=https://mcp.example.com/mcp
# op://<vault>/<item>/<field> - references to 1Password vault item fields
MCP_CC_PROXY_CLIENT_ID=op://Private/My MCP Credentials/client-id
MCP_CC_PROXY_CLIENT_SECRET=op://Private/My MCP Credentials/client-secret{
"mcpServers": {
"my-remote-server": {
"command": "op",
"args": ["run", "--env-file=~/.config/mcp/my-server.env.tpl", "--", "npx", "-y", "mcp-client-credentials-auth"]
}
}
}op run resolves the op:// references at launch, injects the real values as environment variables, and executes the proxy. Secrets never touch the file system.
Bitwarden CLI
Create a Bitwarden vault login item (e.g. named "My MCP Credentials") and store the client_id as the username and client_secret as the password. Then use a wrapper script that fetches them via bw get:
#!/usr/bin/env bash
export MCP_CC_PROXY_REMOTE_MCP_URL="https://mcp.example.com/mcp"
# "My MCP Credentials" is the name of the Bitwarden vault login item
export MCP_CC_PROXY_CLIENT_ID="$(bw get username 'My MCP Credentials')"
export MCP_CC_PROXY_CLIENT_SECRET="$(bw get password 'My MCP Credentials')"
exec npx -y mcp-client-credentials-authSave the script (e.g. ~/.local/bin/mcp-my-server.sh), make it executable, and point your MCP config at it:
{
"mcpServers": {
"my-remote-server": {
"command": "/Users/you/.local/bin/mcp-my-server.sh"
}
}
}Bitwarden must be unlocked (bw unlock) before the MCP client starts the proxy.
macOS Keychain
Store the client secret in the built-in macOS Keychain. The -s flag is the service name (a label you choose to identify this entry), -a is the account name, and -w is the secret value:
security add-generic-password -s "My MCP Credentials" -a "client_secret" -w "my-client-secret"Then use a wrapper script to read it at launch:
#!/usr/bin/env bash
export MCP_CC_PROXY_REMOTE_MCP_URL="https://mcp.example.com/mcp"
# The OAuth client ID assigned by your identity provider
export MCP_CC_PROXY_CLIENT_ID="my-oauth-client-id"
# -s and -a must match the values used in add-generic-password above
export MCP_CC_PROXY_CLIENT_SECRET="$(security find-generic-password -s 'My MCP Credentials' -a 'client_secret' -w)"
exec npx -y mcp-client-credentials-authNo extra software required; the Keychain is built into macOS and protected by your login password or Touch ID.
Runtime Credential Safeguards
Access token is stored only in memory, never logged
Client secrets loaded at startup, never forwarded or logged
Authorization header always set by the auth proxy, never influenced by MCP client content
Auth-like metadata keys (
authorization,token,bearer,access_token,client_secret) stripped from_metain all client-to-server messages (requests and notifications) before forwarding to prevent any influence by MCP Client
Troubleshooting
All auth proxy logs are written to stderr (stdout is reserved for MCP protocol messages). To see them:
Cursor - open the MCP server output panel (Developer: Show MCP Logs)
Claude Desktop - check
~/Library/Logs/Claude/mcp-server-*.log(macOS) or%APPDATA%\Claude\logs\(Windows)Claude Code - logs appear in the terminal with
--mcp-debugflag
Set MCP_CC_PROXY_DEBUG=true for verbose output including OAuth discovery details, message forwarding, and token refresh scheduling.
Token acquired but remote server returns 403
If the proxy acquires a token but the remote server rejects requests, the token likely has fewer scopes than expected. IdPs handle scopes in client_credentials differently:
Silent dropping (Keycloak, Auth0): scopes not assigned to the client in the IdP are quietly removed from the token without an error. The proxy gets a valid token that lacks the permissions the MCP server requires. This is the hardest case to debug.
Strict rejection (Okta, AWS Cognito): requesting a scope not assigned to the client fails the token request immediately with
invalid_scope. Easier to diagnose since the proxy logsToken prefetch failed (will retry on first request)at startup..defaultconvention (Entra ID / Azure AD): individual scope names are not accepted; you must use{resource}/.default. SetMCP_CC_PROXY_SCOPESto override with the.defaultformat; check the remote MCP server's documentation for the exact value. If permissions are still missing, the issue is likely missing admin consent on the app registration; contact the MCP server operator or your Azure AD tenant administrator.
Debugging steps:
Look for the
OAuth discovery completelog line (always printed at startup), itsscopesfield shows thescopes_supportedvalues discovered from the remote server's resource metadata, or(default)if none were advertised.Request a token directly from your IdP's token endpoint (using
curlor your IdP's admin UI), decode it at jwt.io or withjq, and inspect thescopeorscpclaim to see what was actually granted.Compare with the scopes the remote MCP server requires for the failing operation.
If scopes are missing, update the scope grants on your service account in the IdP, or contact the MCP server operator.
Notes for MCP Server Developers
If you operate an MCP server that publishes RFC 9728 Protected Resource Metadata, the scopes_supported field in your .well-known/oauth-protected-resource document is consumed by both interactive clients (authorization code flow) and machine-to-machine clients (client_credentials flow). These two flows can have conflicting scope requirements depending on the IdP. If your setup requires a scope override for client_credentials, document the correct MCP_CC_PROXY_SCOPES value in your user-facing setup instructions.
Recommended approach
List granular, application-level scopes in scopes_supported. These serve the common case (interactive clients) and work with most IdPs:
{
"resource": "https://mcp.example.com/mcp",
"authorization_servers": ["https://auth.example.com"],
"scopes_supported": ["mcp:tools", "mcp:resources", "mcp:prompts"]
}Machine-to-machine clients whose IdP requires a different scope format can override via MCP_CC_PROXY_SCOPES (or equivalent in their tooling) without requiring changes to the server's metadata.
Entra ID (Azure AD) compatibility
Entra ID requires {resource}/.default for client_credentials grants and rejects individual scope names. Since scopes_supported cannot contain both granular scopes (for authorization code flow) and .default (for client_credentials flow) in a way that works for both, the override is the intended solution:
// MCP client config for Entra ID
{
"mcpServers": {
"my-remote-server": {
"command": "npx",
"args": ["-y", "mcp-client-credentials-auth"],
"env": {
"MCP_CC_PROXY_REMOTE_MCP_URL": "https://mcp.example.com/mcp",
"MCP_CC_PROXY_CLIENT_ID": "my-service",
"MCP_CC_PROXY_CLIENT_SECRET": "s3cr3t",
"MCP_CC_PROXY_SCOPES": "api://my-api-client-id/.default"
}
}
}
}Announce all required scopes
List every scope your server uses in scopes_supported. The auth proxy (and the MCP SDK in general) requests the full set on initial token acquisition, which avoids per-operation 403 challenges. This is especially important because the MCP TypeScript SDK has known scope step-up bugs that can cause infinite re-authorization loops when scopes are added incrementally.
Identity and Capabilities Forwarding
The MCP protocol exchanges identity (name, version) and capabilities during the initialize handshake. The auth proxy forwards both in each direction using a two-phase connection strategy:
Discovery phase: the auth proxy connects to the remote server to learn its identity and capabilities, then disconnects.
Local handshake: the auth proxy presents the remote server's identity to your MCP client.
Reconnect phase: after your MCP client identifies itself, the auth proxy reconnects to the remote server with the real client identity (plus a suffix) and the real client capabilities.
Remote server identity → local client: Your MCP client sees the real remote server name in its UI, not the auth proxy.
Local client identity → remote server: The auth proxy automatically forwards your MCP client's name with a suffix indicating its name and version. For example, if Cursor (cursor-vscode v1.0.0) connects through the auth proxy v0.1.0, the remote server sees:
clientInfo.name:"cursor-vscode via mcp-client-credentials-auth v0.1.0"clientInfo.version:"1.0.0"
No configuration is needed; the real client name is introspected from the MCP handshake.
Client capabilities → remote server: The auth proxy forwards the local client's declared capabilities (sampling, roots, elicitation, etc.) to the remote server. This enables server-to-client features like sampling requests and root listing to work through the auth proxy.
Extension announcement: The auth proxy automatically declares the io.modelcontextprotocol/oauth-client-credentials extension in its client capabilities when connecting to the remote server. This signals to the remote server that the connecting client authenticates via the client credentials flow, allowing the server to adjust behavior accordingly (e.g., skip interactive auth prompts, apply machine-to-machine policies). The extension is declared on both the discovery connection and the real connection.
Known Issues
Scope step-up does not work reliably with client_credentials
The MCP TypeScript SDK has known bugs around scope step-up (403 insufficient_scope handling):
Scope overwrite instead of accumulation (typescript-sdk#1582): when multiple operations require different scopes, the transport overwrites the active scope instead of merging, causing infinite re-authorization loops.
fetchTokenignores challenge scope (typescript-sdk#2255): forclient_credentialsgrants,fetchToken()reads the scope from the provider's immutableclientMetadata.scoperather than the scope extracted from theWWW-Authenticateheader. A 403 challenge with a new scope never actually reaches the token endpoint.
These are upstream SDK issues with open PRs, but no released fix as of SDK v1.x.
Workaround: List all scopes your server uses in scopes_supported so the full set is requested on initial token acquisition and no per-operation 403 challenges occur. See Announce all required scopes for details.
Contributing
See CONTRIBUTING.md for development setup, testing, and PR guidelines. See AGENTS.md for architecture and code conventions.
License
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/velias/mcp-client-credentials-auth'
If you have feedback or need assistance with the MCP directory API, please join our Discord server