feat: support Client ID Metadata Document (CIMD) for OAuth#8550
Conversation
Add CIMD support so Goose can connect to MCP servers that support CIMD-based OAuth without requiring manual client registration or DCR. - Host a client metadata JSON document that will be served at https://goose-docs.ai/oauth/client-metadata.json - Use rmcp's start_authorization_with_metadata_url() to pass the CIMD URL into the OAuth flow, with transparent DCR fallback
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d3e85b6ff8
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
The actual redirect URI sent during the OAuth flow includes /oauth_callback, so the CIMD document must match. RFC 8252 allows dynamic ports for loopback, but the path must be consistent.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2827ff60a0
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Per documentation/AGENTS.md brand guidelines, the product name should always use a lowercase "g".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9030336842
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| { | ||
| "client_id": "https://goose-docs.ai/oauth/client-metadata.json", | ||
| "client_name": "goose", | ||
| "redirect_uris": ["http://localhost/oauth_callback"], |
There was a problem hiding this comment.
Align metadata redirect URI with runtime callback URI
The OAuth flow sends redirect_uri as http://localhost:{port}/oauth_callback with an ephemeral port (crates/goose/src/oauth/mod.rs line 83), but this metadata document only registers http://localhost/oauth_callback. On authorization servers that enforce exact redirect URI matching for Client ID Metadata Documents, authorization will fail with an invalid redirect URI. Fresh evidence: rmcp’s URL-based client-id path (AuthorizationSession::new in transport/auth.rs, lines 2129-2148 on docs.rs) uses the metadata URL directly when client_id_metadata_document_supported=true and does not fall back to DCR in that branch, so this mismatch is terminal.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
This specific issue is invalid, though it does reveal another issue. RFC 8252 Section 7.3 says that for URLs pointing at loopback IP literals, any port can be used at the time of the request. However, we're using localhost and not an IP literal. Fixed.
RFC 8252 Section 7.3 specifies that dynamic port allowance applies to loopback IP literals (127.0.0.1, [::1]), not "localhost". Switch the redirect URI from localhost to 127.0.0.1, and whitelist both IPv4 and IPv6 loopback addresses in the CIMD document. Existing DCR-registered credentials using localhost will be treated as stale and re-registered on next auth.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d396ce9a2d
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Remove the "scope" field — goose passes an empty scope list and lets the server advertise required scopes. Hardcoding "openid profile email" would cause invalid_scope errors on MCP servers with different scope requirements. Add "refresh_token" to grant_types since goose attempts token refresh on startup via stored credentials.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ff7d059e5f
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| .start_authorization_with_metadata_url( | ||
| &[], | ||
| redirect_uri.as_str(), | ||
| Some("goose"), | ||
| Some(CLIENT_METADATA_URL), |
There was a problem hiding this comment.
Preserve DCR fallback when CIMD URL cannot be fetched
Passing Some(CLIENT_METADATA_URL) unconditionally forces rmcp down the URL-based client-id path whenever the server advertises client_id_metadata_document_supported; in AuthorizationSession::new, that branch does not fall back to register_client if the authorization server later fails to resolve the metadata URL. In environments where the server has restricted egress (common for private/enterprise MCP deployments), OAuth now fails even though dynamic client registration would have worked before this change.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
A server which cannot fetch CIMD documents but nonetheless advertises support for CIMD is misconfigured; it's not the client's responsibility to work around that.
| let mut oauth_state = OAuthState::new(mcp_server_url, None).await?; | ||
|
|
||
| let redirect_uri = format!("http://localhost:{}/oauth_callback", used_addr.port()); | ||
| let redirect_uri = format!("http://127.0.0.1:{}/oauth_callback", used_addr.port()); |
There was a problem hiding this comment.
This change is because we use a dynamic port. RFC 8252 Section 7.3 says that a redirect URL listed in a CIMD which points at a loopback IP literal matches the same URL with any port, but this behaviour is explicitly only for loopback IP literals, not for localhost.
Summary
Add CIMD (Client ID Metadata Document) support so Goose can connect to MCP servers that support CIMD-based OAuth (SEP-991) without requiring manual client registration or Dynamic Client Registration.
documentation/static/oauth/client-metadata.json, which will be served athttps://goose-docs.ai/oauth/client-metadata.jsonvia the existing docs deploymentstart_authorization_with_metadata_url(), passing the CIMD URL. Servers that support CIMD will use it; others fall back to DCR transparently.Testing
cargo build -p goosecompiles successfullycargo test -p goosepasses (3 pre-existing unrelated failures)Related Issues
Relates to #7071