@@ -1167,6 +1167,57 @@ async def test_auth_flow_with_no_tokens(self, oauth_provider: OAuthClientProvide
11671167 assert oauth_provider .context .current_tokens .access_token == "new_access_token"
11681168 assert oauth_provider .context .token_expiry_time is not None
11691169
1170+ @pytest .mark .anyio
1171+ async def test_auth_flow_logs_and_reraises_oauth_errors (self , oauth_provider : OAuthClientProvider , caplog ):
1172+ """OAuth flow failures should be logged and re-raised."""
1173+ oauth_provider .context .current_tokens = None
1174+ oauth_provider .context .token_expiry_time = None
1175+ oauth_provider .context .client_info = OAuthClientInformationFull (
1176+ client_id = "existing_client" ,
1177+ redirect_uris = [AnyUrl ("http://localhost:3030/callback" )],
1178+ )
1179+ oauth_provider ._initialized = True
1180+ oauth_provider ._perform_authorization = mock .AsyncMock (side_effect = RuntimeError ("auth boom" ))
1181+
1182+ test_request = httpx .Request ("GET" , "https://api.example.com/v1/mcp" )
1183+ auth_flow = oauth_provider .async_auth_flow (test_request )
1184+
1185+ await auth_flow .__anext__ ()
1186+
1187+ response = httpx .Response (
1188+ 401 ,
1189+ headers = {
1190+ "WWW-Authenticate" : 'Bearer resource_metadata="https://api.example.com/.well-known/oauth-protected-resource"'
1191+ },
1192+ request = test_request ,
1193+ )
1194+ discovery_request = await auth_flow .asend (response )
1195+
1196+ discovery_response = httpx .Response (
1197+ 200 ,
1198+ content = (
1199+ b'{"resource": "https://api.example.com/v1/mcp", "authorization_servers": ["https://auth.example.com"]}'
1200+ ),
1201+ request = discovery_request ,
1202+ )
1203+ oauth_metadata_request = await auth_flow .asend (discovery_response )
1204+
1205+ oauth_metadata_response = httpx .Response (
1206+ 200 ,
1207+ content = (
1208+ b'{"issuer": "https://auth.example.com", '
1209+ b'"authorization_endpoint": "https://auth.example.com/authorize", '
1210+ b'"token_endpoint": "https://auth.example.com/token"}'
1211+ ),
1212+ request = oauth_metadata_request ,
1213+ )
1214+
1215+ with caplog .at_level ("ERROR" , logger = "mcp.client.auth.oauth2" ):
1216+ with pytest .raises (RuntimeError , match = "auth boom" ):
1217+ await auth_flow .asend (oauth_metadata_response )
1218+
1219+ assert "OAuth flow error" in caplog .text
1220+
11701221 @pytest .mark .anyio
11711222 async def test_auth_flow_no_unnecessary_retry_after_oauth (
11721223 self , oauth_provider : OAuthClientProvider , mock_storage : MockTokenStorage , valid_tokens : OAuthToken
0 commit comments