diff --git a/src/google/adk/tools/mcp_tool/mcp_session_manager.py b/src/google/adk/tools/mcp_tool/mcp_session_manager.py index 1d9e5c80a0..90edbf1f34 100644 --- a/src/google/adk/tools/mcp_tool/mcp_session_manager.py +++ b/src/google/adk/tools/mcp_tool/mcp_session_manager.py @@ -261,7 +261,7 @@ async def before_request( ) return - if 'Authorization' in headers: + if any(key.lower() == 'authorization' for key in headers): logger.debug('Authorization header already present, not overwriting') return diff --git a/tests/unittests/tools/mcp_tool/test_mcp_session_manager.py b/tests/unittests/tools/mcp_tool/test_mcp_session_manager.py index 52d9ebf5ca..5cfc4a6d57 100644 --- a/tests/unittests/tools/mcp_tool/test_mcp_session_manager.py +++ b/tests/unittests/tools/mcp_tool/test_mcp_session_manager.py @@ -1298,6 +1298,25 @@ def mock_refresh(req): assert headers["Authorization"] == "Bearer refreshed_token" + @pytest.mark.skipif(not AIO_SUPPORTED, reason="google.auth.aio not supported") + @pytest.mark.asyncio + async def test_before_request_preserves_lowercase_authorization_header(self): + """An existing lowercase authorization header prevents token injection.""" + from google.adk.tools.mcp_tool.mcp_session_manager import _RefreshableAsyncCredentials + + mock_creds = Mock() + mock_creds.expired = True + mock_creds.token = "service_account_token" + mock_creds.refresh = Mock() + + credentials = _RefreshableAsyncCredentials(mock_creds) + headers = {"authorization": "Bearer user_token"} + + await credentials.before_request(None, "GET", "http://example.com", headers) + + assert headers == {"authorization": "Bearer user_token"} + mock_creds.refresh.assert_not_called() + class TestGoogleAuthAsyncByteStream: