2828
2929from futuresearch_mcp import redis_store
3030from futuresearch_mcp .config import settings
31+ from futuresearch_mcp .request_context import get_conversation_id , get_user_agent
3132
3233logger = logging .getLogger (__name__ )
3334
@@ -57,19 +58,33 @@ class SessionContext:
5758
5859
5960def _get_client (ctx : FuturesearchContext ) -> AuthenticatedClient :
60- """Get an FutureSearch API client from the FastMCP lifespan context."""
61- return ctx .request_context .lifespan_context .client_factory ()
61+ """Get a FutureSearch API client with MCP client identity headers."""
62+ client = ctx .request_context .lifespan_context .client_factory ()
63+ extra_headers = _extract_client_headers (ctx )
64+ logger .debug (f"Setting extra headers to { extra_headers } " )
65+ if extra_headers :
66+ client = client .with_headers (extra_headers )
67+ return client
68+
69+
70+ def _extract_client_headers (ctx : FuturesearchContext ) -> dict [str , str ]:
71+ """Build X-MCP-Client-* headers from MCP client params or User-Agent."""
72+ headers : dict [str , str ] = {}
73+ cp = ctx .session .client_params
74+ if cp and cp .clientInfo :
75+ if cp .clientInfo .name :
76+ headers ["X-MCP-Client-Name" ] = cp .clientInfo .name
77+ if cp .clientInfo .version :
78+ headers ["X-MCP-Client-Version" ] = cp .clientInfo .version
79+ elif user_agent := get_user_agent ():
80+ headers ["X-MCP-Client-Name" ] = user_agent
81+ return headers
6282
6383
6484def _get_conversation_id () -> str | None :
6585 """Get the conversation ID from the current HTTP request context, if any."""
66- try :
67- from futuresearch_mcp .http_config import get_conversation_id # noqa: PLC0415
68-
69- val = get_conversation_id ()
70- return val if val else None
71- except Exception :
72- return None
86+ val = get_conversation_id ()
87+ return val if val else None
7388
7489
7590def create_linked_session (
@@ -88,8 +103,6 @@ def log_client_info(ctx: FuturesearchContext, tool_name: str) -> None:
88103 if not cp :
89104 # Stateless HTTP mode — no MCP initialize handshake.
90105 # Fall back to User-Agent from the HTTP request.
91- from futuresearch_mcp .http_config import get_user_agent # noqa: PLC0415
92-
93106 ua = get_user_agent ()
94107 logger .info (
95108 "[%s] client_params=None (stateless) ua=%s" ,
@@ -180,8 +193,6 @@ def _widgets_from_user_agent() -> bool:
180193 Only clients we have confirmed can render widgets get them; unknown UAs
181194 default to text-only to avoid wasting context tokens on unsupported UIs.
182195 """
183- from futuresearch_mcp .http_config import get_user_agent # noqa: PLC0415
184-
185196 ua = get_user_agent ().lower ()
186197
187198 # Whitelist of UA substrings for clients that support widgets.
@@ -203,8 +214,6 @@ def _widgets_from_user_agent() -> bool:
203214
204215def is_internal_client () -> bool :
205216 """Return True if the request comes from FutureSearch's own app."""
206- from futuresearch_mcp .http_config import get_user_agent # noqa: PLC0415
207-
208217 return "futuresearch" in get_user_agent ().lower ()
209218
210219
0 commit comments