@@ -863,6 +863,26 @@ async def test_validate_resource_rejects_mismatched_resource(
863863 await provider ._validate_resource_match (prm )
864864
865865
866+ @pytest .mark .anyio
867+ async def test_validate_resource_rejects_mismatched_query_component (
868+ client_metadata : OAuthClientMetadata , mock_storage : MockTokenStorage
869+ ) -> None :
870+ """Client rejects PRM resources with a different query-routed resource identifier."""
871+ provider = OAuthClientProvider (
872+ server_url = "https://api.example.com/v1/mcp?tenant=a" ,
873+ client_metadata = client_metadata ,
874+ storage = mock_storage ,
875+ )
876+ provider ._initialized = True
877+
878+ prm = ProtectedResourceMetadata (
879+ resource = AnyHttpUrl ("https://api.example.com/v1/mcp?tenant=b" ),
880+ authorization_servers = [AnyHttpUrl ("https://auth.example.com" )],
881+ )
882+ with pytest .raises (OAuthFlowError , match = "does not match expected" ):
883+ await provider ._validate_resource_match (prm )
884+
885+
866886@pytest .mark .anyio
867887async def test_validate_resource_accepts_matching_resource (
868888 client_metadata : OAuthClientMetadata , mock_storage : MockTokenStorage
@@ -1827,6 +1847,23 @@ async def callback_handler() -> AuthorizationCodeResult:
18271847 assert discovery_urls [0 ] == "https://api.example.com/.well-known/oauth-protected-resource/v1/mcp"
18281848 assert discovery_urls [1 ] == "https://api.example.com/.well-known/oauth-protected-resource"
18291849
1850+ def test_prm_discovery_preserves_server_url_query_component (self ):
1851+ """Fallback PRM discovery preserves RFC 9728 query components."""
1852+ init_response = httpx .Response (
1853+ status_code = 401 , headers = {}, request = httpx .Request ("GET" , "https://api.example.com/v1/mcp?tenant=a" )
1854+ )
1855+
1856+ discovery_urls = build_protected_resource_metadata_discovery_urls (
1857+ extract_resource_metadata_from_www_auth (init_response ), "https://api.example.com/v1/mcp?tenant=a"
1858+ )
1859+
1860+ assert discovery_urls == snapshot (
1861+ [
1862+ "https://api.example.com/.well-known/oauth-protected-resource/v1/mcp?tenant=a" ,
1863+ "https://api.example.com/.well-known/oauth-protected-resource" ,
1864+ ]
1865+ )
1866+
18301867 @pytest .mark .anyio
18311868 async def test_root_based_fallback_after_path_based_404 (
18321869 self , client_metadata : OAuthClientMetadata , mock_storage : MockTokenStorage
0 commit comments