Follow-up to #107. Implement the io.modelcontextprotocol/tasks extension so multi-minute analytical queries (BigQuery/SAP/Iceberg via DuckDB) return a durable taskId immediately instead of blocking the HTTP connection until a proxy times out. Design in research ISSUES.md (#17).
- C10 — durable store:
mcp_task_store backed by DuckLake/CacheManager (flapi_mcp_tasks: task_id UUID, tool, principal, status, timestamps, ttl_ms, poll_interval_ms, request/result/error json). Invariants in the store API (terminal immutability, create-before-respond); GC via existing HeartbeatWorker.
- C11 — worker pool: new bounded pool (
mcp.tasks.workers, queue-depth); per-task DuckDB connection so duckdb_interrupt implements tasks/cancel; shutdown interrupts + joins with a deadline and durably marks in-flight tasks failed; boot sweep working→failed.
- C12 — RPCs + gating + YAML:
tasks/get/tasks/cancel (+tasks/update iff the extension requires server receive); task path only when modern era ∧ client declares the tasks capability, else always synchronous (legacy clients never observe a task); tasks/get re-checks principal every call; mcp-tool.async / async-after YAML; advertise the extension in server/discover. New test_mcp_tasks.py (lifecycle, cancel, TTL, principal isolation, sync fallbacks, restart recovery, saturation).
Depends on the dual-era core (Tranche 1) for the modern envelope and capability negotiation.
Follow-up to #107. Implement the
io.modelcontextprotocol/tasksextension so multi-minute analytical queries (BigQuery/SAP/Iceberg via DuckDB) return a durabletaskIdimmediately instead of blocking the HTTP connection until a proxy times out. Design in researchISSUES.md(#17).mcp_task_storebacked by DuckLake/CacheManager (flapi_mcp_tasks: task_id UUID, tool, principal, status, timestamps, ttl_ms, poll_interval_ms, request/result/error json). Invariants in the store API (terminal immutability, create-before-respond); GC via existingHeartbeatWorker.mcp.tasks.workers,queue-depth); per-task DuckDB connection soduckdb_interruptimplementstasks/cancel; shutdown interrupts + joins with a deadline and durably marks in-flight tasks failed; boot sweepworking→failed.tasks/get/tasks/cancel(+tasks/updateiff the extension requires server receive); task path only when modern era ∧ client declares the tasks capability, else always synchronous (legacy clients never observe a task);tasks/getre-checks principal every call;mcp-tool.async/async-afterYAML; advertise the extension inserver/discover. Newtest_mcp_tasks.py(lifecycle, cancel, TTL, principal isolation, sync fallbacks, restart recovery, saturation).Depends on the dual-era core (Tranche 1) for the modern envelope and capability negotiation.