From 1b027daea940bbe336c07e12c0c2b43b1a7becc0 Mon Sep 17 00:00:00 2001 From: Sam Morrow Date: Tue, 4 Aug 2026 22:37:19 +0200 Subject: [PATCH] Forward OAuth client metadata URL Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- rust/src/types.rs | 44 ++++++++++++++++++++++++++++++++++++++++++++ rust/src/wire.rs | 4 ++++ 2 files changed, 48 insertions(+) diff --git a/rust/src/types.rs b/rust/src/types.rs index b5c180e4ab..6da7aa8152 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -1860,6 +1860,12 @@ pub struct SessionConfig { /// applied automatically at session creation/resume time. `None` means no /// explicit value is set and the runtime default takes effect. pub mcp_oauth_token_storage: Option, + /// URL identifying this host's OAuth client metadata document. + /// + /// Authorization servers that support client ID metadata documents can use + /// this URL as the MCP OAuth client ID. Older runtimes ignore this optional + /// field. + pub auth_client_id_metadata_url: Option, /// Enables runtime discovery of supported configuration. Explicitly supplied /// configuration takes precedence over discovered values. pub enable_config_discovery: Option, @@ -2235,6 +2241,7 @@ impl Default for SessionConfig { excluded_builtin_agents: None, mcp_servers: None, mcp_oauth_token_storage: None, + auth_client_id_metadata_url: None, enable_config_discovery: None, skip_embedding_retrieval: None, organization_custom_instructions: None, @@ -2388,6 +2395,7 @@ impl SessionConfig { tool_filter_precedence: "excluded", mcp_servers: self.mcp_servers, mcp_oauth_token_storage: self.mcp_oauth_token_storage, + auth_client_id_metadata_url: self.auth_client_id_metadata_url, embedding_cache_storage: self.embedding_cache_storage, env_value_mode: "direct", enable_config_discovery: self.enable_config_discovery, @@ -2715,6 +2723,12 @@ impl SessionConfig { self } + /// Set the URL identifying this host's OAuth client metadata document. + pub fn with_auth_client_id_metadata_url(mut self, url: impl Into) -> Self { + self.auth_client_id_metadata_url = Some(url.into()); + self + } + /// Set embedding cache storage mode. pub fn with_embedding_cache_storage( mut self, @@ -3101,6 +3115,9 @@ pub struct ResumeSessionConfig { /// Controls how MCP OAuth tokens are stored for this session. /// See [`SessionConfig::mcp_oauth_token_storage`] for details. pub mcp_oauth_token_storage: Option, + /// Re-supply the host OAuth client metadata document URL on resume. + /// See [`SessionConfig::auth_client_id_metadata_url`] for details. + pub auth_client_id_metadata_url: Option, /// Enables runtime discovery of supported configuration. Explicitly supplied /// configuration takes precedence over discovered values. pub enable_config_discovery: Option, @@ -3457,6 +3474,7 @@ impl ResumeSessionConfig { tool_filter_precedence: "excluded", mcp_servers: self.mcp_servers, mcp_oauth_token_storage: self.mcp_oauth_token_storage, + auth_client_id_metadata_url: self.auth_client_id_metadata_url, embedding_cache_storage: self.embedding_cache_storage, env_value_mode: "direct", enable_config_discovery: self.enable_config_discovery, @@ -3556,6 +3574,7 @@ impl ResumeSessionConfig { excluded_builtin_agents: None, mcp_servers: None, mcp_oauth_token_storage: None, + auth_client_id_metadata_url: None, enable_config_discovery: None, skip_embedding_retrieval: None, organization_custom_instructions: None, @@ -3855,6 +3874,12 @@ impl ResumeSessionConfig { self } + /// Set the host OAuth client metadata document URL on resume. + pub fn with_auth_client_id_metadata_url(mut self, url: impl Into) -> Self { + self.auth_client_id_metadata_url = Some(url.into()); + self + } + /// Set embedding cache storage mode on resume. pub fn with_embedding_cache_storage( mut self, @@ -6375,6 +6400,25 @@ mod tests { assert!(empty_json.get("largeOutput").is_none()); } + #[test] + fn auth_client_id_metadata_url_reaches_create_and_resume_wire_payloads() { + let url = "https://example.com/oauth/client-metadata.json"; + + let (create_wire, _) = SessionConfig::default() + .with_auth_client_id_metadata_url(url) + .into_wire(None) + .expect("default create has no duplicate handlers"); + let create_json = serde_json::to_value(&create_wire).unwrap(); + assert_eq!(create_json["authClientIdMetadataUrl"], url); + + let (resume_wire, _) = ResumeSessionConfig::new(SessionId::from("sess-1")) + .with_auth_client_id_metadata_url(url) + .into_wire() + .expect("default resume has no duplicate handlers"); + let resume_json = serde_json::to_value(&resume_wire).unwrap(); + assert_eq!(resume_json["authClientIdMetadataUrl"], url); + } + #[test] fn session_config_builder_composes() { use indexmap::IndexMap; diff --git a/rust/src/wire.rs b/rust/src/wire.rs index 4dc7569093..5c4c52de57 100644 --- a/rust/src/wire.rs +++ b/rust/src/wire.rs @@ -90,6 +90,8 @@ pub(crate) struct SessionCreateWire { #[serde(skip_serializing_if = "Option::is_none")] pub mcp_oauth_token_storage: Option, #[serde(skip_serializing_if = "Option::is_none")] + pub auth_client_id_metadata_url: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub embedding_cache_storage: Option, pub env_value_mode: &'static str, #[serde(skip_serializing_if = "Option::is_none")] @@ -230,6 +232,8 @@ pub(crate) struct SessionResumeWire { #[serde(skip_serializing_if = "Option::is_none")] pub mcp_oauth_token_storage: Option, #[serde(skip_serializing_if = "Option::is_none")] + pub auth_client_id_metadata_url: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub embedding_cache_storage: Option, pub env_value_mode: &'static str, #[serde(skip_serializing_if = "Option::is_none")]