You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: server wire-edges P2 batch — ALL 73 driver gaps now closed
Final batch: 29 fixed + 4 dispositioned (with BP-3/PAT-G9/CF-9/SCHEMA-G5
rationale recorded in the register). The register stands at 73/73 closed
(1/1 P0, 14/14 P1, 58/58 P2 — 52 fixed, 6 dispositioned total).
Behavior:
- null request ids → 400 + -32600 pre-dispatch, both lanes (MCP forbids
them; turul-rpc keeps its base-JSON-RPC Null variant) — revert-and-fail
proven.
- Invalid pagination cursors → -32602 at all five list sites (cursor must
be one the server issued) — revert-and-fail proven. NOTE: three
2025-lane e2e tests asserted the old non-spec leniency (fabricated
"test_cursor" succeeding silently) — migrated WITH the contract; the
2025 pagination spec carries the same SHOULD.
- completion/complete is no longer a default handler: unconfigured server
→ 404 + -32601. Default handler counts migrated (2026: 14, 2025: 21).
- Blob resource contents validated as base64 before shipping.
- prompts/list carries title/icons/_meta; initialize rejection names
supported versions in error.data; X-Accel-Buffering: no on streaming
responses; tool-name format warnings at registration (SHOULD-level);
Mcp-Param message whitespace runs collapsed.
- New session helpers: notify_elicitation_complete(elicitation_id),
notify_request_progress_with_message(progress, total, message).
- PromptAnnotations moved protocol→builders (no schema counterpart in
DRAFT-2026-v1 — protocol-purity). Fallout fixed across prompts-server,
prompts-test-server, tests/prompts bin, a glob ambiguity, and a real
macro-hygiene bug (prompt! expanded a bare PromptAnnotations relying on
call-site scope — now fully qualified).
Tests: wire_edges_2026.rs (10 — null id, _meta branches, initialize
versions, unknown tool/resource/prompt codes, list determinism +
pagination walk + cacheable fields, blob encoding, prompt descriptors,
completion -32601, logging capability), numeric Mcp-Param compare,
roots/sampling -32003 capability arms, SEP-2577 marker tripwire
(reverting Slice A'' now fails the protocol crate's tests).
Gates: scripts/ci-gates.sh all → ALL GATES PASSED.
Copy file name to clipboardExpand all lines: CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
20
20
21
21
### Added
22
22
23
+
- **Server wire-edges P2 batch — the FINAL open driver gaps (2026-06-11).** All 73 audit gaps are now closed (52 fixed, 6 dispositioned with recorded rationale). Behavior: null request ids → 400 + -32600 pre-dispatch (MCP forbids them; turul-rpc's base-JSON-RPC Null variant stays); invalid pagination cursors → -32602 at all five list sites; `completion/complete` no longer a default handler (unconfigured server → 404 + -32601); blob resource contents validated as base64 before shipping; prompts/list carries title/icons/_meta; the initialize rejection names supported versions in error.data; `X-Accel-Buffering: no` on streaming responses; tool-name format warnings at registration; Mcp-Param message whitespace runs collapsed; `notify_elicitation_complete` + `notify_request_progress_with_message` session helpers; `PromptAnnotations` moved protocol→builders (no schema counterpart — purity). Tests: `wire_edges_2026.rs` (10), numeric Mcp-Param compare, roots/sampling -32003 arms, SEP-2577 marker tripwire (reverting Slice A'' now fails CI). Dispositions: schema-dialect validation (documented limitation), progress rate-limiting (middleware layer per ADR-012), sampling message-shape constraints (deprecated surface), tool-Err-vs-isError (deliberate AGENTS.md-documented contract: `Err` = protocol error, `CallToolResult::error` = model-visible). EXAMPLES_PIN capture date corrected. Closes **CHG/G4, CHG/G6, DEP-GAP-3, BP-2/3/4, VER-2, PAT/G5/G9, TX/GAP-3/4/5, CF/GAP-CF-6/7/9, DISC-4, PRM-2026-01/04/05, RES-G3/G6/G7, TOOLS-G3/G4/G6/G7, UTIL/COMP-2, UTIL/PAG-1/2, UTIL/LOG-2, SCHEMA/G2/G3/G5**.
23
24
- **Client capability/discovery P2 batch (2026-06-11).** (1) The `server/discover` body is now retained for the connection: `DiscoveredServer` (capabilities, instructions, serverInfo, supportedVersions) with `discovered_server()`/`server_capabilities()`/`server_instructions()` accessors. (2) `-32004` negotiation honors `error.data.supported`: fallback only when 2025-11-25 is mutually supported, otherwise the error names the server's list ("select a mutually supported version … or surface an error"). (3) Era detection no longer keys on one code: structured `-32602` also classifies as a legacy-server fallback signal per "commonly -32601 or -32602" (the prior -32602→abort unit pin migrated WITH the contract). (4) `DeclaredCapabilities` gains `elicitation_url`/`sampling_tools`/`sampling_context`, mapped into the spec's sub-capability shapes in every request `_meta`. (5) `call_tool` auto-recovers from `-32001` Mcp-Param rejections: one `tools/list` refresh + one retry per the SEP-2243 client-behavior note. (6) New `call_tool_with_progress(name, args, token, on_progress)`: SSE-framed request with `_meta.progressToken`, progress params delivered to the callback before the final result (real-server e2e). (7) `McpClientError::is_resource_not_found()` accepts `-32602` and the backwards-compat `-32002`. (8) First-page contract documented on the convenience list APIs (use `*_paginated` for full walks). structuredContent validation dispositioned (apps bring their own validator — no 2020-12 validator dependency for a SHOULD). Closes driver gaps **ARCH/GAP-ARCH-1, ARCH/GAP-ARCH-2, DISC-1, VER-3, CF/GAP-CF-5, TX/GAP-6, TX/GAP-7, RES-G4, UTIL/PAG-3, PAT/G4, TOOLS-G2**.
24
25
- **Subscriptions/cancellation P2 batch (2026-06-11, mostly tests).** New wire coverage: concurrent `subscriptions/listen` streams each receive exactly their filtered subset stamped with their own `subscriptionId`, and `notifications/message` never rides a listen stream (MUST NOT); dropping one subscription leaves siblings delivering; progress notifications stop at the final response (MUST); MRTR negative paths (neither-field `InputRequired` → server error; `InputRequired` escaping `completion/complete` → error, never `input_required`); unrecognized `logLevel` → `-32602`. Code: `notifications/cancelled` is now an explicitly registered notification on both lanes (202, never 404 — note: the 202 wire contract for true notifications pre-existed via the transport's fire-and-forget path; the registration adds sibling parity and the request-shaped consistency). Cancellation of in-flight work on Streamable HTTP remains the stream-close mechanism; cross-request correlation by id is impossible without sessions on the stateless lane, so inbound cancelled notifications are accepted and ignored per "Invalid cancellation notifications SHOULD be ignored". Server-shutdown stream teardown dispositioned (socket-close; no graceful-shutdown API exists). Closes driver gaps **PAT/G6, PAT/G7, PAT/G8, TOOLS-G5, UTIL/LOG-1, SCHEMA/G1**.
25
26
- **OAuth/security P2 batch (2026-06-11).** (1) *Malformed Authorization → 400*: a present-but-unparseable `Authorization` header (wrong scheme, empty/multi-token Bearer) now answers 400 + `error="invalid_request"` (RFC 6750 §3.1) instead of the missing-credentials 401 — `RequestContext::authorization_malformed` is set by both transports; wire-tested. (2) *Runtime scope enforcement*: `OAuthResourceMiddleware::with_required_scopes` rejects tokens missing a required scope with 403 + `error="insufficient_scope"` per Authorization §Insufficient Scope; unit-tested with minted HS256 tokens. (3) *offline_access guard*: `ProtectedResourceMetadata::with_scopes` filters `offline_access` with a warning (resource servers SHOULD NOT advertise it). (4) *Sessionless-ping auth*: on the 2025-11-25 lane, the `allow_unauthenticated_ping` bypass now runs AFTER the pre-session auth phase — it waives the session requirement only, matching its documented contract ("the full middleware stack still runs"); new 2025-lane wire test `tests/ping_auth_2025.rs` wired into the gates. (5) *Session-user binding (AUTH-7)*: dispositioned by design — claims stay request-scoped per ADR-021 D2; deployments needing binding implement it via middleware + session state; moot on the sessionless 2026 lane. Closes spec-compliance driver gaps **AUTH-2, AUTH-3, AUTH-5, AUTH-6 (fixed) + AUTH-7 (dispositioned)** — the OAuth/security P2 theme is closed.
0 commit comments