[Docs][Examples][CI] Document and gate the 2026-07-28 lifecycle (#457)

docs/stateless-lifecycle.md walks the revision end to end - per-request
_meta, server/discover, multi round-trip requests, caching and subscriptions
- and a runnable example on each side shows what that looks like in code.

CI matrixes both conformance roles over both revisions. --spec-version is
cumulative across the dated revisions, so 2025-11-25 covers the two before
it; 2026-07-28 is not cumulative with them and needs its own run against its
own baseline. The runner is pinned so a PR only goes red for reasons in the
PR, and conformance-weekly tracks the moving target instead - on both
revisions, since the draft scenarios ship only on the alpha dist-tag.

The Inspector cannot reach a modern-lifecycle server (it opens with
initialize), so the example is covered by integration tests instead: one
drives it with hand-built HTTP the way a conforming client would, one drives
it with this SDK's client, and one drives the single endpoint from both eras.
This commit is contained in:
Christopher Hertel 2026-08-19 03:24:17 +02:00 • committed by GitHub
commit 7fe88677ad
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -146,7 +146,6 @@ When the `middleware` argument is omitted (or set to `null`), the transport inst
|-------|------------|---------|
| 1 | `CorsMiddleware` | Applies CORS headers to every response. By default does **not** set `Access-Control-Allow-Origin` (cross-origin requests are blocked). |
| 2 | `DnsRebindingProtectionMiddleware` | Validates `Origin`/`Host` against an allowlist. Defaults to localhost variants only. |
| 3 | `ProtocolVersionMiddleware` | Rejects requests carrying an unsupported `MCP-Protocol-Version` header with `400 Bad Request`. |
```php
// Zero-config, secure-by-default — local servers get full protection automatically.
@ -159,6 +158,13 @@ The default stack can be inspected and recomposed via the public factory:
$middleware = StreamableHttpTransport::defaultMiddleware();
```
These run at the edge, before the request's protocol era is known, because what they enforce is true of
both eras. `ProtocolVersionMiddleware` is not in that stack: the `MCP-Protocol-Version` header rule belongs
to the handshake era, so the transport applies it only to requests it classified as handshake-era traffic,
and the modern leg answers for its own revisions. It is available as
`StreamableHttpTransport::handshakeMiddleware()` and is applied whether or not you replace the edge stack.
See [Serving both eras](stateless-lifecycle.md#serving-both-eras).
### CORS Configuration
CORS is handled by `CorsMiddleware`. To enable cross-origin browser requests, configure it explicitly and pass it