Cover MCP catalog and tool execution with 28 declarative scenarios

Draft
VA
1d ago
+1072-120

Problem

MCP catalog, authorization and result projection lacked shared data scenarios. The first cases asserted a nonexistent turn_completed record. Explicit pinned calls also exposed a production bug: the next request validated history solely against advertised tools, rejecting admitted hidden revisions.

Design

Add 28 short MCP cases over production catalog installation, remote dispatch, schema enforcement and projection with an immutable scripted transport. Cover visible/hidden pinned revisions, selected schemas, exact names/arguments, text/Unicode, images, metadata, structured output, server failures, multiple calls, denied grants and invalid input/output. Assert the real final response Model::Completed record at step 1.

Retain only missing historical revision definitions in immutable prepared request/prefix files. Resolve exact names/revisions, validate arguments and projections, and reject duplicate/conflicting schemas without advertising hidden tools. Update constructors, cloning, inventories, bounded JSON schemas and ownership accounting; ordinary requests retain an allocation-free empty-history path. The merge preserves both main's manifest-pinning method and this historical resolver.

Deletions

Reuse the shared scripted provider, runner, Driver trait and matcher; no model fake, background service, synchronization primitive or registry. #611 is now on main. Current PR delta: +1072/-120, net +952 lines. Seven request/prefix seeds supplement seven MCP-script seeds. Touched source/test files remain within their line limits.

Tests run

All gates ran on bb1 through bs.ps1 at signed b326f1e37bc26076e4de6fe4887b26204ceb57ce before push:

  • One focused native lib/e2e build with filesystem-local,mcp-http, followed by direct binary runs.
  • 19 model tests: 0.20 s; 12 registry tests: 0.90 s; four context-manifest tests: 0.06 s; ten tool-prefix tests: <0.01 s.
  • All 39 shared tests: 0.43 s. All 370 scenarios: 0.159 s, including all 28 MCP cases, both pinned cases and every negative control.
  • model_request/prefix fuzzer: 512 ASan runs in <1 s, nightly-2026-07-01, scenarios, --dev, max_len=8192, rebuilt against merged dependencies.
  • Browser/WASM library check: cargo check -p acyclic-harness --features browser --target wasm32-unknown-unknown --lib --locked passed.
  • MCP-script codec: 512 ASan runs at 906116069 reused; that parser is unchanged.
  • Formatting and git diff --check passed. No whole-suite clock assertions, sleeps, polling, thread caps or workspace-wide gate.

Decisions

Historical schemas live in the already-retained request/prefix files because canonical decode and recovery must work without a live registry. Advertisement stays separate and Model.options stays untouched. No new store, tool or wire protocol. The MCP backend does not imitate a model. Shrinking properties verify revision binding, schema/projection validation, codecs and argument equality; controls keep unrelated admission conditions valid. Corpus seeds and cargo-fuzz cover request and prefix parsing.

Follow-up

Keep DRAFT until the cases use production request-file admission and assert actual task-volume follow records, terminal status and persisted output. #495 is merged: request-file consumption, status publication and snapshot-plus-follow are already available. The remaining producer gaps are precise: LocalHarness::bind creates TaskFiles without connecting runtime.bind_task_files; there are no production TurnRequest/Completion writers; and generic MCP tool request/result files are absent while Bash has its own writer. TaskFile::Chunk requires a text/reasoning channel and cannot hold arbitrary event JSON as a workaround. Track the producer/identity/fencing requirements at https://github.com/acyclic-labs/sdk/pull/495#issuecomment-6234718846. The existing one-Driver selection remains explicit component coverage; journal observations and unchanged sentinels do not establish that wire contract.

The main integration is preserved on signed hf/gc-e2e-mcp-main-checkpoint at 1db6f94c8d0b2593d1d4c25c31dedc47b011c554 (no new PR). This review branch remains b326f1e37 and DRAFT until the real file-backed contract is implemented and green. The checkpoint merges pinned main5a29e692f, including #852 and #905, and retains its existing five-second scenario guards after main's #669 removed them. Main's recent-window fixture omitted FileValue.requester; use the existing constructor and preserve its channel so future defaults are centralized.

At d8e226f05: 55 focused Harness tests and 24 provider tests passed; this includes the corrected nonempty token/accounting selections, five recent-window tests (0.05s), and native lost-ack/settlement (0.25s; resume4024bytes under4096, opening/reopening904, reconciliation3904). Five MCP controls passed0.72s; all28 MCP cases passed0.330s. Windows GNU Harness/Providers lib/tests passed6m12s; native compilation11m34s, excluded from runtime. The full target FAILED82passed/3failed/1pre-existingignored in9.06s, including135/766 scenario deadlines (family5.955s). The two additional failures were fs_family_rejects_bypassing_schema_rejection and fs_family_rejects_executing_a_rejected_command; they were not both timeouts. Stop-at-first-failure skipped the fuzz steps.

The first control used whitespace, which the executor also rejects: both inputs produced the same generic indeterminate outcome. A buildless trace established that a valid add command instead reaches another model request and is rejected by the unchanged exact-script-count assertion. Signed1db6f94c8 uses that distinguishing mutation and deletes duplicate oracle plumbing, keeping every assertion and guard. Its Windows Harness lib/tests check passed25.68s; the revised schema control passed0.25s and the bash corruption control0.36s. The rejected-command control still fails in0.10s at its unchanged baseline: actual terminal status is indeterminate, expected completed. Returning invalid calls to the model and settling their cause is owned by open #899; do not weaken that baseline. No unchanged full-target rerun or new fuzz pass is claimed. Unchanged library/provider results above are reused.

Artifacts e2e-mcp-resume-p295y_38 and e2e-schema-control-d9hxn53h are retained in the lane target directory. Commands, logs, source gaps, failed gates and remaining work are in Q:/lanes/handoff-gc-e2e.md. No new performance/API series was opened.