diff --git a/src/mcp/client/auth.py b/src/mcp/client/auth.py index 6238d6951..8bafe18eb 100644 --- a/src/mcp/client/auth.py +++ b/src/mcp/client/auth.py @@ -308,6 +308,7 @@ async def _register_client(self) -> httpx.Request | None: async def _handle_registration_response(self, response: httpx.Response) -> None: """Handle registration response.""" if response.status_code not in (200, 201): + await response.aread() raise OAuthRegistrationError(f"Registration failed: {response.status_code} {response.text}") try: diff --git a/tests/client/test_auth.py b/tests/client/test_auth.py index 8e6b4f54d..affcaa276 100644 --- a/tests/client/test_auth.py +++ b/tests/client/test_auth.py @@ -516,6 +516,42 @@ async def test_resource_param_included_with_protected_resource_metadata(self, oa assert "resource=" in content +class TestRegistrationResponse: + """Test client registration response handling.""" + + @pytest.mark.anyio + async def test_handle_registration_response_reads_before_accessing_text(self, oauth_provider): + """Test that response.aread() is called before accessing response.text.""" + + # Track if aread() was called + class MockResponse: + def __init__(self): + self.status_code = 400 + self._aread_called = False + self._text = "Registration failed with error" + + async def aread(self): + self._aread_called = True + return b"test content" + + @property + def text(self): + if not self._aread_called: + raise RuntimeError("Response.text accessed before response.aread()") + return self._text + + mock_response = MockResponse() + + # This should call aread() before accessing text + with pytest.raises(Exception) as exc_info: + await oauth_provider._handle_registration_response(mock_response) + + # Verify aread() was called + assert mock_response._aread_called + # Verify the error message includes the response text + assert "Registration failed: 400" in str(exc_info.value) + + class TestAuthFlow: """Test the auth flow in httpx."""