1111
1212The original audit found three structural holes and eight bugs. ** All eight bugs and all three structural
1313holes are closed** , along with the Tasks extension, the extensions framework, subscriptions delivery,
14- request-scoped streaming, the caching policy, deprecations, docs and an end-user example.
14+ request-scoped streaming, the caching policy, deprecations, docs and end-user examples. The ** client** now
15+ speaks the revision too, so both halves of the SDK are on 2026-07-28.
1516
1617| | Before | After |
1718| --- | --- | --- |
1819| Modern conformance (` make conformance-draft-server ` ) | 138 passed / 3 failed | ** 151/151** |
1920| Handshake conformance (` make conformance-server ` ) | 39/39 | ** 80/80** |
2021| Server baseline entries | 3 | ** 0** |
21- | Unit tests | 1222 | ** 1421** |
22- | Integration tests | 33 | ** 43** |
22+ | Modern client conformance (` make conformance-draft-client ` ) | not gated | ** baseline clean** |
23+ | Unit tests | 1222 | ** 1476** |
24+ | Integration tests | 33 | ** 47** |
2325| Inspector snapshot tests | 97 | ** 103** |
2426| Tasks conformance (` tasks-* ` , nine scenarios) | n/a | every failure the runner's core-schema check |
2527| PHPStan | 7 pre-existing errors | 7 pre-existing errors |
2628
27- The server side now passes both revisions outright: the two failures the branch had disclaimed turned out
29+ Both sides now pass both revisions outright. The two server failures the branch had disclaimed turned out
2830to be fixture bugs, not SDK ones — a resource template echoing back its own ` {id} ` pattern instead of the
2931resolved URI, and a ` json_schema_2020_12_tool ` neither conformance server defined. The check counts jumped
3032because the runner is now pinned to a version that carries the 2026-07-28 scenarios and is run with
3133` --suite all ` on both revisions.
3234
3335** What is done** — §A lifecycle & transport · §B MRTR · §C headers & metadata · §D results & caching ·
34- §E errors & schema · §F subscriptions · §G1 extensions framework · §G2 Tasks · §I1 deprecations · §I3 docs.
36+ §E errors & schema · §F subscriptions · §G1 extensions framework · §G2 Tasks · §I1 deprecations · §I3 docs ·
37+ the client side of all of it.
3538
3639** What remains** — §3.1 MCP Apps ergonomics (an attribute and a scheme check) · §3.2 Authorization (mostly
3740blocked: there is no client-side OAuth for those rules to constrain yet) · §3.3 ` anyOf ` for a union of two
38- different array shapes · §3.4 conformance traceability · ** §3.5 the client half of 2026-07-28, which is
39- untouched** . None is a MUST-level gap for a server implementation.
41+ different array shapes · §3.4 conformance traceability. None is a MUST-level gap.
4042These are tracked in [ §3] ( #3-remaining-work ) with the same requirement/evidence/action shape as the original
4143audit. Everything else in this document is kept as the record of what was found and how it was closed.
4244
@@ -213,25 +215,6 @@ Related: #370 (`additionalProperties` unsupported) and #397 (phpstan/psalm numbe
213215to wire SEP traceability files into the runner and surface per-SEP pass rates; #368 is the Tier 2 gap
214216analysis, for which this document is input.
215217
216- ### 3.5 The client does not speak 2026-07-28 — P1, no upstream issue yet
217-
218- Everything above is the ** server** half. Gating the client suite on the modern revision (see §4) shows the
219- client still opens with ` initialize ` regardless of the revision it is pointed at, so it never reaches the
220- stateless wire at all. Seven scenarios fail on that one root cause:
221-
222- | Scenario | What is missing |
223- | --- | --- |
224- | ` request-metadata ` | the per-request ` _meta ` envelope, ` MCP-Protocol-Version ` header, client info and capability declarations (SEP-2575) |
225- | ` http-standard-headers ` | ` Mcp-Method ` on every POST, ` Mcp-Name ` on the addressed methods (SEP-2243) |
226- | ` http-custom-headers ` | ` x-mcp-header ` → ` Mcp-Param-* ` mirroring, value encoding, the Base64 sentinel, null omission (SEP-2243) |
227- | ` http-invalid-tool-headers ` | refusing a tool whose header annotations do not validate (SEP-2243) |
228- | ` sep-2322-client-request-state ` | echoing ` requestState ` , a fresh JSON-RPC id per round, parallel isolation (SEP-2322) |
229- | ` tools_call ` , ` json-schema-2020-12-preservation ` | cascade only — both need a reachable ` tools/list ` |
230-
231- The pieces exist server-side (` StatelessProtocol ` , ` StandardHeaderValidator ` , the MRTR machinery), so this
232- is a matter of giving the client the same wire, not new protocol work. Baselined per-scenario so the
233- entries double as the work list.
234-
235218---
236219
237220## 4. Verification
@@ -243,16 +226,16 @@ four run in CI — `.github/workflows/pipeline.yaml` matrixes each role over the
243226make conformance-server # handshake endpoint — 80/80
244227make conformance-draft-server # modern endpoint — 151/151
245228make conformance-client # handshake — baseline clean (auth stack absent, §3.2)
246- make conformance-draft-client # modern — baseline clean (§3.2 + §3.5 )
229+ make conformance-draft-client # modern — baseline clean (auth stack absent, §3.2 )
247230
248231# Tasks (off the spec timeline, so --force and one scenario at a time):
249232npx @modelcontextprotocol/conformance@0.2.0-alpha.11 server --url http://localhost:8000/stateless \
250233 --scenario tasks-lifecycle --spec-version 2026-07-28 --force
251234# Every remaining failure is the runner's wire-schema-valid check applying the
252235# *core* schema to an extension result.
253236
254- vendor/bin/phpunit --testsuite=unit # 1421
255- vendor/bin/phpunit --testsuite=integration # 43 , boots the example over real HTTP
237+ vendor/bin/phpunit --testsuite=unit # 1476
238+ vendor/bin/phpunit --testsuite=integration # 47 , boots the examples over real HTTP
256239vendor/bin/phpunit --testsuite=inspector # 103 (7 skipped); handshake-era examples only
257240vendor/bin/phpstan --memory-limit=-1 # 7 pre-existing errors, all alreadyNarrowedType under PHP 8.5
258241vendor/bin/php-cs-fixer fix
@@ -264,6 +247,8 @@ the dated revision and `alpha` for the draft one, which is what keeps the pin fr
264247
265248** The Inspector cannot reach a modern-lifecycle server.** It opens with ` initialize ` , which this revision
266249removed, so ` tests/Inspector/ ` covers the handshake-era examples only. The
267- ` stateless-lifecycle ` example is verified instead by ` tests/Integration/StatelessLifecycleTest.php ` , which
268- drives it over real HTTP the way a conforming client would — discovery, a tool call, both MRTR rounds, a
269- tampered ` requestState ` , and the response stream carrying interleaved progress and log notifications.
250+ ` stateless-lifecycle ` example is verified instead by two integration tests, one per direction:
251+ ` StatelessLifecycleTest ` drives it with hand-built HTTP the way a conforming client would — discovery, a
252+ tool call, both MRTR rounds, a tampered ` requestState ` , and the response stream carrying interleaved
253+ progress and log notifications — and ` StatelessClientTest ` drives it with the SDK's own client, which is
254+ what proves that client is conforming.
0 commit comments