@@ -485,7 +485,10 @@ async def test_get_mcp_tools_with_kubernetes_auth(
485485 mocker .patch ("utils.responses.configuration" , mock_config )
486486 tools_k8s = await get_mcp_tools (token = "user-k8s-token" )
487487 assert len (tools_k8s ) == 1
488- assert tools_k8s [0 ].authorization == "Bearer user-k8s-token"
488+ # The Bearer scheme is stripped here since OGX adds its own "Bearer "
489+ # prefix before forwarding the token to the MCP server; passing the
490+ # scheme through would result in a duplicated "Bearer Bearer <token>".
491+ assert tools_k8s [0 ].authorization == "user-k8s-token"
489492
490493 @pytest .mark .asyncio
491494 async def test_get_mcp_tools_with_mcp_headers (self , mocker : MockerFixture ) -> None :
@@ -623,7 +626,7 @@ async def test_get_mcp_tools_with_mixed_headers(
623626
624627 tools = await get_mcp_tools (token = "k8s-token" , mcp_headers = mcp_headers )
625628 assert len (tools ) == 1
626- assert tools [0 ].authorization == "Bearer k8s-token"
629+ assert tools [0 ].authorization == "k8s-token"
627630 assert tools [0 ].headers == {
628631 "X-API-Key" : "secret-api-key" ,
629632 "X-Custom" : "client-custom-value" ,
@@ -708,6 +711,40 @@ async def test_get_mcp_tools_with_propagated_headers(
708711 "x-request-id" : "req-456" ,
709712 }
710713
714+ @pytest .mark .asyncio
715+ async def test_get_mcp_tools_propagated_authorization_strips_bearer_scheme (
716+ self , mocker : MockerFixture
717+ ) -> None :
718+ """Regression test for a duplicated 'Bearer Bearer <token>' MCP header.
719+
720+ When an MCP server allowlists the incoming ``Authorization`` header
721+ via ``headers: [Authorization]`` (no ``authorization_headers``
722+ config), the propagated value already includes the ``Bearer``
723+ scheme. Since OGX's MCP ``authorization`` field expects a raw token
724+ and adds its own ``Bearer `` prefix, the scheme must be stripped
725+ before it is assigned to that field, or the downstream MCP server
726+ receives ``Authorization: Bearer Bearer <token>``.
727+ """
728+ servers = [
729+ ModelContextProtocolServer (
730+ name = "subscription-watch" ,
731+ url = "http://subscription-watch:8080" ,
732+ headers = ["Authorization" ],
733+ provider_id = "provider" ,
734+ ),
735+ ]
736+ mock_config = mocker .Mock ()
737+ mock_config .mcp_servers = servers
738+ mocker .patch ("utils.responses.configuration" , mock_config )
739+
740+ request_headers = {"Authorization" : "Bearer user-jwt-token" }
741+ tools = await get_mcp_tools (
742+ token = None , mcp_headers = None , request_headers = request_headers
743+ )
744+ assert len (tools ) == 1
745+ assert tools [0 ].authorization == "user-jwt-token"
746+ assert tools [0 ].headers is None
747+
711748 @pytest .mark .asyncio
712749 async def test_get_mcp_tools_propagated_headers_do_not_overwrite_auth_headers (
713750 self , tmp_path : Path , mocker : MockerFixture
@@ -815,7 +852,7 @@ async def test_get_mcp_tools_propagated_headers_additive_with_mcp_headers(
815852 token = None , mcp_headers = mcp_hdrs , request_headers = request_headers
816853 )
817854 assert len (tools ) == 1
818- assert tools [0 ].authorization == "Bearer client-token"
855+ assert tools [0 ].authorization == "client-token"
819856 assert tools [0 ].headers == {"x-rh-identity" : "identity-value" }
820857
821858 @pytest .mark .asyncio
@@ -934,6 +971,48 @@ async def test_apply_mcp_headers_preserves_type(
934971 dumped = out [0 ].model_dump (exclude_unset = True )
935972 assert dumped .get ("type" ) == "mcp"
936973
974+ def test_apply_mcp_headers_strips_bearer_from_propagated_authorization (
975+ self , mocker : MockerFixture
976+ ) -> None :
977+ """apply_mcp_headers_to_explicit_tools must strip the Bearer scheme.
978+
979+ Same regression as ``test_get_mcp_tools_propagated_authorization_strips_bearer_scheme``
980+ but for the explicit-tools path: a propagated ``Authorization`` header
981+ must not retain its ``Bearer`` scheme when assigned to OGX's
982+ ``authorization`` field, or the MCP server receives a duplicated
983+ ``Bearer Bearer <token>`` header.
984+ """
985+ from utils .responses import ( # pylint: disable=import-outside-toplevel
986+ apply_mcp_headers_to_explicit_tools ,
987+ )
988+
989+ servers = [
990+ ModelContextProtocolServer (
991+ name = "subscription-watch" ,
992+ url = "http://subscription-watch:8080" ,
993+ headers = ["Authorization" ],
994+ provider_id = "mcp" ,
995+ ),
996+ ]
997+ mock_config = mocker .Mock ()
998+ mock_config .mcp_servers = servers
999+ mocker .patch ("utils.responses.configuration" , mock_config )
1000+
1001+ explicit = InputToolMCP (
1002+ server_label = "subscription-watch" ,
1003+ server_url = "http://subscription-watch:8080" ,
1004+ )
1005+
1006+ out = apply_mcp_headers_to_explicit_tools (
1007+ [explicit ],
1008+ token = None ,
1009+ mcp_headers = None ,
1010+ request_headers = {"Authorization" : "Bearer user-jwt-token" },
1011+ )
1012+
1013+ assert len (out ) == 1
1014+ assert out [0 ].authorization == "user-jwt-token"
1015+
9371016
9381017class TestGetTopicSummary :
9391018 """Tests for get_topic_summary function."""
0 commit comments