1+ use anyhow:: Context ;
2+ use oauth2:: { ClientSecret , RefreshToken } ;
13use rmcp:: {
24 ClientHandler , ClientLifecycleMode , ClientServiceExt , ErrorData , RoleClient , ServiceExt ,
35 model:: * ,
@@ -6,7 +8,8 @@ use rmcp::{
68 AuthClient , AuthorizationManager , StreamableHttpClientTransport ,
79 auth:: {
810 AuthorizationCallback , AuthorizationRequest , ClientCredentialsConfig ,
9- InMemoryCredentialStore , JwtSigningAlgorithm , OAuthState ,
11+ InMemoryCredentialStore , JwtSigningAlgorithm , OAuthState , default_oauth_http_client,
12+ enterprise:: { EmaAuthorizationServer , EmaClientAuthentication , EmaExchangeRequest } ,
1013 } ,
1114 streamable_http_client:: StreamableHttpClientTransportConfig ,
1215 } ,
@@ -36,6 +39,17 @@ struct ConformanceContext {
3639 private_key_pem : Option < String > ,
3740 #[ serde( default ) ]
3841 signing_algorithm : Option < String > ,
42+ // enterprise-managed-authorization-refresh-token
43+ #[ serde( default ) ]
44+ idp_client_id : Option < String > ,
45+ #[ serde( default ) ]
46+ idp_client_secret : Option < String > ,
47+ #[ serde( default ) ]
48+ idp_refresh_token : Option < String > ,
49+ #[ serde( default ) ]
50+ idp_issuer : Option < String > ,
51+ #[ serde( default ) ]
52+ idp_token_endpoint : Option < String > ,
3953}
4054
4155fn load_context ( ) -> ConformanceContext {
@@ -760,6 +774,66 @@ async fn run_client_credentials_jwt(
760774 Ok ( ( ) )
761775}
762776
777+ /// Exchange the fixture's IdP refresh token, then exercise authenticated MCP access.
778+ async fn run_ema_refresh_token_client (
779+ server_url : & str ,
780+ ctx : & ConformanceContext ,
781+ ) -> anyhow:: Result < ( ) > {
782+ let manager = AuthorizationManager :: new ( server_url) . await ?;
783+ let metadata = manager. resolve_metadata ( ) . await ?. metadata ;
784+ let idp = EmaAuthorizationServer :: new (
785+ ctx. idp_issuer . as_deref ( ) . context ( "Missing idp_issuer" ) ?,
786+ ctx. idp_token_endpoint
787+ . as_deref ( )
788+ . context ( "Missing idp_token_endpoint" ) ?,
789+ ctx. idp_client_id
790+ . as_deref ( )
791+ . context ( "Missing idp_client_id" ) ?,
792+ )
793+ . with_client_authentication ( EmaClientAuthentication :: ClientSecretBasic (
794+ ClientSecret :: new (
795+ ctx. idp_client_secret
796+ . clone ( )
797+ . context ( "Missing idp_client_secret" ) ?,
798+ ) ,
799+ ) ) ;
800+ let resource_as = EmaAuthorizationServer :: new (
801+ metadata
802+ . issuer
803+ . context ( "Missing authorization server issuer" ) ?,
804+ metadata. token_endpoint ,
805+ ctx. client_id . as_deref ( ) . context ( "Missing client_id" ) ?,
806+ )
807+ . with_client_authentication ( EmaClientAuthentication :: ClientSecretBasic (
808+ ClientSecret :: new ( ctx. client_secret . clone ( ) . context ( "Missing client_secret" ) ?) ,
809+ ) ) ;
810+ let refresh_token = RefreshToken :: new (
811+ ctx. idp_refresh_token
812+ . clone ( )
813+ . context ( "Missing idp_refresh_token" ) ?,
814+ ) ;
815+ let http = default_oauth_http_client ( ) ?;
816+ let token = EmaExchangeRequest :: new ( idp, resource_as, server_url, & refresh_token)
817+ . with_scopes ( manager. select_scopes ( None , & [ ] ) )
818+ . exchange ( & http, & http)
819+ . await ?;
820+
821+ let transport = StreamableHttpClientTransport :: from_config (
822+ StreamableHttpClientTransportConfig :: with_uri ( server_url)
823+ . auth_header ( token. access_token . secret ( ) ) ,
824+ ) ;
825+ let client = BasicClientHandler
826+ . serve_with_lifecycle ( transport, conformance_lifecycle ( ) )
827+ . await ?;
828+ let tools = client. list_tools ( Default :: default ( ) ) . await ?;
829+ for tool in tools. tools {
830+ let args = build_tool_arguments ( & tool) ;
831+ client. call_tool ( call_tool_params ( tool. name , args) ) . await ?;
832+ }
833+ client. cancel ( ) . await ?;
834+ Ok ( ( ) )
835+ }
836+
763837/// Cross-app access flow (SEP-1046 extension).
764838async fn run_cross_app_access_client (
765839 server_url : & str ,
@@ -1110,6 +1184,11 @@ async fn run_scenario(
11101184 "auth/client-credentials-basic" => run_client_credentials_basic ( server_url, ctx) . await ?,
11111185 "auth/client-credentials-jwt" => run_client_credentials_jwt ( server_url, ctx) . await ?,
11121186
1187+ // Auth - enterprise-managed authorization with a refresh-token subject
1188+ "auth/enterprise-managed-authorization-refresh-token" => {
1189+ run_ema_refresh_token_client ( server_url, ctx) . await ?
1190+ }
1191+
11131192 // Auth - cross-app access
11141193 "auth/cross-app-access-complete-flow" => {
11151194 run_cross_app_access_client ( server_url, ctx) . await ?
0 commit comments