diff --git a/docs/toolhive/concepts/auth-framework.mdx b/docs/toolhive/concepts/auth-framework.mdx index e93d3559..740cdb07 100644 --- a/docs/toolhive/concepts/auth-framework.mdx +++ b/docs/toolhive/concepts/auth-framework.mdx @@ -83,10 +83,14 @@ clients a spec-compliant OAuth experience while centralizing the complexity of token acquisition and management. To eliminate the client registration burden, the embedded authorization server -currently implements Dynamic Client Registration (DCR), which the MCP -specification lists as the backward compatibility fallback. Support for Client -ID Metadata Documents, the spec's preferred mechanism for clients and servers -without an existing relationship, is planned. +supports two client registration mechanisms. **Client ID Metadata Document +(CIMD)** is the MCP specification's preferred mechanism: a client presents a +public HTTPS URL as its `client_id`, and the embedded AS fetches and validates +the metadata document at that URL. Clients such as VS Code support CIMD and use +it automatically when the embedded AS advertises support. **Dynamic Client +Registration (DCR, RFC 7591)** is the backward-compatibility fallback. MCP +clients that do not support CIMD call `/oauth/register` to receive a `client_id` +automatically. ## Authentication framework diff --git a/docs/toolhive/concepts/backend-auth.mdx b/docs/toolhive/concepts/backend-auth.mdx index 3c3c8f89..84206a6a 100644 --- a/docs/toolhive/concepts/backend-auth.mdx +++ b/docs/toolhive/concepts/backend-auth.mdx @@ -162,8 +162,9 @@ the external service, obtains tokens on behalf of the user, and automatically forwards the upstream token to the MCP server on each subsequent request. The embedded authorization server runs in-process within the ToolHive proxy with -no separate infrastructure needed. It supports Dynamic Client Registration -(DCR), so MCP clients can register automatically with ToolHive. No manual client +no separate infrastructure needed. It supports Client ID Metadata Documents +(CIMD) and Dynamic Client Registration (DCR), so MCP clients can identify +themselves or register automatically with ToolHive. No manual client configuration in ToolHive is required. For a full explanation of how the OAuth flow works, token storage and diff --git a/docs/toolhive/concepts/embedded-auth-server.mdx b/docs/toolhive/concepts/embedded-auth-server.mdx index 6b4d17df..1f62bcba 100644 --- a/docs/toolhive/concepts/embedded-auth-server.mdx +++ b/docs/toolhive/concepts/embedded-auth-server.mdx @@ -43,9 +43,14 @@ identity provider and those services. From the client's perspective, the embedded authorization server provides a standard OAuth 2.0 experience: -1. If the client is not yet registered, it registers via Dynamic Client - Registration (DCR, RFC 7591), receiving a `client_id` and `client_secret`. No - manual client registration in ToolHive is required. +1. The client identifies itself using one of two mechanisms, with no manual + registration in ToolHive required: + - **Client ID Metadata Document (CIMD):** If CIMD is enabled on the embedded + AS and the client supports it (for example, VS Code), the client presents + its public HTTPS metadata URL as its `client_id`. The embedded AS fetches + and validates the document. + - **Dynamic Client Registration (DCR, RFC 7591):** The client calls + `/oauth/register` to receive a `client_id` dynamically. 2. The client is directed to the ToolHive authorization endpoint. 3. ToolHive redirects the client to the upstream identity provider for authentication (for example, signing in with GitHub or Atlassian). @@ -132,9 +137,12 @@ the OAuth flow. - **In-process execution:** The authorization server runs within the ToolHive proxy with no separate infrastructure or sidecar containers. -- **Dynamic Client Registration (DCR):** Supports OAuth 2.0 DCR (RFC 7591), - allowing MCP clients to register automatically. No manual client registration - in ToolHive is required. +- **Client ID Metadata Document (CIMD):** When enabled, accepts HTTPS URLs as + `client_id` values and resolves client metadata on demand. Clients that + support CIMD (such as VS Code) use it automatically. +- **Dynamic Client Registration (DCR):** Supports OAuth 2.0 DCR (RFC 7591) as a + fallback for clients that do not support CIMD. MCP clients register + automatically with no manual configuration in ToolHive. - **Direct upstream redirect:** Redirects clients directly to the upstream provider for authentication (for example, GitHub or Atlassian). - **Configurable signing keys:** JWTs are signed with keys you provide, @@ -196,6 +204,68 @@ If you also set `baselineClientScopes`, those scopes apply to CIMD-resolved clients too. Because CIMD clients can be resolved from arbitrary HTTPS URLs, keep the baseline narrow. +### Two-layer architecture + +The client's CIMD identity is used only within the embedded AS. The embedded AS +uses its own pre-configured upstream credentials when redirecting to the +upstream identity provider. + +```mermaid +sequenceDiagram + participant Client as VS Code
(CIMD client_id) + participant EmbeddedAS as Embedded AS + participant IDP as Upstream IDP + + Note over Client,EmbeddedAS: Leg 1: CIMD + Client->>EmbeddedAS: client_id = https://vscode.dev/oauth/client-metadata.json + EmbeddedAS->>EmbeddedAS: Fetch and validate CIMD document + EmbeddedAS-->>Client: Redirect to upstream IDP + + Note over EmbeddedAS,IDP: Leg 2: AS own credentials + Client->>IDP: Authenticate + IDP-->>EmbeddedAS: Authorization code + EmbeddedAS->>IDP: Exchange (AS's own client_id + secret) + EmbeddedAS-->>Client: Issue ToolHive JWT +``` + +The upstream IDP never sees the client's CIMD URL. This means you must still +configure an upstream client ID and secret for the embedded AS regardless of +whether clients use CIMD or DCR. + +### Document validation + +The embedded AS enforces the following rules on fetched CIMD documents: + +- The URL must use `https` (loopback `http://localhost` is accepted in + development environments only). +- The `client_id` field inside the document must exactly match the URL it was + fetched from. +- `redirect_uris` must be present and pass strict validation. +- Symmetric shared-secret `token_endpoint_auth_method` values are forbidden. +- `grant_types` must include `authorization_code` and be a subset of + `[authorization_code, refresh_token]`. +- `response_types` must be a subset of `[code]`. +- Declared scopes must be a subset of the AS's configured `scopes_supported` + list (when set). + +The fetcher also applies SSRF protection: DNS resolution runs before dialing, +private IP ranges are blocked, redirects are not followed, and each fetch is +subject to a five-second timeout and a 10 KB response cap. + +### Verify CIMD is enabled + +After applying the configuration, confirm that the discovery document advertises +CIMD support: + +```bash +curl -s https:///.well-known/oauth-authorization-server | \ + python3 -m json.tool | grep client_id_metadata_document +``` + +Replace `` with the `issuer` value from your +`MCPExternalAuthConfig`. You should see +`"client_id_metadata_document_supported": true`. + ## Session storage By default, session storage is in-memory. Upstream tokens are lost when pods diff --git a/docs/toolhive/concepts/vmcp.mdx b/docs/toolhive/concepts/vmcp.mdx index 992c805c..3ca0361c 100644 --- a/docs/toolhive/concepts/vmcp.mdx +++ b/docs/toolhive/concepts/vmcp.mdx @@ -142,9 +142,9 @@ vMCP can also run an embedded authorization server that handles the full OAuth flow with multiple upstream identity providers (such as GitHub, Google, or Okta). This enables per-user backend authentication: when a user logs in, the auth server acquires tokens from each upstream provider and injects them into -requests to the appropriate backends. MCP clients register automatically through -Dynamic Client Registration (DCR), so no manual client configuration is needed. -See +requests to the appropriate backends. MCP clients register or identify +themselves automatically through Client ID Metadata Documents (CIMD) or Dynamic +Client Registration (DCR), so no manual client configuration is needed. See [Authentication](../guides-vmcp/authentication.mdx#embedded-authorization-server) for setup details. diff --git a/docs/toolhive/guides-k8s/auth-k8s.mdx b/docs/toolhive/guides-k8s/auth-k8s.mdx index 2a05570f..d87af2c6 100644 --- a/docs/toolhive/guides-k8s/auth-k8s.mdx +++ b/docs/toolhive/guides-k8s/auth-k8s.mdx @@ -1185,6 +1185,39 @@ kubectl describe mcpserver -n toolhive-system `kubectl logs -n toolhive-system -l app.kubernetes.io/name=toolhive-operator` - Verify the operator is running: `kubectl get pods -n toolhive-system` +**CIMD client not using CIMD (falling back to DCR):** + +- Verify `cimd.enabled: true` is set in the `MCPExternalAuthConfig` and the + operator has reconciled the change: + `kubectl describe mcpexternalauthconfig -n toolhive-system` +- Confirm the discovery document advertises CIMD support: + ```bash + curl -s https:///.well-known/oauth-authorization-server | \ + python3 -m json.tool | grep client_id_metadata_document + ``` + Replace `` with the `issuer` value from your + `MCPExternalAuthConfig`. You should see + `"client_id_metadata_document_supported": true`. +- Restart the proxy runner pod after updating an existing resource. + +**CIMD authentication failing with `invalid_client`:** + +- The `client_id` field inside the fetched document must exactly match the URL + used to fetch it. +- Documents must not declare `token_endpoint_auth_method` values that use a + symmetric shared secret (`client_secret_post`, `client_secret_basic`, + `client_secret_jwt`). +- `grant_types` must include `authorization_code`. `response_types` must only + contain `code`. +- `redirect_uris` must be present and valid. + +**CIMD fetch failing (egress / timeout):** + +- The proxy runner pod needs outbound HTTPS access to the client's metadata URL + (for example, `https://vscode.dev`). Check cluster egress policies. +- Fetches time out after five seconds. Ensure the metadata host is reachable + from within the cluster. +
diff --git a/docs/toolhive/guides-ui/run-mcp-servers.mdx b/docs/toolhive/guides-ui/run-mcp-servers.mdx index 73e3f740..c224384d 100644 --- a/docs/toolhive/guides-ui/run-mcp-servers.mdx +++ b/docs/toolhive/guides-ui/run-mcp-servers.mdx @@ -151,13 +151,17 @@ remaining required information and adjust any optional settings as needed: 1. **Authorization method**: Choose how ToolHive should authenticate with the remote server.\ The default is **Auto-Discovered**. Use this option for MCP servers that - fully implement the MCP authorization spec including dynamic client - registration (RFC7591) or for servers that do not require authentication. - ToolHive automatically: - - Discovers OAuth/OIDC endpoints - - Registers a new OAuth client - - Obtains and manages client credentials - - Handles token lifecycle automatically + implement the MCP authorization spec or for servers that do not require + authentication. ToolHive automatically discovers OAuth/OIDC endpoints and + identifies itself using whichever mechanism the server supports: + - **Client ID Metadata Document (CIMD):** If the server's discovery document + sets `client_id_metadata_document_supported: true`, ToolHive presents + [`https://toolhive.dev/oauth/client-metadata.json`](https://toolhive.dev/oauth/client-metadata.json) + as the `client_id`. No registration round-trip is needed. + - **Dynamic Client Registration (DCR, RFC 7591):** When CIMD is unavailable + or rejected, ToolHive registers an OAuth client dynamically. + + Either path handles token acquisition and lifecycle automatically. For MCP servers that accept a bearer token in the `Authorization` header, select **Bearer Token**. ToolHive stores the token securely and sends it as @@ -459,13 +463,17 @@ On the configuration form, enter: 6. **Authorization method**: Choose how ToolHive should authenticate with the remote server.\ The default is **Auto-Discovered**. Use this option for MCP servers that - fully implement the MCP authorization spec including dynamic client - registration (RFC7591) or for servers that do not require authentication. - ToolHive automatically: - - Discovers OAuth/OIDC endpoints - - Registers a new OAuth client - - Obtains and manages client credentials - - Handles token lifecycle automatically + implement the MCP authorization spec or for servers that do not require + authentication. ToolHive automatically discovers OAuth/OIDC endpoints and + identifies itself using whichever mechanism the server supports: + - **Client ID Metadata Document (CIMD):** If the server's discovery document + sets `client_id_metadata_document_supported: true`, ToolHive presents + [`https://toolhive.dev/oauth/client-metadata.json`](https://toolhive.dev/oauth/client-metadata.json) + as the `client_id`. No registration round-trip is needed. + - **Dynamic Client Registration (DCR, RFC 7591):** When CIMD is unavailable + or rejected, ToolHive registers an OAuth client dynamically. + + Either path handles token acquisition and lifecycle automatically. For MCP servers that accept a bearer token in the `Authorization` header, select **Bearer Token**. ToolHive stores the token securely and sends it as diff --git a/docs/toolhive/guides-vmcp/authentication.mdx b/docs/toolhive/guides-vmcp/authentication.mdx index ecea981e..7ce9c0d0 100644 --- a/docs/toolhive/guides-vmcp/authentication.mdx +++ b/docs/toolhive/guides-vmcp/authentication.mdx @@ -397,10 +397,13 @@ stored upstream tokens for backends. Use the embedded authorization server when your backend MCP servers call external APIs on behalf of individual users and no federation relationship -exists between your identity provider and those services. It also provides OAuth +exists between your identity provider and those services. It also supports OAuth 2.0 Dynamic Client Registration +([RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591)) and Client ID +Metadata Documents (CIMD) and Dynamic Client Registration ([RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591)), so MCP clients can -register automatically without manual client configuration in ToolHive. +identify themselves or register automatically without manual client +configuration in ToolHive. :::info