Skip to content

Commit 4351721

Browse files
committed
Document httpx2 exception migration and the TLS change in whats-new
Old except httpx.X handlers fail silently after the swap because httpx usually stays co-installed transitively, so the migration guide now calls out exception handlers, isinstance checks, and that httpx client objects are not interchangeable at runtime. The whats-new silent-changes list gains the certifi to system-trust-store entry. No-Verification-Needed: documentation-only change
1 parent 8a2dfbf commit 4351721

3 files changed

Lines changed: 17 additions & 5 deletions

File tree

docs/client/transports.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ Two things to notice:
5656

5757
One TLS note: `httpx2` verifies certificates against the operating system trust store (via
5858
[`truststore`](https://pypi.org/project/truststore/)), not a bundled CA list. In an environment with
59-
no usable system CA store some minimal containers set the standard `SSL_CERT_FILE`/`SSL_CERT_DIR`
59+
no usable system CA store (some minimal containers), set the standard `SSL_CERT_FILE`/`SSL_CERT_DIR`
6060
environment variables or pass an explicit `verify=ssl_context` to your `httpx2.AsyncClient`
6161
(background in
6262
[`httpx` and `httpx-sse` replaced by `httpx2`](../migration.md#httpx-and-httpx-sse-replaced-by-httpx2)).

docs/migration.md

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@ The SDK now depends on [`httpx2`](https://pypi.org/project/httpx2/) instead of
9999
`httpx`) with server-sent events support built in, so the separate `httpx-sse`
100100
dependency is gone.
101101

102-
The swap itself does not change any SDK signatures `streamable_http_client`
103-
and `sse_client` accept the same arguments as elsewhere in v2 but the client
102+
The swap itself does not change any SDK signatures - `streamable_http_client`
103+
and `sse_client` accept the same arguments as elsewhere in v2 - but the client
104104
type they expect is now `httpx2.AsyncClient`. If you construct your own client to pass as
105105
`http_client` (or build an `httpx2.Auth` subclass for `auth`), import from
106106
`httpx2`:
@@ -125,13 +125,24 @@ http_client = httpx2.AsyncClient(follow_redirects=True)
125125
changes. To consume SSE directly, use `httpx2.EventSource` (or
126126
`AsyncClient.sse()`) instead of the `httpx-sse` helpers.
127127

128+
Exception handlers need the same rename: the SDK now raises `httpx2`
129+
exceptions (`httpx2.ConnectError`, `httpx2.HTTPStatusError`, and so on), and
130+
this failure mode is silent. `httpx` usually stays installed as a transitive
131+
dependency of other packages, so an old `except httpx.ConnectError:` block
132+
keeps importing fine and simply never matches again. Audit `except httpx.`
133+
clauses and `isinstance` checks along with the imports. The same identity
134+
split applies to objects: `httpx` and `httpx2` types are not interchangeable
135+
at runtime, so an `httpx.AsyncClient` passed as `http_client` degrades in
136+
subtle ways (server-initiated messages stop arriving) instead of raising
137+
immediately.
138+
128139
TLS verification also changes: `httpx` validated certificates against the
129140
bundled `certifi` CA list, while `httpx2` validates against the operating
130141
system trust store via [`truststore`](https://pypi.org/project/truststore/).
131142
If your environment has no usable system CA store (some minimal containers),
132143
or you relied on certifi's bundle specifically, point the standard
133-
`SSL_CERT_FILE` or `SSL_CERT_DIR` environment variable at a CA bundle
134-
`httpx2` honors these before falling back to the system store or pass an
144+
`SSL_CERT_FILE` or `SSL_CERT_DIR` environment variable at a CA bundle
145+
(`httpx2` honors these before falling back to the system store), or pass an
135146
explicit `verify=ssl_context` to your `httpx2.AsyncClient`. Passing a CA
136147
bundle path as `verify="ca.pem"` or using the `cert=` parameter is deprecated
137148
in `httpx2`; build an `ssl.SSLContext` and configure it instead.

docs/whats-new.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ The renames announce themselves. These do not:
138138
* **URI templates are real RFC 6570 now.** `{+path}`, `{?query}` and friends work, matching is exact instead of regex-loose, and path traversal in extracted values is rejected by default. Stricter templates fail at decoration time, not on the first request. **[URI templates](servers/uri-templates.md)**.
139139
* **The streamable HTTP lifespan runs once**, at startup, and its state is shared by every session and request. In v1 it ran once per session, and once per request under `stateless_http=True`. Pools and caches built in a lifespan get dramatically cheaper; anything that acquired a per-connection resource there belongs in the handler body now. **[Lifespan](handlers/lifespan.md)**.
140140
* **`mcp dev` and `mcp install` pin the environment they spawn** to your installed SDK version. Both commands run your server in a fresh `uv run --with ...` environment, which used to resolve `mcp` to the newest stable release rather than the version you are developing against. **[Migration Guide](migration.md#mcp-dev-and-mcp-install-pin-the-spawned-environment-to-your-sdk-version)**.
141+
* **TLS certificates verify against the operating system trust store, not certifi.** The SDK's HTTP client is now `httpx2`, which validates through `truststore` instead of certifi's bundled CA list. Most environments never notice; a minimal container with no system CA store, or a private CA that only certifi's bundle knew about, starts failing the TLS handshake. Set `SSL_CERT_FILE`/`SSL_CERT_DIR` or pass `verify=ssl_context` to your client. **[Migration Guide](migration.md#httpx-and-httpx-sse-replaced-by-httpx2)**.
141142

142143
### Removed outright
143144

0 commit comments

Comments
 (0)