Summary
Add and validate support for OAuth Client ID Metadata Documents (CIMD) for the hosted MCP Cloudflare OAuth proxy.
CIMD lets OAuth clients use an HTTPS URL as their client_id, where that URL serves the client metadata document. In MCP 2025-11-25, clients and authorization servers SHOULD support CIMD; Dynamic Client Registration is now a MAY fallback for compatibility.
Current State
Confirmed from source inspection:
@cloudflare/workers-oauth-provider supports CIMD in the version currently installed by this repo (0.3.0) and in the latest published version (0.8.0).
- The provider requires both:
clientIdMetadataDocumentEnabled: true
- the Workers
global_fetch_strictly_public compatibility flag
- Our
wrangler.jsonc, wrangler.canary.jsonc, and wrangler.test.jsonc already include global_fetch_strictly_public.
- Our Cloudflare OAuth proxy does not currently pass
clientIdMetadataDocumentEnabled: true to new OAuthProvider(...).
- Our path-scoped authorization-server metadata compatibility shim does not advertise
client_id_metadata_document_supported.
- Our protected-resource metadata implementation is separate and already path-scoped for
/mcp....
- The MCP TypeScript SDK has client-side CIMD support in
@modelcontextprotocol/sdk@1.26.0: it checks client_id_metadata_document_supported, uses provider.clientMetadataUrl as the client_id when available, and falls back to Dynamic Client Registration otherwise.
- I did not find equivalent direct CIMD support in
@ai-sdk/mcp@1.0.52.
- Our repo-local
mcp-test-client always uses Dynamic Client Registration today.
Relevant files:
packages/mcp-cloudflare/src/server/index.ts
packages/mcp-cloudflare/src/server/authorization-server-metadata.ts
packages/mcp-cloudflare/src/server/protected-resource-metadata.ts
packages/mcp-cloudflare/wrangler*.jsonc
packages/mcp-test-client/src/auth/oauth.ts
Goals
- Enable CIMD support in the hosted Cloudflare OAuth proxy.
- Advertise CIMD support consistently through authorization-server metadata.
- Preserve Dynamic Client Registration fallback for clients that do not support CIMD.
- Keep path-scoped MCP resource behavior intact for
/mcp, /mcp/{org}, and /mcp/{org}/{project}.
- Add focused tests that prove the behavior and guard the security-sensitive edge cases.
Non-Goals
- Do not remove Dynamic Client Registration.
- Do not change stdio auth; stdio uses Sentry device-code auth and is unrelated to CIMD.
- Do not implement a custom CIMD fetcher unless the Cloudflare provider behavior proves insufficient.
- Do not add enterprise-managed authorization or ID-JAG support as part of this work.
Proposed Plan
1. Enable Cloudflare provider support
- Add
clientIdMetadataDocumentEnabled: true to new OAuthProvider(...) in packages/mcp-cloudflare/src/server/index.ts.
- Keep the existing
global_fetch_strictly_public flag in all Wrangler configs.
- Confirm local/test runtime exposes the flag sufficiently for provider metadata to report support.
2. Advertise support in metadata
-
Verify root authorization metadata from the Cloudflare provider reports:
{
"client_id_metadata_document_supported": true
}
-
Update createScopedAuthorizationServerMetadataResponse(...) so path-scoped compatibility metadata also includes client_id_metadata_document_supported: true.
-
Ensure scoped metadata still includes the resource-bound authorization endpoint for /mcp... URLs.
3. Add server behavior tests
Add Cloudflare package tests covering:
/.well-known/oauth-authorization-server includes client_id_metadata_document_supported: true.
/.well-known/oauth-authorization-server/mcp includes client_id_metadata_document_supported: true.
/.well-known/oauth-authorization-server/mcp/{org}/{project} includes client_id_metadata_document_supported: true.
- Existing protected-resource metadata still returns the exact path/query resource identifier.
- Existing
WWW-Authenticate patching still points to path-specific protected-resource metadata.
4. Add CIMD flow tests
Use mocked fetch or worker test harness support to simulate a client metadata URL.
Cover successful flow:
- Authorization request uses
client_id=https://client.example/oauth/client.json.
- Provider fetches the metadata document.
- Metadata document includes matching
client_id, client_name, redirect_uris, grant_types, response_types, and token_endpoint_auth_method: "none".
- Authorization request redirect URI is accepted only when listed in the fetched metadata document.
Cover failure cases:
- Metadata URL fetch returns non-200.
- Metadata document
client_id does not exactly match the metadata URL.
- Metadata document has no
redirect_uris.
- Authorization request uses a redirect URI not present in the metadata document.
- Metadata document uses disallowed
token_endpoint_auth_method, such as client_secret_post.
- Oversized metadata response is rejected by provider behavior if feasible to exercise.
5. Review consent and phishing UX
CIMD changes what the user sees during OAuth consent because the client identity is now fetched from a URL.
Review the authorization approval UI and tests to ensure it displays enough information for user trust decisions:
- client name
- client metadata host or full client ID URL
- redirect URI hostname
- warnings or clear treatment for localhost redirect URIs
If existing UI only shows the friendly client name, add the hostname/redirect host before enabling broadly.
6. Decide whether to update repo-local test client
The current mcp-test-client is DCR-only. Options:
- Leave it as DCR-only and rely on dedicated Cloudflare tests for CIMD.
- Add optional CIMD support with a
clientMetadataUrl config/flag so it can exercise the new path end-to-end.
If we update it, also fix the adjacent MCP 2025-11-25 drift where token requests should include the RFC 8707 resource parameter; it currently sends resource on authorization but not token exchange.
7. Validate against real clients
After unit/integration tests:
- Test with an MCP SDK OAuth client configured with
clientMetadataUrl.
- Verify the SDK chooses CIMD when metadata advertises support.
- Verify the same SDK falls back to DCR when the flag is disabled or metadata omits support.
- Test at least one non-CIMD client to confirm DCR remains working.
8. Rollout
- Prefer canary first.
- Watch OAuth telemetry for:
- invalid client errors
- metadata fetch failures
- redirect URI validation failures
- registration volume changes
- If canary is clean, enable in production.
Acceptance Criteria
- Cloudflare OAuth metadata advertises
client_id_metadata_document_supported: true when CIMD is enabled.
- Path-scoped authorization metadata advertises the same support.
- URL-based
client_id authorization requests work when the metadata document is valid.
- Invalid metadata documents fail safely.
- Redirect URIs are validated against fetched metadata.
- Dynamic Client Registration still works.
- Existing scoped MCP OAuth flows continue to bind the correct
/mcp... resource.
- Tests cover success and key failure cases.
pnpm run tsc && pnpm run lint && pnpm run test passes before merge.
Open Questions
- Should CIMD be always-on in production once tests pass, or controlled by an env flag for staged rollout?
- Do we need additional allowlist/trust policy controls for client metadata domains, or is open CIMD acceptable for our hosted MCP server?
- Should the repo-local
mcp-test-client gain first-class CIMD support, or is that better left to SDK/client compatibility QA?
- Should we upgrade
@cloudflare/workers-oauth-provider from 0.3.0 to 0.8.0 before enabling this, given newer versions include related metadata/resource handling improvements?
References
Summary
Add and validate support for OAuth Client ID Metadata Documents (CIMD) for the hosted MCP Cloudflare OAuth proxy.
CIMD lets OAuth clients use an HTTPS URL as their
client_id, where that URL serves the client metadata document. In MCP2025-11-25, clients and authorization servers SHOULD support CIMD; Dynamic Client Registration is now a MAY fallback for compatibility.Current State
Confirmed from source inspection:
@cloudflare/workers-oauth-providersupports CIMD in the version currently installed by this repo (0.3.0) and in the latest published version (0.8.0).clientIdMetadataDocumentEnabled: trueglobal_fetch_strictly_publiccompatibility flagwrangler.jsonc,wrangler.canary.jsonc, andwrangler.test.jsoncalready includeglobal_fetch_strictly_public.clientIdMetadataDocumentEnabled: truetonew OAuthProvider(...).client_id_metadata_document_supported./mcp....@modelcontextprotocol/sdk@1.26.0: it checksclient_id_metadata_document_supported, usesprovider.clientMetadataUrlas theclient_idwhen available, and falls back to Dynamic Client Registration otherwise.@ai-sdk/mcp@1.0.52.mcp-test-clientalways uses Dynamic Client Registration today.Relevant files:
packages/mcp-cloudflare/src/server/index.tspackages/mcp-cloudflare/src/server/authorization-server-metadata.tspackages/mcp-cloudflare/src/server/protected-resource-metadata.tspackages/mcp-cloudflare/wrangler*.jsoncpackages/mcp-test-client/src/auth/oauth.tsGoals
/mcp,/mcp/{org}, and/mcp/{org}/{project}.Non-Goals
Proposed Plan
1. Enable Cloudflare provider support
clientIdMetadataDocumentEnabled: truetonew OAuthProvider(...)inpackages/mcp-cloudflare/src/server/index.ts.global_fetch_strictly_publicflag in all Wrangler configs.2. Advertise support in metadata
Verify root authorization metadata from the Cloudflare provider reports:
{ "client_id_metadata_document_supported": true }Update
createScopedAuthorizationServerMetadataResponse(...)so path-scoped compatibility metadata also includesclient_id_metadata_document_supported: true.Ensure scoped metadata still includes the resource-bound authorization endpoint for
/mcp...URLs.3. Add server behavior tests
Add Cloudflare package tests covering:
/.well-known/oauth-authorization-serverincludesclient_id_metadata_document_supported: true./.well-known/oauth-authorization-server/mcpincludesclient_id_metadata_document_supported: true./.well-known/oauth-authorization-server/mcp/{org}/{project}includesclient_id_metadata_document_supported: true.WWW-Authenticatepatching still points to path-specific protected-resource metadata.4. Add CIMD flow tests
Use mocked fetch or worker test harness support to simulate a client metadata URL.
Cover successful flow:
client_id=https://client.example/oauth/client.json.client_id,client_name,redirect_uris,grant_types,response_types, andtoken_endpoint_auth_method: "none".Cover failure cases:
client_iddoes not exactly match the metadata URL.redirect_uris.token_endpoint_auth_method, such asclient_secret_post.5. Review consent and phishing UX
CIMD changes what the user sees during OAuth consent because the client identity is now fetched from a URL.
Review the authorization approval UI and tests to ensure it displays enough information for user trust decisions:
If existing UI only shows the friendly client name, add the hostname/redirect host before enabling broadly.
6. Decide whether to update repo-local test client
The current
mcp-test-clientis DCR-only. Options:clientMetadataUrlconfig/flag so it can exercise the new path end-to-end.If we update it, also fix the adjacent MCP
2025-11-25drift where token requests should include the RFC 8707resourceparameter; it currently sendsresourceon authorization but not token exchange.7. Validate against real clients
After unit/integration tests:
clientMetadataUrl.8. Rollout
Acceptance Criteria
client_id_metadata_document_supported: truewhen CIMD is enabled.client_idauthorization requests work when the metadata document is valid./mcp...resource.pnpm run tsc && pnpm run lint && pnpm run testpasses before merge.Open Questions
mcp-test-clientgain first-class CIMD support, or is that better left to SDK/client compatibility QA?@cloudflare/workers-oauth-providerfrom0.3.0to0.8.0before enabling this, given newer versions include related metadata/resource handling improvements?References
global_fetch_strictly_public: https://developers.cloudflare.com/workers/configuration/compatibility-flags/#global-fetch-strictly-public