@@ -482,7 +482,10 @@ async def test_get_mcp_tools_with_kubernetes_auth(
482482 mocker .patch ("utils.responses.configuration" , mock_config )
483483 tools_k8s = await get_mcp_tools (token = "user-k8s-token" )
484484 assert len (tools_k8s ) == 1
485- assert tools_k8s [0 ].authorization == "Bearer user-k8s-token"
485+ # The Bearer scheme is stripped here since OGX adds its own "Bearer "
486+ # prefix before forwarding the token to the MCP server; passing the
487+ # scheme through would result in a duplicated "Bearer Bearer <token>".
488+ assert tools_k8s [0 ].authorization == "user-k8s-token"
486489
487490 @pytest .mark .asyncio
488491 async def test_get_mcp_tools_with_mcp_headers (self , mocker : MockerFixture ) -> None :
@@ -620,7 +623,7 @@ async def test_get_mcp_tools_with_mixed_headers(
620623
621624 tools = await get_mcp_tools (token = "k8s-token" , mcp_headers = mcp_headers )
622625 assert len (tools ) == 1
623- assert tools [0 ].authorization == "Bearer k8s-token"
626+ assert tools [0 ].authorization == "k8s-token"
624627 assert tools [0 ].headers == {
625628 "X-API-Key" : "secret-api-key" ,
626629 "X-Custom" : "client-custom-value" ,
@@ -705,6 +708,40 @@ async def test_get_mcp_tools_with_propagated_headers(
705708 "x-request-id" : "req-456" ,
706709 }
707710
711+ @pytest .mark .asyncio
712+ async def test_get_mcp_tools_propagated_authorization_strips_bearer_scheme (
713+ self , mocker : MockerFixture
714+ ) -> None :
715+ """Regression test for a duplicated 'Bearer Bearer <token>' MCP header.
716+
717+ When an MCP server allowlists the incoming ``Authorization`` header
718+ via ``headers: [Authorization]`` (no ``authorization_headers``
719+ config), the propagated value already includes the ``Bearer``
720+ scheme. Since OGX's MCP ``authorization`` field expects a raw token
721+ and adds its own ``Bearer `` prefix, the scheme must be stripped
722+ before it is assigned to that field, or the downstream MCP server
723+ receives ``Authorization: Bearer Bearer <token>``.
724+ """
725+ servers = [
726+ ModelContextProtocolServer (
727+ name = "subscription-watch" ,
728+ url = "http://subscription-watch:8080" ,
729+ headers = ["Authorization" ],
730+ provider_id = "provider" ,
731+ ),
732+ ]
733+ mock_config = mocker .Mock ()
734+ mock_config .mcp_servers = servers
735+ mocker .patch ("utils.responses.configuration" , mock_config )
736+
737+ request_headers = {"Authorization" : "Bearer user-jwt-token" }
738+ tools = await get_mcp_tools (
739+ token = None , mcp_headers = None , request_headers = request_headers
740+ )
741+ assert len (tools ) == 1
742+ assert tools [0 ].authorization == "user-jwt-token"
743+ assert tools [0 ].headers is None
744+
708745 @pytest .mark .asyncio
709746 async def test_get_mcp_tools_propagated_headers_do_not_overwrite_auth_headers (
710747 self , tmp_path : Path , mocker : MockerFixture
@@ -812,7 +849,7 @@ async def test_get_mcp_tools_propagated_headers_additive_with_mcp_headers(
812849 token = None , mcp_headers = mcp_hdrs , request_headers = request_headers
813850 )
814851 assert len (tools ) == 1
815- assert tools [0 ].authorization == "Bearer client-token"
852+ assert tools [0 ].authorization == "client-token"
816853 assert tools [0 ].headers == {"x-rh-identity" : "identity-value" }
817854
818855 @pytest .mark .asyncio
@@ -931,6 +968,48 @@ async def test_apply_mcp_headers_preserves_type(
931968 dumped = out [0 ].model_dump (exclude_unset = True )
932969 assert dumped .get ("type" ) == "mcp"
933970
971+ def test_apply_mcp_headers_strips_bearer_from_propagated_authorization (
972+ self , mocker : MockerFixture
973+ ) -> None :
974+ """apply_mcp_headers_to_explicit_tools must strip the Bearer scheme.
975+
976+ Same regression as ``test_get_mcp_tools_propagated_authorization_strips_bearer_scheme``
977+ but for the explicit-tools path: a propagated ``Authorization`` header
978+ must not retain its ``Bearer`` scheme when assigned to OGX's
979+ ``authorization`` field, or the MCP server receives a duplicated
980+ ``Bearer Bearer <token>`` header.
981+ """
982+ from utils .responses import ( # pylint: disable=import-outside-toplevel
983+ apply_mcp_headers_to_explicit_tools ,
984+ )
985+
986+ servers = [
987+ ModelContextProtocolServer (
988+ name = "subscription-watch" ,
989+ url = "http://subscription-watch:8080" ,
990+ headers = ["Authorization" ],
991+ provider_id = "mcp" ,
992+ ),
993+ ]
994+ mock_config = mocker .Mock ()
995+ mock_config .mcp_servers = servers
996+ mocker .patch ("utils.responses.configuration" , mock_config )
997+
998+ explicit = InputToolMCP (
999+ server_label = "subscription-watch" ,
1000+ server_url = "http://subscription-watch:8080" ,
1001+ )
1002+
1003+ out = apply_mcp_headers_to_explicit_tools (
1004+ [explicit ],
1005+ token = None ,
1006+ mcp_headers = None ,
1007+ request_headers = {"Authorization" : "Bearer user-jwt-token" },
1008+ )
1009+
1010+ assert len (out ) == 1
1011+ assert out [0 ].authorization == "user-jwt-token"
1012+
9341013
9351014class TestGetTopicSummary :
9361015 """Tests for get_topic_summary function."""
0 commit comments