Skip to content

Commit 4bb2a5b

Browse files
authored
feat(mcp): allow updating headers on MCPServerHTTP (#5559)
1 parent af4eb74 commit 4bb2a5b

1 file changed

Lines changed: 35 additions & 6 deletions

File tree

  • livekit-agents/livekit/agents/llm

livekit-agents/livekit/agents/llm/mcp.py

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ def __init__(
262262
tool_result_resolver=tool_result_resolver,
263263
)
264264
self.url = url
265-
self.headers = headers
265+
self._headers = headers or {}
266266
self._timeout = timeout
267267
self._sse_read_timeout = sse_read_timeout
268268
self._allowed_tools = set(allowed_tools) if allowed_tools else None
@@ -278,6 +278,37 @@ def __init__(
278278
# Fall back to URL-based detection for backward compatibility
279279
self._use_streamable_http = self._should_use_streamable_http(url)
280280

281+
self._http_client: httpx.AsyncClient | None = None
282+
283+
@property
284+
def headers(self) -> dict[str, Any]:
285+
return self._headers
286+
287+
@headers.setter
288+
def headers(self, headers: dict[str, Any]) -> None:
289+
self._headers = headers
290+
if self._http_client is not None:
291+
self._http_client.headers = headers
292+
293+
def _create_http_client(
294+
self,
295+
headers: dict[str, Any] | None = None,
296+
timeout: httpx.Timeout | None = None,
297+
auth: httpx.Auth | None = None,
298+
) -> httpx.AsyncClient:
299+
# ported from mcp.shared._httpx_utils.create_mcp_http_client
300+
kwargs: dict[str, Any] = {
301+
"follow_redirects": True,
302+
"timeout": timeout
303+
if timeout is not None
304+
else httpx.Timeout(self._timeout, read=self._sse_read_timeout),
305+
"headers": headers if headers is not None else self._headers,
306+
}
307+
if auth is not None:
308+
kwargs["auth"] = auth
309+
self._http_client = httpx.AsyncClient(**kwargs)
310+
return self._http_client
311+
281312
def _should_use_streamable_http(self, url: str) -> bool:
282313
"""
283314
Determine transport type based on URL path (for backward compatibility).
@@ -306,10 +337,7 @@ def client_streams(
306337

307338
@asynccontextmanager
308339
async def _streamable_http_with_client(): # type: ignore[no-untyped-def]
309-
async with httpx.AsyncClient(
310-
headers=self.headers or {},
311-
timeout=httpx.Timeout(self._timeout, read=self._sse_read_timeout),
312-
) as http_client:
340+
async with self._create_http_client() as http_client:
313341
async with streamable_http_client(
314342
url=self.url, http_client=http_client
315343
) as streams:
@@ -319,9 +347,10 @@ async def _streamable_http_with_client(): # type: ignore[no-untyped-def]
319347
else:
320348
return sse_client( # type: ignore[no-any-return]
321349
url=self.url,
322-
headers=self.headers,
350+
headers=self._headers,
323351
timeout=self._timeout,
324352
sse_read_timeout=self._sse_read_timeout,
353+
httpx_client_factory=self._create_http_client,
325354
)
326355

327356
async def list_tools(self) -> list[MCPTool]:

0 commit comments

Comments
 (0)