@@ -591,6 +591,11 @@ pub enum AuthorizationMetadataSource {
591591 /// URL (`/authorize`, `/token`, `/register`) for compatibility with the
592592 /// 2025-03-26 MCP spec's default-endpoint fallback. The server gave no
593593 /// evidence that it supports OAuth.
594+ ///
595+ /// [Newer MCP revisions] require metadata discovery and do not define an
596+ /// endpoint-synthesis fallback.
597+ ///
598+ /// [Newer MCP revisions]: https://modelcontextprotocol.io/specification/draft/basic/authorization/authorization-server-discovery#protected-resource-metadata-discovery-requirements
594599 LegacyEndpointFallback ,
595600}
596601
@@ -1268,8 +1273,10 @@ impl AuthorizationManager {
12681273
12691274 /// Set OAuth2 authorization metadata
12701275 ///
1271- /// This should be called after discovering metadata via `discover_metadata()`
1272- /// and before creating an `AuthorizationSession`.
1276+ /// This should be called with
1277+ /// [`DiscoveredAuthorizationMetadata::metadata`] after
1278+ /// [`Self::discover_metadata`] and before creating an
1279+ /// [`AuthorizationSession`].
12731280 pub fn set_metadata ( & mut self , metadata : AuthorizationMetadata ) {
12741281 self . metadata = Some ( metadata) ;
12751282 }
@@ -1284,8 +1291,8 @@ impl AuthorizationManager {
12841291 && stored. token_response . is_some ( )
12851292 {
12861293 if self . metadata . is_none ( ) {
1287- let metadata = self . discover_metadata ( ) . await ?;
1288- self . metadata = Some ( metadata) ;
1294+ let discovered = self . discover_metadata ( ) . await ?;
1295+ self . metadata = Some ( discovered . metadata ) ;
12891296 }
12901297
12911298 if let ( Some ( stored_issuer) , Some ( current_issuer) ) =
@@ -1352,27 +1359,32 @@ impl AuthorizationManager {
13521359 Ok ( ( ) )
13531360 }
13541361
1355- /// discover oauth2 metadata (per SEP-985: Protected Resource Metadata first, then direct OAuth)
1362+ /// Discover OAuth 2.0 metadata and report how it was obtained.
13561363 ///
1357- /// When no metadata can be discovered, this falls back to legacy default
1358- /// endpoints derived from the base URL rather than returning an error, so
1359- /// a successful result does not prove the server supports OAuth. Callers
1360- /// that need to tell verified discovery apart from the synthesized
1361- /// fallback should use [`Self::discover_metadata_with_source`] instead.
1362- pub async fn discover_metadata ( & self ) -> Result < AuthorizationMetadata , AuthError > {
1363- Ok ( self . discover_metadata_with_source ( ) . await ?. metadata )
1364- }
1365-
1366- /// Discover oauth2 metadata along with how it was obtained.
1364+ /// Discovery follows SEP-985: protected resource metadata first, then
1365+ /// direct OAuth 2.0 Authorization Server Metadata or OpenID Connect
1366+ /// Discovery. When discovery finds nothing, the result contains legacy
1367+ /// default endpoints derived from the base URL and
1368+ /// [`AuthorizationMetadataSource::LegacyEndpointFallback`].
13671369 ///
1368- /// Unlike [`Self::discover_metadata`], the returned
1369- /// [`AuthorizationMetadataSource`] lets callers distinguish metadata the
1370- /// server actually published from the legacy default-endpoint fallback
1371- /// that is synthesized when discovery finds nothing
1372- /// ([`AuthorizationMetadataSource::LegacyEndpointFallback`]).
1373- pub async fn discover_metadata_with_source (
1374- & self ,
1375- ) -> Result < DiscoveredAuthorizationMetadata , AuthError > {
1370+ /// # Examples
1371+ ///
1372+ /// ```no_run
1373+ /// use rmcp::transport::auth::{AuthorizationManager, AuthorizationMetadataSource};
1374+ ///
1375+ /// # async fn discover() -> Result<(), Box<dyn std::error::Error>> {
1376+ /// let mut manager = AuthorizationManager::new("https://mcp.example.com").await?;
1377+ /// let discovered = manager.discover_metadata().await?;
1378+ ///
1379+ /// if discovered.source == AuthorizationMetadataSource::LegacyEndpointFallback {
1380+ /// println!("the server did not publish OAuth metadata");
1381+ /// }
1382+ ///
1383+ /// manager.set_metadata(discovered.metadata);
1384+ /// # Ok(())
1385+ /// # }
1386+ /// ```
1387+ pub async fn discover_metadata ( & self ) -> Result < DiscoveredAuthorizationMetadata , AuthError > {
13761388 if let Some ( metadata) = self . discover_oauth_server_via_resource_metadata ( ) . await ? {
13771389 return Ok ( DiscoveredAuthorizationMetadata {
13781390 metadata,
@@ -3473,8 +3485,8 @@ impl OAuthState {
34733485
34743486 * manager. current_scopes . write ( ) . await = granted_scopes. clone ( ) ;
34753487
3476- let metadata = manager. discover_metadata ( ) . await ?;
3477- manager. metadata = Some ( metadata) ;
3488+ let discovered = manager. discover_metadata ( ) . await ?;
3489+ manager. metadata = Some ( discovered . metadata ) ;
34783490
34793491 let stored = StoredCredentials {
34803492 client_id : client_id. to_string ( ) ,
@@ -3529,7 +3541,7 @@ impl OAuthState {
35293541 } ;
35303542 debug ! ( "start discovery" ) ;
35313543 let metadata = match manager. discover_metadata ( ) . await {
3532- Ok ( metadata ) => metadata,
3544+ Ok ( discovered ) => discovered . metadata ,
35333545 Err ( e) => {
35343546 * self = OAuthState :: Unauthorized ( manager) ;
35353547 return Err ( e) ;
@@ -3721,8 +3733,8 @@ impl OAuthState {
37213733 } ;
37223734
37233735 // Discover metadata
3724- let metadata = manager. discover_metadata ( ) . await ?;
3725- manager. metadata = Some ( metadata) ;
3736+ let discovered = manager. discover_metadata ( ) . await ?;
3737+ manager. metadata = Some ( discovered . metadata ) ;
37263738
37273739 // Validate server supports the requested auth method
37283740 manager. validate_client_credentials_metadata ( & config) ?;
@@ -3857,7 +3869,7 @@ mod tests {
38573869 . await
38583870 . unwrap ( ) ;
38593871
3860- let metadata = manager. discover_metadata ( ) . await . unwrap ( ) ;
3872+ let metadata = manager. discover_metadata ( ) . await . unwrap ( ) . metadata ;
38613873
38623874 assert_eq ! ( metadata. token_endpoint, "https://auth.example.com/token" ) ;
38633875 assert_eq ! (
@@ -3920,7 +3932,7 @@ mod tests {
39203932 . await
39213933 . unwrap ( ) ;
39223934
3923- let metadata = manager. discover_metadata ( ) . await . unwrap ( ) ;
3935+ let metadata = manager. discover_metadata ( ) . await . unwrap ( ) . metadata ;
39243936
39253937 assert_eq ! (
39263938 (
@@ -4102,7 +4114,7 @@ mod tests {
41024114 . await
41034115 . unwrap ( ) ;
41044116
4105- let metadata = manager. discover_metadata ( ) . await . unwrap ( ) ;
4117+ let metadata = manager. discover_metadata ( ) . await . unwrap ( ) . metadata ;
41064118
41074119 assert_eq ! (
41084120 (
@@ -4137,7 +4149,7 @@ mod tests {
41374149 }
41384150
41394151 #[ tokio:: test]
4140- async fn discover_metadata_falls_back_to_legacy_default_endpoints ( ) {
4152+ async fn discover_metadata_reports_legacy_fallback_when_nothing_is_discovered ( ) {
41414153 let client = RecordingOAuthHttpClient :: with_responses ( vec ! [
41424154 empty_response( 404 ) ,
41434155 empty_response( 404 ) ,
@@ -4152,20 +4164,22 @@ mod tests {
41524164 . await
41534165 . unwrap ( ) ;
41544166
4155- let metadata = manager. discover_metadata ( ) . await . unwrap ( ) ;
4167+ let discovered = manager. discover_metadata ( ) . await . unwrap ( ) ;
41564168
41574169 assert_eq ! (
41584170 (
4159- metadata. authorization_endpoint. as_str( ) ,
4160- metadata. token_endpoint. as_str( ) ,
4161- metadata. registration_endpoint. as_deref( ) ,
4171+ discovered. source,
4172+ discovered. metadata. authorization_endpoint. as_str( ) ,
4173+ discovered. metadata. token_endpoint. as_str( ) ,
4174+ discovered. metadata. registration_endpoint. as_deref( ) ,
41624175 client
41634176 . requests( )
41644177 . iter( )
41654178 . map( |request| request. uri. as_str( ) )
41664179 . collect:: <Vec <_>>( ) ,
41674180 ) ,
41684181 (
4182+ AuthorizationMetadataSource :: LegacyEndpointFallback ,
41694183 "https://legacy.example.com/authorize" ,
41704184 "https://legacy.example.com/token" ,
41714185 Some ( "https://legacy.example.com/register" ) ,
@@ -4181,37 +4195,7 @@ mod tests {
41814195 }
41824196
41834197 #[ tokio:: test]
4184- async fn discover_metadata_with_source_reports_legacy_fallback_when_nothing_is_discovered ( ) {
4185- let client = RecordingOAuthHttpClient :: with_responses ( vec ! [
4186- empty_response( 404 ) ,
4187- empty_response( 404 ) ,
4188- empty_response( 404 ) ,
4189- empty_response( 404 ) ,
4190- empty_response( 404 ) ,
4191- ] ) ;
4192- let manager = AuthorizationManager :: new_with_oauth_http_client (
4193- "https://legacy.example.com/" ,
4194- Arc :: new ( client) ,
4195- )
4196- . await
4197- . unwrap ( ) ;
4198-
4199- let discovered = manager. discover_metadata_with_source ( ) . await . unwrap ( ) ;
4200-
4201- assert_eq ! (
4202- (
4203- discovered. source,
4204- discovered. metadata. authorization_endpoint. as_str( ) ,
4205- ) ,
4206- (
4207- AuthorizationMetadataSource :: LegacyEndpointFallback ,
4208- "https://legacy.example.com/authorize" ,
4209- )
4210- ) ;
4211- }
4212-
4213- #[ tokio:: test]
4214- async fn discover_metadata_with_source_reports_protected_resource_metadata ( ) {
4198+ async fn discover_metadata_reports_protected_resource_metadata ( ) {
42154199 let challenge = oauth2:: http:: Response :: builder ( )
42164200 . status ( 401 )
42174201 . header (
@@ -4245,7 +4229,7 @@ mod tests {
42454229 . await
42464230 . unwrap ( ) ;
42474231
4248- let discovered = manager. discover_metadata_with_source ( ) . await . unwrap ( ) ;
4232+ let discovered = manager. discover_metadata ( ) . await . unwrap ( ) ;
42494233
42504234 assert_eq ! (
42514235 (
@@ -4260,7 +4244,7 @@ mod tests {
42604244 }
42614245
42624246 #[ tokio:: test]
4263- async fn discover_metadata_with_source_reports_authorization_server_metadata ( ) {
4247+ async fn discover_metadata_reports_authorization_server_metadata ( ) {
42644248 let client = RecordingOAuthHttpClient :: with_responses ( vec ! [
42654249 empty_response( 404 ) ,
42664250 empty_response( 404 ) ,
@@ -4281,7 +4265,7 @@ mod tests {
42814265 . await
42824266 . unwrap ( ) ;
42834267
4284- let discovered = manager. discover_metadata_with_source ( ) . await . unwrap ( ) ;
4268+ let discovered = manager. discover_metadata ( ) . await . unwrap ( ) ;
42854269
42864270 assert_eq ! (
42874271 (
@@ -4398,7 +4382,7 @@ mod tests {
43984382 )
43994383 . await
44004384 . unwrap ( ) ;
4401- manager. metadata = Some ( manager. discover_metadata ( ) . await . unwrap ( ) ) ;
4385+ manager. metadata = Some ( manager. discover_metadata ( ) . await . unwrap ( ) . metadata ) ;
44024386
44034387 let request = AuthorizationRequest :: new ( "http://localhost:8080/callback" )
44044388 . with_preregistered_client ( "preregistered-client" ) ;
@@ -4853,7 +4837,7 @@ mod tests {
48534837 . await
48544838 . unwrap ( ) ;
48554839
4856- let metadata = manager. discover_metadata ( ) . await . unwrap ( ) ;
4840+ let metadata = manager. discover_metadata ( ) . await . unwrap ( ) . metadata ;
48574841 let requests = client. requests ( ) ;
48584842
48594843 assert_eq ! (
@@ -4910,7 +4894,7 @@ mod tests {
49104894 . await
49114895 . unwrap ( ) ;
49124896
4913- let metadata = manager. discover_metadata ( ) . await . unwrap ( ) ;
4897+ let metadata = manager. discover_metadata ( ) . await . unwrap ( ) . metadata ;
49144898
49154899 assert_eq ! (
49164900 (
0 commit comments