Enable CIMD on the embedded authorization server
This guide shows you how to enable Client ID Metadata Document (CIMD) support on
the ToolHive embedded authorization server. With CIMD enabled, MCP clients that
host a public metadata document — such as VS Code
(https://vscode.dev/oauth/client-metadata.json) — can authenticate without
registering through the /oauth/register endpoint first.
CIMD support on the embedded AS requires Kubernetes and the ToolHive Operator.
It is not available for standalone thv run deployments.
For the conceptual background on CIMD, including the two-layer architecture and security model, see Client ID Metadata Documents (CIMD).
The cimd field on MCPExternalAuthConfig is available from the version of the
ToolHive Operator that includes this feature. Check the
ToolHive release notes to
confirm the minimum required version before applying this configuration.
Prerequisites
- Kubernetes cluster with the ToolHive Operator installed
- An existing
MCPExternalAuthConfigresource withtype: embeddedAuthServerand at least one upstream provider configured (see Set up embedded authorization server authentication) kubectlaccess to your cluster
Enable CIMD
Add a cimd block to the embeddedAuthServer section of your
MCPExternalAuthConfig resource and set enabled: true.
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPExternalAuthConfig
metadata:
name: my-embedded-auth-server
namespace: toolhive-system
spec:
type: embeddedAuthServer
embeddedAuthServer:
issuer: https://auth.example.com
upstreamProviders:
- name: github
type: oidc
oidcConfig:
issuerUrl: https://github.com
clientId: your-github-client-id
clientSecretRef:
name: github-client-secret
key: client_secret
cimd:
enabled: true
Apply the updated resource:
kubectl apply -f my-embedded-auth-server.yaml
The embedded AS begins advertising client_id_metadata_document_supported: true
in its OAuth discovery documents (/.well-known/oauth-authorization-server and
/.well-known/openid-configuration). MCP clients that read discovery metadata
will use CIMD automatically.
Configure cache settings
The embedded AS caches fetched CIMD documents to avoid an outbound HTTP request on every authorization. Two fields control the cache:
| Field | Default | Description |
|---|---|---|
cacheMaxSize | 256 | Maximum number of CIMD documents held in the LRU cache. When the cache is full, the least-recently-used entry is evicted. |
cacheFallbackTtl | 5m | Fixed TTL for each cached document. Cache-Control header parsing is not yet implemented; all entries use this value. |
Adjust these values based on the number of distinct MCP clients you expect and how quickly you need metadata changes to take effect:
cimd:
enabled: true
cacheMaxSize: 512
cacheFallbackTtl: '10m'
Setting cacheFallbackTtl to a shorter value causes more frequent outbound
fetches to the client's metadata URL. Setting it to a longer value means a
client's metadata changes (for example, adding a new redirect URI) take longer
to propagate. Until Cache-Control header parsing is implemented,
cacheFallbackTtl is the only way to control cache lifetime.
Verify the configuration
Confirm that the embedded AS is advertising CIMD support in its discovery document. Port-forward to the proxy service and query the well-known endpoint:
# Replace <mcp-server-name> with the name of your MCPServer resource
kubectl port-forward -n toolhive-system svc/mcp-<mcp-server-name>-proxy 8080:8080 &
curl -s http://localhost:8080/.well-known/oauth-authorization-server | \
python3 -m json.tool | grep client_id_metadata_document
You should see:
"client_id_metadata_document_supported": true
Complete example
The following example shows a full MCPExternalAuthConfig with CIMD enabled,
custom cache settings, and an OIDC upstream provider:
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPExternalAuthConfig
metadata:
name: my-embedded-auth-server
namespace: toolhive-system
spec:
type: embeddedAuthServer
embeddedAuthServer:
issuer: https://auth.example.com
upstreamProviders:
- name: default
type: oidc
oidcConfig:
issuerUrl: https://accounts.google.com
clientId: your-google-client-id
clientSecretRef:
name: google-oauth-secret
key: client_secret
baselineClientScopes:
- openid
- offline_access
cimd:
enabled: true
cacheMaxSize: 256
cacheFallbackTtl: '5m'
baselineClientScopes and CIMD work independently. Baseline scopes are unioned
into every client's registered scope set — this applies equally to
DCR-registered clients and to CIMD-resolved clients. Keep your baseline scopes
narrow to avoid granting unexpected permissions to dynamically resolved
third-party clients.
Troubleshooting
VS Code is not using CIMD
VS Code reads the OAuth discovery document when it first connects to an MCP
server. If client_id_metadata_document_supported is absent or false, VS Code
falls back to DCR. Check that:
cimd.enabledis set totruein theMCPExternalAuthConfig.- The resource has been applied and the operator has reconciled it:
kubectl describe mcpexternalauthconfig my-embedded-auth-server -n toolhive-system
- The proxy runner pod has restarted after the configuration change if you updated an existing resource.
CIMD authentication is failing with invalid_client
The embedded AS rejects CIMD documents that fail validation. Common causes:
- The
client_idfield inside the fetched document does not exactly match the URL used to fetch it. The client's metadata document must be self-consistent. - The document declares a
token_endpoint_auth_methodthat uses a symmetric shared secret (client_secret_post,client_secret_basic,client_secret_jwt). CIMD clients cannot use shared-secret authentication methods. - The document declares
grant_typesthat do not includeauthorization_code, or declares aresponse_typeother thancode. - The
redirect_urisfield is empty or contains a URI that fails strict validation.
The embedded AS cannot reach the client's metadata URL
The embedded AS makes an outbound HTTPS request to fetch the CIMD document. If
your cluster has egress restrictions, ensure that the proxy runner pod has
network access to https://vscode.dev (or whichever host the client uses). The
fetch uses a five-second timeout; if the fetch times out, the authorization
request fails with an error.
Related information
- Client ID Metadata Documents (CIMD) — conceptual overview, two-layer architecture, and security model
- Embedded authorization server — full description of the embedded AS, DCR, token forwarding, and session storage
- Set up embedded authorization server authentication — initial embedded AS setup before adding CIMD