new option for mcp servers

This patch adds an option to be able to pass a `verify` option to MCP servers definition. It is set to true by default which means that TLS certificate are being checked like they were before the patch if unset. If set to `false` then the TLS certificate are not checked. This option is really useful to have agent zero work with MCP servers on internal network where it is difficult to have public and valid certificate. It will be necessary to update the MCP python module to get access to the option allowing to pass custom HTTP client.

Eric Leblond committed Aug 21, 2025 at 15:53 UTC f32cc92999a9ff3d34c58a40ddb3dd464a820c95
1 file changed +38
python/helpers/mcp_handler.py
+38
@@ -24,6 +24,8 @@ import json
24 from python.helpers import errors
25 from python.helpers import settings
26
27 +import httpx
28 +
29 from mcp import ClientSession, StdioServerParameters
30 from mcp.client.stdio import stdio_client
31 from mcp.client.sse import sse_client
@@ -216,6 +218,7 @@ class MCPServerRemote(BaseModel):
218 headers: dict[str, Any] | None = Field(default_factory=dict[str, Any])
219 init_timeout: int = Field(default=0)
220 tool_timeout: int = Field(default=0)
221 + verify: bool = Field(default=True, description="Verify SSL certificates")
222 disabled: bool = Field(default=False)
223
224 __lock: ClassVar[threading.Lock] = PrivateAttr(default=threading.Lock())
@@ -265,6 +268,7 @@ class MCPServerRemote(BaseModel):
268 "init_timeout",
269 "tool_timeout",
270 "disabled",
271 + "verify",
272 ]:
273 if key == "name":
274 value = normalize_name(value)
@@ -293,6 +297,7 @@ class MCPServerLocal(BaseModel):
297 )
298 init_timeout: int = Field(default=0)
299 tool_timeout: int = Field(default=0)
300 + verify: bool = Field(default=True, description="Verify SSL certificates")
301 disabled: bool = Field(default=False)
302
303 __lock: ClassVar[threading.Lock] = PrivateAttr(default=threading.Lock())
@@ -1018,6 +1023,36 @@ class MCPClientLocal(MCPClientBase):
1023 # do not read or close the file here, as stdio is async
1024 return stdio_transport
1025
1026 +class CustomHTTPClientFactory(ABC):
1027 + def __init__(self, verify: bool = True):
1028 + self.verify = verify
1029 +
1030 + def __call__(
1031 + self,
1032 + headers: dict[str, str] | None = None,
1033 + timeout: httpx.Timeout | None = None,
1034 + auth: httpx.Auth | None = None,
1035 + ) -> httpx.AsyncClient:
1036 + # Set MCP defaults
1037 + kwargs: dict[str, Any] = {
1038 + "follow_redirects": True,
1039 + }
1040 +
1041 + # Handle timeout
1042 + if timeout is None:
1043 + kwargs["timeout"] = httpx.Timeout(30.0)
1044 + else:
1045 + kwargs["timeout"] = timeout
1046 +
1047 + # Handle headers
1048 + if headers is not None:
1049 + kwargs["headers"] = headers
1050 +
1051 + # Handle authentication
1052 + if auth is not None:
1053 + kwargs["auth"] = auth
1054 +
1055 + return httpx.AsyncClient(**kwargs, verify=self.verify)
1056
1057 class MCPClientRemote(MCPClientBase):
1058
@@ -1040,6 +1075,7 @@ class MCPClientRemote(MCPClientBase):
1075 init_timeout = min(server.init_timeout or set["mcp_client_init_timeout"], 5)
1076 tool_timeout = min(server.tool_timeout or set["mcp_client_tool_timeout"], 10)
1077
1078 + client_factory = CustomHTTPClientFactory(verify=server.verify)
1079 # Check if this is a streaming HTTP type
1080 if _is_streaming_http_type(server.type):
1081 # Use streamable HTTP client
@@ -1049,6 +1085,7 @@ class MCPClientRemote(MCPClientBase):
1085 headers=server.headers,
1086 timeout=timedelta(seconds=init_timeout),
1087 sse_read_timeout=timedelta(seconds=tool_timeout),
1088 + httpx_client_factory=client_factory,
1089 )
1090 )
1091 # streamablehttp_client returns (read_stream, write_stream, get_session_id_callback)
@@ -1066,6 +1103,7 @@ class MCPClientRemote(MCPClientBase):
1103 headers=server.headers,
1104 timeout=init_timeout,
1105 sse_read_timeout=tool_timeout,
1106 + httpx_client_factory=client_factory,
1107 )
1108 )
1109 return stdio_transport