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(ext-tasks): bilingual client task surface (slice B)
Opt-in ext-tasks feature on turul-mcp-client:
- declared_capabilities.ext_tasks declares io.modelcontextprotocol/tasks
in every 2026 request's _meta clientCapabilities.extensions (unit
tests pin both the declared shape and the no-opt-in absence)
- call_tool_or_task(name, args) -> ToolCallOutcome::Completed | Task —
the server is the sole decider (SEP-2663), so the API is the honest
union; plain call_tool keeps the strict BP-1 unknown-resultType
rejection
- task_get / task_update / task_cancel bind the lifecycle; task_wait
polls to a terminal status honoring pollIntervalMs (clamped 50ms-30s)
4 real-server e2e tests (ext_tasks_e2e_2026.rs; gates + CI step):
task→poll→completed, sync fallback for undeclared clients, task_update
resuming an input_required task, cancel-to-cancelled. Full client suite
162-passing under the feature. Revert-and-fail recorded: suppressing
the capability emission fails task_outcome_polls_to_completion with a
sync result (also live-proving the server's progressive enhancement).
Full ci-gates.sh all green.
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
+
- **Tasks-extension client surface (2026-06-12, SEP-2663 — slice B).** New opt-in `ext-tasks` feature on `turul-mcp-client`: `declared_capabilities.ext_tasks = true` declares `io.modelcontextprotocol/tasks` in every 2026 request's `_meta` `clientCapabilities.extensions`; `call_tool_or_task(name, args)` returns `ToolCallOutcome::Completed | Task` (the server is the sole decider — the typed union replaces guessing); `task_get`/`task_update`/`task_cancel` bind the lifecycle methods; `task_wait` polls to a terminal status honoring the server's `pollIntervalMs` (clamped 50ms–30s). The strict BP-1 parser is untouched — plain `call_tool` still rejects unknown `resultType`s; only the ext-aware path accepts `"task"`. 4 real-server e2e tests (`ext_tasks_e2e_2026.rs`, gates + CI): task→poll→completed, sync fallback for undeclared clients, `task_update` resuming an `input_required` task, cancel-to-cancelled; revert-and-fail recorded (suppressing the capability emission fails the task-outcome test with a sync result).
23
24
- **Tasks-extension server runtime (2026-06-12, SEP-2663 — closes driver gap G1).** New opt-in `ext-tasks` feature on `turul-mcp-server` (off by default per SEP-2133): `.with_ext_tasks(store)` advertises `io.modelcontextprotocol/tasks` in `server/discover`'s `capabilities.extensions` and registers `tasks/get`/`tasks/update`/`tasks/cancel`; `.ext_task_tool(tool)` / `.ext_task_tool_required(tool)` mark tools for task election — a request whose per-request `_meta` `clientCapabilities.extensions` declares the extension gets a durable `CreateTaskResult` (UUIDv4 bearer-grade id, store written BEFORE the response) with a spawned worker; undeclared requests run synchronously (progressive enhancement) or, for `_required` tools, get `-32003` with the upstream `data.requiredCapabilities.extensions` shape. **MRTR bridge**: a task tool returning `McpError::InputRequired` parks its task in `input_required`; `tasks/update` validates response keys against outstanding requests (partial delivery keeps it parked) and resumes the worker with the responses injected through the same session-extension keys as the sync retry leg — tool code is identical under both execution models. `tasks/cancel` is cooperative (aborts the worker, drops input waiters, acks terminal tasks). `notifications/tasks` rides `subscriptions/listen`: the transport honors a `taskIds` filter iff the extension is advertised (keyed off the capability map — no transport dependency on the ext crate), echoes it in the ack, and delivers per-taskId. `turul-mcp-ext-tasks` gains the `TaskStore` trait + `TaskState` + `InMemoryTaskStore` (no tokio in the public API). 9 wire e2e tests (`ext_tasks_2026.rs`, wired into gates + CI); revert-and-fail recorded. Dispatcher design recorded in ADR-028 (2026-06-12 entry).
24
25
-**`turul-mcp-ext-apps` 0.1.0 scaffold (2026-06-12, SEP-1865).** Spec-neutral extension crate binding the MCP-side Apps surface: extension identifier `io.modelcontextprotocol/ui` (the ADR-028 table's `/apps` guess corrected against upstream), client capability (`UiClientCapabilities.mimeTypes` + the `text/html;profile=mcp-app` HTML-views gate), tool `_meta.ui` (`UiToolMeta`: `resourceUri`, `visibility` model/app), and UI-resource `_meta.ui` (`UiResourceMeta`: CSP domain lists, sandbox permissions, dedicated origin, `prefersBorder`). The host↔view iframe protocol is deliberately not bound (app/host SDK scope). Vendored spec pinned at `modelcontextprotocol/ext-apps@ca1d2989`; 5 wire-shape compliance tests.
25
26
- **Versioning/cancellation/elicitation P2 trio (2026-06-12).** (1) **VER-4**: the headerless-`initialize` rejection (400 + `-32001`) now carries `error.data.supported` naming this build's protocol versions — a true legacy client's only diagnostic; wire test `headerless_initialize_rejection_names_supported_versions`, red-phase recorded. (2) **PAT/G10**: dedicated `CancelledNotificationHandler` extracts `requestId` + `reason` from inbound `notifications/cancelled` into a structured log line ("Both parties SHOULD log cancellation reasons"); accepted-and-ignored semantics unchanged. (3) **CF/GAP-CF-8**: new `turul_mcp_builders::validate_elicit_content(schema, content)` validates elicited form content against the requesting schema (required/unknown keys, primitive types, string-length/numeric bounds, integer-ness, enum membership across the 2026 enum-union shapes; format assertions annotation-only by design) — central enforcement is impossible on the stateless lane (leg-1 schema not retained), so tools call it on the MRTR retry; wired into `mrtr-elicitation-server` and live-verified. Plus **BP-5** (COMPLIANCE.md §"Supported JSON Schema dialects" — the documentation the SHOULD asks for) and **UTIL/COMP-3** (relevance/fuzzy/rate-limit completion SHOULDs dispositioned: provider semantics + middleware rate limiting). Driver summary now 305 ✅ / 68 🟡 / 5 ❌ / 12 🧪 / 100 ➖ — the 5 remaining ❌ all carry recorded dispositions.
0 commit comments