MCP semantic data contract: normalize CallToolResult into payload data - #1769
MCP semantic data contract: normalize CallToolResult into payload data#1769RhysSullivan wants to merge 2 commits into
Conversation
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
executor-marketing | d2a8758 | Commit Preview URL Branch Preview URL |
Aug 27 2026, 08:18 AM |
Cloudflare preview
Sign-in is Cloudflare Access (one-time PIN to an allowed email). The preview has its own database and encryption key; it is destroyed when this PR closes. |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
executor-cloud | d2a8758 | Aug 27 2026, 08:19 AM |
@executor-js/cli
@executor-js/config
@executor-js/execution
@executor-js/sdk
@executor-js/codemode-core
@executor-js/runtime-quickjs
@executor-js/plugin-file-secrets
@executor-js/plugin-graphql
@executor-js/plugin-keychain
@executor-js/plugin-mcp
@executor-js/plugin-onepassword
@executor-js/plugin-openapi
executor
commit: |
e56e9ff to
d2a8758
Compare
|
Codex review findings addressed: the content side-channel type is inlined in the result union instead of a named definition (a provider's own |
Stacked on #1768. The structural fix from the design review (independently confirmed by the fresh-eyes Codex report):
ToolResult.datais the tool's SEMANTIC payload on every transport — the MCP CallToolResult envelope no longer reaches sandbox code, telemetry, or shape inference.Contract (core-owned,
tool-result-normalization.ts): per successful MCP call —structuredContentISdata; else a lone exact-JSON text block parses intodata(the Linear case); else lone prose is the string; else the ordered content-block array. Non-duplicate blocks ride inresult.content(the spec-mandated serialized duplicate of structuredContent is suppressed — payloads stop being paid for twice);_metamoves toresult.meta.isErrorhandling unchanged.Mechanism: persisted
tool.result_encodingcolumn (direct|mcp-call-tool-result-v2, NULL = direct) stamped by the MCP plugin at catalog sync;executor.executeapplies the encoding after invocation, before telemetry and shape observation. The MCP plugin now persists the server's declared output schema DIRECTLY (it typesdata), no synthesized envelope — schemaless MCP tools fall under the plain observed-shape serve rule with contract-scoped recall (#1768).No data migration: MCP catalogs re-sync on a 15-minute TTL, so rows stamp themselves with the encoding on their next use — per-row atomic (NULL = fully old behavior, stamped = fully new), fleet-converged within minutes of the deploy. Old envelope-shaped learned shapes are invalidated by contract-scoped recall, no deletion pass. Migrations here are the additive nullable column only (drizzle for both hosts + the sqlite boot safety net, following the origin_redirect_uri precedent).
Describe surface: the result union models see becomes
{ ok: true; data: T; content?: ToolContentBlock[]; meta?: unknown; http?: ToolHttpMeta } | …; execute skill text documents the contract ("never look for data.content[0].text").Evidence: e2e journey passing on selfhost AND cloud — cold describe
data: unknownwith no envelope, sandbox code receives{ value: "hi", length: 2, ok: true }directly, warm describe serves the observed payload type with provenance. MCP plugin suite 147 passing with contract assertions rewritten (prose→string, structured→semantic+side channels, multi-block→array). Full typecheck 44/44; every package suite green in isolation (the fully-parallel local run flakes on 5s OAuth-fixture timeouts in varying packages, as on prior PRs — CI shards adjudicate).Blast radius (enumerated in the design discussion): ephemeral sandbox scripts self-heal via describe; ~10 of 117 saved artifacts read envelope fields and will need edits after this deploys; console/apps-shell reads only the outer execute envelope, unaffected.