@@ -261,3 +261,42 @@ async def test_pool_returns_cached_client_for_same_token(self):
261261 second = await main_module ._get_client ()
262262
263263 assert first is second
264+
265+ async def test_header_token_creates_client_and_caches_under_sha256_key (self ):
266+ """
267+ X-CourtListener-Token header must create a client cached under SHA256(token),
268+ not under the env-token key. Header path takes priority.
269+ """
270+ main_module ._client_pool .clear ()
271+ main_module ._client_pool_lock = None
272+
273+ header_token = "header_user_token_abc"
274+ env_token = "env_user_token_xyz"
275+
276+ mock_settings = MagicMock ()
277+ mock_settings .get_api_token .return_value = env_token
278+
279+ mock_request = MagicMock ()
280+ mock_request .headers = MagicMock ()
281+ mock_request .headers .get = lambda k : header_token if k == "x-courtlistener-token" else None
282+
283+ with patch ("courtlistener_mcp.main._get_settings" , return_value = mock_settings ):
284+ with patch ("courtlistener_mcp.main.get_http_request" , return_value = mock_request ):
285+ client = await main_module ._get_client ()
286+
287+ # Client must be created with the header token, not the env token
288+ assert client ._token == header_token
289+
290+ # Must be cached under SHA256(header_token), not SHA256(env_token)
291+ import hashlib
292+ header_key = hashlib .sha256 (header_token .encode ()).hexdigest ()
293+ env_key = hashlib .sha256 (env_token .encode ()).hexdigest ()
294+ assert main_module ._client_pool .get (header_key ) is client
295+ assert main_module ._client_pool .get (env_key ) is None
296+
297+ # Second call with same header returns the cached instance
298+ with patch ("courtlistener_mcp.main._get_settings" , return_value = mock_settings ):
299+ with patch ("courtlistener_mcp.main.get_http_request" , return_value = mock_request ):
300+ second = await main_module ._get_client ()
301+
302+ assert second is client
0 commit comments