From 10b4b86ada93cd62d994c3179ff14dfd1a6e56f0 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 30 Mar 2026 05:10:24 -0500 Subject: [PATCH] refac --- backend/open_webui/utils/mcp/client.py | 36 ++++++++++++++++---------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/backend/open_webui/utils/mcp/client.py b/backend/open_webui/utils/mcp/client.py index fbabb390aa..79221f4463 100644 --- a/backend/open_webui/utils/mcp/client.py +++ b/backend/open_webui/utils/mcp/client.py @@ -9,22 +9,27 @@ from mcp.client.auth import OAuthClientProvider, TokenStorage from mcp.client.streamable_http import streamablehttp_client from mcp.shared.auth import OAuthClientInformationFull, OAuthClientMetadata, OAuthToken import httpx -from open_webui.env import AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL +from open_webui.env import AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL, AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER -def create_insecure_httpx_client(headers=None, timeout=None, auth=None): - """Create an httpx AsyncClient with SSL verification disabled. +def _build_httpx_client(headers=None, timeout=None, auth=None, verify=True): + """Create an httpx AsyncClient for MCP transport. - Note: verify=False must be passed at construction time because httpx + Falls back to AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER when the caller + (i.e. the MCP SDK) does not supply an explicit timeout. + + Note: verify must be passed at construction time because httpx configures the SSL context during __init__. Setting client.verify = False after construction does not affect the underlying transport's SSL context. """ kwargs = { 'follow_redirects': True, - 'verify': False, + 'verify': verify, } if timeout is not None: kwargs['timeout'] = timeout + elif AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER is not None: + kwargs['timeout'] = float(AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER) if headers is not None: kwargs['headers'] = headers if auth is not None: @@ -32,6 +37,14 @@ def create_insecure_httpx_client(headers=None, timeout=None, auth=None): return httpx.AsyncClient(**kwargs) +def create_httpx_client(headers=None, timeout=None, auth=None): + return _build_httpx_client(headers=headers, timeout=timeout, auth=auth, verify=True) + + +def create_insecure_httpx_client(headers=None, timeout=None, auth=None): + return _build_httpx_client(headers=headers, timeout=timeout, auth=auth, verify=False) + + class MCPClient: def __init__(self): self.session: Optional[ClientSession] = None @@ -40,14 +53,11 @@ class MCPClient: async def connect(self, url: str, headers: Optional[dict] = None): async with AsyncExitStack() as exit_stack: try: - if AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL: - self._streams_context = streamablehttp_client(url, headers=headers) - else: - self._streams_context = streamablehttp_client( - url, - headers=headers, - httpx_client_factory=create_insecure_httpx_client, - ) + self._streams_context = streamablehttp_client( + url, + headers=headers, + httpx_client_factory=create_httpx_client if AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL else create_insecure_httpx_client, + ) transport = await exit_stack.enter_async_context(self._streams_context) read_stream, write_stream, _ = transport