Add verify parameter for SSL certificate configuration#3487
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d93b8f28a9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| elif self.verify is not None: | ||
| # create_mcp_http_client doesn't support verify, so construct | ||
| # the client directly with the same MCP defaults | ||
| if timeout is None: | ||
| timeout = httpx.Timeout(30.0, read=300.0) |
There was a problem hiding this comment.
Propagate verify to OAuth preflight client for streamable HTTP
When verify is provided and no custom httpx_client_factory is set, this code path builds a one-off httpx.AsyncClient for transport requests but leaves self.httpx_client_factory as None; auth="oauth" therefore still creates OAuth with its default factory. OAuth.redirect_handler uses auth.httpx_client_factory() for the authorization preflight request, so self-signed/internal-CA servers still fail certificate validation before OAuth completes, despite verify=False or a custom CA being passed.
Useful? React with 👍 / 👎.
| def _factory(**kwargs: Any) -> httpx.AsyncClient: | ||
| return httpx.AsyncClient(verify=verify, **kwargs) | ||
|
|
||
| client_kwargs["httpx_client_factory"] = _factory |
There was a problem hiding this comment.
Reuse verify-aware factory for OAuth in SSE transport
The verify-specific factory created here is only passed to sse_client via local client_kwargs; it is not assigned to self.httpx_client_factory, so auth="oauth" still keeps OAuth's default httpx.AsyncClient factory. In OAuth flows, OAuth.redirect_handler uses that factory for its preflight GET, which means TLS verification ignores the transport verify setting and fails against self-signed/internal-CA auth servers.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0095c5d01d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| resolved = OAuth( | ||
| self.url, | ||
| httpx_client_factory=self.httpx_client_factory | ||
| or self._make_verify_factory(), |
There was a problem hiding this comment.
Propagate verify for OAuth auth objects
This branch applies a verify-aware httpx_client_factory only when auth == "oauth"; when callers use the documented auth=OAuth(...) form, _set_auth falls through to isinstance(auth, OAuth) and keeps the provider’s default httpx.AsyncClient, so OAuth preflight requests still enforce normal certificate validation and fail against self-signed/internal-CA servers even if verify=False or a custom CA was passed. I confirmed this in the same transport logic and the mirrored _set_auth implementation in src/fastmcp/client/transports/sse.py.
Useful? React with 👍 / 👎.
| if isinstance(self.transport, StreamableHttpTransport | SSETransport): | ||
| self.transport.verify = verify |
There was a problem hiding this comment.
Refresh OAuth factory after setting transport verify
When Client receives an already-constructed HTTP transport (a supported input type) with OAuth already configured, this code only mutates transport.verify and does not re-create/rebind OAuth auth, so the existing OAuth provider keeps its old httpx_client_factory and ignores the new verify setting. In practice, Client(StreamableHttpTransport(url, auth="oauth"), verify=False) still performs OAuth preflight with certificate verification enabled.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 61820c49ca
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if auth.httpx_client_factory is httpx.AsyncClient: | ||
| verify_factory = ( |
There was a problem hiding this comment.
Rebind OAuth factory when verify changes
This conditional only rewires an OAuth instance when its factory is exactly httpx.AsyncClient, so pre-constructed transports that already carry a verify-aware factory keep stale TLS settings after Client(..., verify=...) mutates transport.verify. For example, Client(StreamableHttpTransport(url, verify=False, auth="oauth"), verify=True) leaves OAuth preflight requests at CERT_NONE even though the transport verify setting is now strict; the same _set_auth pattern exists in src/fastmcp/client/transports/sse.py.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ad13332052
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| factory = self.httpx_client_factory or self._make_verify_factory() | ||
| if factory is not None: | ||
| auth.httpx_client_factory = factory |
There was a problem hiding this comment.
Preserve custom OAuth client factory on bound auth objects
When callers pass an OAuth(...) instance with its own httpx_client_factory, this branch overwrites it whenever the transport has verify (or a transport-level httpx_client_factory). That silently drops OAuth-specific client settings (for example proxies, client certs, or custom transports), so OAuth preflight/token requests can fail even though the caller explicitly configured them on the auth object. This is a regression from the previous behavior where OAuth instances were only bound to the URL.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7808361f48
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| factory = self.httpx_client_factory or self._make_verify_factory() | ||
| if factory is not None: | ||
| auth.httpx_client_factory = factory |
There was a problem hiding this comment.
Preserve caller OAuth factory when binding SSE auth objects
When auth is an OAuth(...) instance, this branch unconditionally overwrites auth.httpx_client_factory with the transport-level factory (or the verify-derived one). That drops any OAuth-specific client configuration the caller attached to the auth object (for example proxies, mTLS/client certs, or custom transports), so OAuth preflight/token requests can fail even though the auth provider was explicitly configured. This is a regression from the previous behavior where passing an OAuth instance only bound the URL.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ddeda28634
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if isinstance(self.transport.auth, OAuth) and auth is None: | ||
| verify_factory = self.transport._make_verify_factory() | ||
| if verify_factory is not None: | ||
| self.transport.auth.httpx_client_factory = verify_factory |
There was a problem hiding this comment.
Preserve OAuth factory when Client verify is applied
When Client(..., verify=...) wraps a preconstructed StreamableHttpTransport/SSETransport that already has OAuth configured, this block unconditionally replaces transport.auth.httpx_client_factory with a verify-only factory. That drops any existing transport/client-factory behavior (e.g., proxies, client certs, custom transports) for OAuth preflight/token requests while the transport itself still uses self.transport.httpx_client_factory, so auth and transport traffic diverge and OAuth can fail in environments that rely on the custom factory.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a39f12ca52
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if auth.httpx_client_factory is httpx.AsyncClient: | ||
| factory = self.httpx_client_factory or self._make_verify_factory() |
There was a problem hiding this comment.
Refresh OAuth verify factory for reused auth objects
This guard only rewires an OAuth instance when its factory is exactly httpx.AsyncClient, so a previously injected verify-aware factory is treated as “custom” and never updated on the next transport. In practice, reusing one OAuth() across transports (e.g. first verify=False, then verify=True) leaves OAuth preflight/token requests on the stale TLS policy from the first transport, so the second transport’s verify setting is ignored; I reproduced this with StreamableHttpTransport, and the same _set_auth pattern exists in sse.py.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
We are devolving into more and more unlikely edge cases.
Connecting to MCP servers with self-signed certificates or internal CAs currently requires constructing a custom
httpx_client_factory— boilerplate that shouldn't be necessary for such a common enterprise/development scenario.The
Client,StreamableHttpTransport, andSSETransportnow accept averifyparameter matching httpx conventions (bool, cert path string, orssl.SSLContext):The parameter is applied after transport inference rather than being threaded through
infer_transport, so it only touches HTTP-based transports — passingverifywith an in-memory or stdio transport raises a clear error.Closes #717