stitchkit 0.93.0 → 0.94.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +134 -0
- package/README.md +5 -2
- package/dist/agent-runtime/children-control.d.ts +6 -0
- package/dist/agent-runtime/children-control.d.ts.map +1 -0
- package/dist/agent-runtime/children-spawn.d.ts +6 -0
- package/dist/agent-runtime/children-spawn.d.ts.map +1 -0
- package/dist/agent-runtime/children-state.d.ts +46 -0
- package/dist/agent-runtime/children-state.d.ts.map +1 -0
- package/dist/agent-runtime/children-usage.d.ts +8 -0
- package/dist/agent-runtime/children-usage.d.ts.map +1 -0
- package/dist/agent-runtime/children.d.ts +11 -14
- package/dist/agent-runtime/children.d.ts.map +1 -1
- package/dist/agent-runtime/coding-tool-contract.d.ts +2 -1
- package/dist/agent-runtime/coding-tool-contract.d.ts.map +1 -1
- package/dist/agent-runtime/deferred-tool-types.d.ts +2 -2
- package/dist/agent-runtime/deferred-tool-types.d.ts.map +1 -1
- package/dist/agent-runtime/events.d.ts +1 -1
- package/dist/agent-runtime/events.d.ts.map +1 -1
- package/dist/agent-runtime/managed-tools.d.ts +1 -1
- package/dist/agent-runtime/managed-tools.d.ts.map +1 -1
- package/dist/agent-runtime/observability.d.ts +1 -1
- package/dist/agent-runtime/observability.d.ts.map +1 -1
- package/dist/{agent-runtime-openrouter.d.ts → agent-runtime/openrouter.d.ts} +3 -3
- package/dist/agent-runtime/openrouter.d.ts.map +1 -0
- package/dist/agent-runtime/projections.d.ts +1 -1
- package/dist/agent-runtime/projections.d.ts.map +1 -1
- package/dist/agent-runtime/run-acquisition.d.ts +17 -0
- package/dist/agent-runtime/run-acquisition.d.ts.map +1 -0
- package/dist/agent-runtime/run-execution-state.d.ts +133 -0
- package/dist/agent-runtime/run-execution-state.d.ts.map +1 -0
- package/dist/agent-runtime/run-execution.d.ts +17 -33
- package/dist/agent-runtime/run-execution.d.ts.map +1 -1
- package/dist/agent-runtime/run-failure.d.ts +18 -0
- package/dist/agent-runtime/run-failure.d.ts.map +1 -0
- package/dist/agent-runtime/run-model-attempts.d.ts +6 -0
- package/dist/agent-runtime/run-model-attempts.d.ts.map +1 -0
- package/dist/agent-runtime/run-prompt-history.d.ts +58 -0
- package/dist/agent-runtime/run-prompt-history.d.ts.map +1 -0
- package/dist/agent-runtime/run-provider-ledger.d.ts +26 -0
- package/dist/agent-runtime/run-provider-ledger.d.ts.map +1 -0
- package/dist/agent-runtime/run-stream-parts.d.ts +17 -0
- package/dist/agent-runtime/run-stream-parts.d.ts.map +1 -0
- package/dist/agent-runtime/run-terminal.d.ts +11 -0
- package/dist/agent-runtime/run-terminal.d.ts.map +1 -0
- package/dist/agent-runtime/run-turn-preparation.d.ts +22 -0
- package/dist/agent-runtime/run-turn-preparation.d.ts.map +1 -0
- package/dist/agent-runtime/runtime-admission-gate.d.ts +29 -0
- package/dist/agent-runtime/runtime-admission-gate.d.ts.map +1 -0
- package/dist/agent-runtime/runtime-control.d.ts +9 -0
- package/dist/agent-runtime/runtime-control.d.ts.map +1 -0
- package/dist/agent-runtime/runtime-recovery.d.ts +10 -0
- package/dist/agent-runtime/runtime-recovery.d.ts.map +1 -0
- package/dist/agent-runtime/runtime-state.d.ts +36 -0
- package/dist/agent-runtime/runtime-state.d.ts.map +1 -0
- package/dist/agent-runtime/runtime-submit.d.ts +5 -0
- package/dist/agent-runtime/runtime-submit.d.ts.map +1 -0
- package/dist/agent-runtime/runtime.d.ts +9 -4
- package/dist/agent-runtime/runtime.d.ts.map +1 -1
- package/dist/{agent-runtime-sqlite-bun.d.ts → agent-runtime/sqlite-bun.d.ts} +5 -4
- package/dist/agent-runtime/sqlite-bun.d.ts.map +1 -0
- package/dist/agent-runtime/sqlite-events.d.ts +5 -0
- package/dist/agent-runtime/sqlite-events.d.ts.map +1 -0
- package/dist/agent-runtime/sqlite-history.d.ts +7 -0
- package/dist/agent-runtime/sqlite-history.d.ts.map +1 -0
- package/dist/agent-runtime/sqlite-ledger.d.ts +7 -0
- package/dist/agent-runtime/sqlite-ledger.d.ts.map +1 -0
- package/dist/{agent-runtime-sqlite-node.d.ts → agent-runtime/sqlite-node.d.ts} +5 -4
- package/dist/agent-runtime/sqlite-node.d.ts.map +1 -0
- package/dist/agent-runtime/sqlite-reads.d.ts +14 -0
- package/dist/agent-runtime/sqlite-reads.d.ts.map +1 -0
- package/dist/agent-runtime/sqlite-rows.d.ts +178 -0
- package/dist/agent-runtime/sqlite-rows.d.ts.map +1 -0
- package/dist/agent-runtime/sqlite-schema.d.ts +7 -0
- package/dist/agent-runtime/sqlite-schema.d.ts.map +1 -0
- package/dist/agent-runtime/sqlite-transactions.d.ts +25 -0
- package/dist/agent-runtime/sqlite-transactions.d.ts.map +1 -0
- package/dist/agent-runtime/sqlite.d.ts +10 -6
- package/dist/agent-runtime/sqlite.d.ts.map +1 -1
- package/dist/agent-runtime/store-archive.d.ts +16 -0
- package/dist/agent-runtime/store-archive.d.ts.map +1 -0
- package/dist/{testing/agent-store-conformance.d.ts → agent-runtime/store-conformance.d.ts} +2 -2
- package/dist/agent-runtime/store-conformance.d.ts.map +1 -0
- package/dist/agent-runtime/store-create.d.ts +11 -0
- package/dist/agent-runtime/store-create.d.ts.map +1 -0
- package/dist/agent-runtime/{store-driver.d.ts → store-driver-contract.d.ts} +7 -7
- package/dist/agent-runtime/store-driver-contract.d.ts.map +1 -0
- package/dist/agent-runtime/store-events.d.ts +7 -89
- package/dist/agent-runtime/store-events.d.ts.map +1 -1
- package/dist/agent-runtime/store-memory.d.ts +4 -0
- package/dist/agent-runtime/store-memory.d.ts.map +1 -0
- package/dist/agent-runtime/store-mutate.d.ts +13 -0
- package/dist/agent-runtime/store-mutate.d.ts.map +1 -0
- package/dist/agent-runtime/store-purge.d.ts +1 -1
- package/dist/agent-runtime/store-purge.d.ts.map +1 -1
- package/dist/agent-runtime/store-reads.d.ts +29 -0
- package/dist/agent-runtime/store-reads.d.ts.map +1 -0
- package/dist/agent-runtime/store-reduce-history.d.ts +10 -0
- package/dist/agent-runtime/store-reduce-history.d.ts.map +1 -0
- package/dist/agent-runtime/store-reduce-run.d.ts +14 -0
- package/dist/agent-runtime/store-reduce-run.d.ts.map +1 -0
- package/dist/agent-runtime/store-reduce-shared.d.ts +76 -0
- package/dist/agent-runtime/store-reduce-shared.d.ts.map +1 -0
- package/dist/agent-runtime/store-reduce-terminal.d.ts +6 -0
- package/dist/agent-runtime/store-reduce-terminal.d.ts.map +1 -0
- package/dist/agent-runtime/store-reducer.d.ts +24 -0
- package/dist/agent-runtime/store-reducer.d.ts.map +1 -0
- package/dist/agent-runtime/store-snapshot.d.ts +19 -0
- package/dist/agent-runtime/store-snapshot.d.ts.map +1 -0
- package/dist/agent-runtime/store.d.ts +1 -1
- package/dist/agent-runtime/store.d.ts.map +1 -1
- package/dist/application/admission.d.ts +1 -1
- package/dist/application/admission.d.ts.map +1 -1
- package/dist/application/events.d.ts +1 -1
- package/dist/application/events.d.ts.map +1 -1
- package/dist/{server → application}/file-state-store.d.ts +1 -1
- package/dist/application/file-state-store.d.ts.map +1 -0
- package/dist/application/health.d.ts +1 -1
- package/dist/application/health.d.ts.map +1 -1
- package/dist/application/kernel-admission.d.ts +8 -0
- package/dist/application/kernel-admission.d.ts.map +1 -0
- package/dist/application/kernel-contract.d.ts +142 -0
- package/dist/application/kernel-contract.d.ts.map +1 -0
- package/dist/application/kernel-resource-context.d.ts +24 -0
- package/dist/application/kernel-resource-context.d.ts.map +1 -0
- package/dist/application/kernel-restart.d.ts +5 -0
- package/dist/application/kernel-restart.d.ts.map +1 -0
- package/dist/application/kernel-rollback.d.ts +4 -0
- package/dist/application/kernel-rollback.d.ts.map +1 -0
- package/dist/application/kernel-shutdown.d.ts +6 -0
- package/dist/application/kernel-shutdown.d.ts.map +1 -0
- package/dist/application/kernel-start.d.ts +20 -0
- package/dist/application/kernel-start.d.ts.map +1 -0
- package/dist/application/kernel-state.d.ts +116 -0
- package/dist/application/kernel-state.d.ts.map +1 -0
- package/dist/application/kernel.d.ts +9 -140
- package/dist/application/kernel.d.ts.map +1 -1
- package/dist/application/latest-sink.d.ts +1 -1
- package/dist/application/latest-sink.d.ts.map +1 -1
- package/dist/application/opentelemetry.d.ts +1 -1
- package/dist/application/opentelemetry.d.ts.map +1 -1
- package/dist/application/watch-hub.d.ts +2 -2
- package/dist/application/watch-hub.d.ts.map +1 -1
- package/dist/browser/client-multipart.d.ts +1 -1
- package/dist/browser/client-multipart.d.ts.map +1 -1
- package/dist/browser/client-url.d.ts +1 -1
- package/dist/browser/client-url.d.ts.map +1 -1
- package/dist/browser/client.d.ts +1 -1
- package/dist/browser/client.d.ts.map +1 -1
- package/dist/browser/contract-stream.d.ts +1 -1
- package/dist/browser/contract-stream.d.ts.map +1 -1
- package/dist/browser/http.d.ts +1 -1
- package/dist/browser/http.d.ts.map +1 -1
- package/dist/browser/resumable.d.ts +1 -28
- package/dist/browser/resumable.d.ts.map +1 -1
- package/dist/browser/retained.d.ts.map +1 -0
- package/dist/browser/socket-io.d.ts +23 -1
- package/dist/browser/socket-io.d.ts.map +1 -1
- package/dist/browser/stream.d.ts +14 -2
- package/dist/browser/stream.d.ts.map +1 -1
- package/dist/contract/define.d.ts +72 -65
- package/dist/contract/define.d.ts.map +1 -1
- package/dist/{internal/errors.d.ts → contract/normalize.d.ts} +3 -39
- package/dist/contract/normalize.d.ts.map +1 -0
- package/dist/contract/tool-view.d.ts +135 -0
- package/dist/contract/tool-view.d.ts.map +1 -0
- package/dist/declaration/declaration.d.ts.map +1 -0
- package/dist/{agent-runtime/durability-contract.d.ts → durability/contract.d.ts} +2 -2
- package/dist/durability/contract.d.ts.map +1 -0
- package/dist/{agent-runtime/durability.d.ts → durability/engine.d.ts} +4 -4
- package/dist/durability/engine.d.ts.map +1 -0
- package/dist/durability/events.d.ts +101 -0
- package/dist/durability/events.d.ts.map +1 -0
- package/dist/{agent-runtime/durability-json.d.ts → durability/json.d.ts} +1 -1
- package/dist/durability/json.d.ts.map +1 -0
- package/dist/{agent-runtime/durability-ledger.d.ts → durability/ledger.d.ts} +2 -2
- package/dist/durability/ledger.d.ts.map +1 -0
- package/dist/{agent-runtime/durability-scheduler.d.ts → durability/scheduler.d.ts} +2 -2
- package/dist/durability/scheduler.d.ts.map +1 -0
- package/dist/entrypoints/agent-runtime/browser.d.ts +5 -0
- package/dist/entrypoints/agent-runtime/browser.d.ts.map +1 -0
- package/dist/{agent-runtime-browser.js → entrypoints/agent-runtime/browser.js} +3 -3
- package/dist/{agent-runtime-coding-tools.d.ts → entrypoints/agent-runtime/coding-tools.d.ts} +2 -2
- package/dist/entrypoints/agent-runtime/coding-tools.d.ts.map +1 -0
- package/dist/entrypoints/agent-runtime/coding-tools.js +22 -0
- package/dist/{agent-runtime-harness.d.ts → entrypoints/agent-runtime/harness.d.ts} +2 -2
- package/dist/entrypoints/agent-runtime/harness.d.ts.map +1 -0
- package/dist/{agent-runtime-harness.js → entrypoints/agent-runtime/harness.js} +24 -25
- package/dist/entrypoints/agent-runtime/openrouter.d.ts +2 -0
- package/dist/entrypoints/agent-runtime/openrouter.d.ts.map +1 -0
- package/dist/{agent-runtime-openrouter.js → entrypoints/agent-runtime/openrouter.js} +3 -3
- package/dist/{agent-runtime-sandbox.d.ts → entrypoints/agent-runtime/sandbox.d.ts} +5 -5
- package/dist/entrypoints/agent-runtime/sandbox.d.ts.map +1 -0
- package/dist/{agent-runtime-sandbox.js → entrypoints/agent-runtime/sandbox.js} +11 -12
- package/dist/entrypoints/agent-runtime/sqlite/bun.d.ts +2 -0
- package/dist/entrypoints/agent-runtime/sqlite/bun.d.ts.map +1 -0
- package/dist/{agent-runtime-sqlite-bun.js → entrypoints/agent-runtime/sqlite/bun.js} +8 -6
- package/dist/entrypoints/agent-runtime/sqlite/node.d.ts +2 -0
- package/dist/entrypoints/agent-runtime/sqlite/node.d.ts.map +1 -0
- package/dist/{agent-runtime-sqlite-node.js → entrypoints/agent-runtime/sqlite/node.js} +8 -6
- package/dist/entrypoints/agent-runtime/testing.d.ts +4 -0
- package/dist/entrypoints/agent-runtime/testing.d.ts.map +1 -0
- package/dist/entrypoints/agent-runtime/testing.js +1084 -0
- package/dist/{agent-runtime.d.ts → entrypoints/agent-runtime.d.ts} +41 -37
- package/dist/entrypoints/agent-runtime.d.ts.map +1 -0
- package/dist/{agent-runtime.js → entrypoints/agent-runtime.js} +408 -366
- package/dist/{application-diagnostic-journal.d.ts → entrypoints/application/diagnostic-journal.d.ts} +2 -2
- package/dist/entrypoints/application/diagnostic-journal.d.ts.map +1 -0
- package/dist/{application-diagnostic-journal.js → entrypoints/application/diagnostic-journal.js} +3 -3
- package/dist/{application-grammy.d.ts → entrypoints/application/grammy.d.ts} +2 -2
- package/dist/entrypoints/application/grammy.d.ts.map +1 -0
- package/dist/{application-grammy.js → entrypoints/application/grammy.js} +2 -2
- package/dist/{application-opentelemetry.d.ts → entrypoints/application/opentelemetry.d.ts} +2 -2
- package/dist/entrypoints/application/opentelemetry.d.ts.map +1 -0
- package/dist/{application-opentelemetry.js → entrypoints/application/opentelemetry.js} +4 -4
- package/dist/{application-schemas.d.ts → entrypoints/application/schemas.d.ts} +2 -2
- package/dist/entrypoints/application/schemas.d.ts.map +1 -0
- package/dist/{application-schemas.js → entrypoints/application/schemas.js} +2 -2
- package/dist/{application.d.ts → entrypoints/application.d.ts} +22 -21
- package/dist/entrypoints/application.d.ts.map +1 -0
- package/dist/{application.js → entrypoints/application.js} +24 -22
- package/dist/entrypoints/bin/upgrade-cli.d.ts.map +1 -0
- package/dist/{upgrade-cli.js → entrypoints/bin/upgrade-cli.js} +3 -3
- package/dist/{cli.d.ts → entrypoints/cli.d.ts} +15 -15
- package/dist/entrypoints/cli.d.ts.map +1 -0
- package/dist/{cli.js → entrypoints/cli.js} +30 -32
- package/dist/entrypoints/contract.d.ts +9 -0
- package/dist/entrypoints/contract.d.ts.map +1 -0
- package/dist/{contract/index.js → entrypoints/contract.js} +14 -6
- package/dist/entrypoints/declaration.d.ts +2 -0
- package/dist/entrypoints/declaration.d.ts.map +1 -0
- package/dist/{declaration.js → entrypoints/declaration.js} +1 -1
- package/dist/{files.d.ts → entrypoints/files.d.ts} +2 -2
- package/dist/entrypoints/files.d.ts.map +1 -0
- package/dist/{files.js → entrypoints/files.js} +3 -3
- package/dist/{geo.d.ts → entrypoints/geo.d.ts} +1 -1
- package/dist/entrypoints/geo.d.ts.map +1 -0
- package/dist/{geo.js → entrypoints/geo.js} +4 -4
- package/dist/entrypoints/google.d.ts +2 -0
- package/dist/entrypoints/google.d.ts.map +1 -0
- package/dist/{google.js → entrypoints/google.js} +1 -1
- package/dist/{index.d.ts → entrypoints/index.d.ts} +14 -13
- package/dist/entrypoints/index.d.ts.map +1 -0
- package/dist/{index.js → entrypoints/index.js} +99 -33
- package/dist/{live.d.ts → entrypoints/live.d.ts} +4 -4
- package/dist/entrypoints/live.d.ts.map +1 -0
- package/dist/{live.js → entrypoints/live.js} +6 -4
- package/dist/{node.d.ts → entrypoints/node.d.ts} +11 -11
- package/dist/entrypoints/node.d.ts.map +1 -0
- package/dist/{node.js → entrypoints/node.js} +20 -16
- package/dist/entrypoints/oauth.d.ts +2 -0
- package/dist/entrypoints/oauth.d.ts.map +1 -0
- package/dist/{oauth.js → entrypoints/oauth.js} +3 -3
- package/dist/{observability/index.d.ts → entrypoints/observability.d.ts} +11 -11
- package/dist/entrypoints/observability.d.ts.map +1 -0
- package/dist/{observability/index.js → entrypoints/observability.js} +9 -11
- package/dist/entrypoints/primitives.d.ts +3 -0
- package/dist/entrypoints/primitives.d.ts.map +1 -0
- package/dist/{primitives.js → entrypoints/primitives.js} +1 -6
- package/dist/{react.d.ts → entrypoints/react.d.ts} +4 -4
- package/dist/entrypoints/react.d.ts.map +1 -0
- package/dist/{react.js → entrypoints/react.js} +3 -3
- package/dist/{release.d.ts → entrypoints/release.d.ts} +4 -4
- package/dist/entrypoints/release.d.ts.map +1 -0
- package/dist/{release.js → entrypoints/release.js} +1 -1
- package/dist/{remote.d.ts → entrypoints/remote.d.ts} +1 -1
- package/dist/entrypoints/remote.d.ts.map +1 -0
- package/dist/entrypoints/remote.js +66 -0
- package/dist/{server/index.d.ts → entrypoints/server.d.ts} +35 -34
- package/dist/entrypoints/server.d.ts.map +1 -0
- package/dist/{server/index.js → entrypoints/server.js} +294 -244
- package/dist/{telegram.d.ts → entrypoints/telegram.d.ts} +2 -2
- package/dist/entrypoints/telegram.d.ts.map +1 -0
- package/dist/{telegram.js → entrypoints/telegram.js} +1 -1
- package/dist/entrypoints/testing.d.ts +9 -0
- package/dist/entrypoints/testing.d.ts.map +1 -0
- package/dist/{testing.js → entrypoints/testing.js} +80 -919
- package/dist/{tools/connections/index.d.ts → entrypoints/tools/connections.d.ts} +6 -7
- package/dist/entrypoints/tools/connections.d.ts.map +1 -0
- package/dist/{tools/connections/index.js → entrypoints/tools/connections.js} +7 -4
- package/dist/{tools-contract.d.ts → entrypoints/tools/contract.d.ts} +5 -5
- package/dist/entrypoints/tools/contract.d.ts.map +1 -0
- package/dist/{tools-contract.js → entrypoints/tools/contract.js} +4 -4
- package/dist/{tool-invoker.d.ts → entrypoints/tools/invoker.d.ts} +2 -2
- package/dist/entrypoints/tools/invoker.d.ts.map +1 -0
- package/dist/entrypoints/tools/invoker.js +20 -0
- package/dist/entrypoints/tools.d.ts +51 -0
- package/dist/entrypoints/tools.d.ts.map +1 -0
- package/dist/{tools.js → entrypoints/tools.js} +1787 -1751
- package/dist/{tracking-server.d.ts → entrypoints/tracking/server.d.ts} +8 -8
- package/dist/entrypoints/tracking/server.d.ts.map +1 -0
- package/dist/{tracking.d.ts → entrypoints/tracking.d.ts} +15 -15
- package/dist/entrypoints/tracking.d.ts.map +1 -0
- package/dist/{tracking.js → entrypoints/tracking.js} +5 -8
- package/dist/google/google.d.ts.map +1 -0
- package/dist/{index-a916km3r.js → index-0b1ess5e.js} +6 -13
- package/dist/{index-zwkgfq1s.js → index-1nd48tm9.js} +113 -118
- package/dist/{index-7zbps32p.js → index-1zbbzgfh.js} +2 -2
- package/dist/{index-mzvgxp0n.js → index-2cr1cqhn.js} +16 -4
- package/dist/{index-f9mb610r.js → index-35mh5bhj.js} +2 -2
- package/dist/index-48ffdxgk.js +6 -0
- package/dist/index-58k4fp34.js +1023 -0
- package/dist/{index-p13mwz16.js → index-83bdg97s.js} +1 -1
- package/dist/index-97ac4gph.js +3618 -0
- package/dist/{index-kw9t5ayn.js → index-cq4qfycf.js} +5 -5
- package/dist/{index-7gnkny4z.js → index-d9pk3td4.js} +1 -1
- package/dist/{index-e42wzzz5.js → index-dcpdvjsc.js} +7 -7
- package/dist/{index-h9etkkyk.js → index-dydjcp8z.js} +102 -25
- package/dist/{index-sr93cwf9.js → index-e2z3ahw9.js} +2 -2
- package/dist/{index-yewwh1w4.js → index-e87kakm4.js} +96 -11
- package/dist/{index-cby4ar3v.js → index-eqqvgdb3.js} +1 -1
- package/dist/index-fdp6hdxn.js +942 -0
- package/dist/{index-0a349c33.js → index-gyr48nzg.js} +125 -198
- package/dist/{index-wnfk50r0.js → index-h6eeys1v.js} +1 -1
- package/dist/{index-77fekveh.js → index-hffjpmq9.js} +1 -15
- package/dist/{index-yn8remb1.js → index-j05z5gn4.js} +50 -14
- package/dist/index-k5hsfc3j.js +31 -0
- package/dist/{index-fq77yfzc.js → index-kj2wbeta.js} +1 -1
- package/dist/index-kvj7f4hq.js +39 -0
- package/dist/{index-4fpa9dy2.js → index-m9zn6cpq.js} +2 -2
- package/dist/{index-2na0qrfn.js → index-mdzh02yc.js} +7 -7
- package/dist/{index-ywd0y6m1.js → index-mkm15s49.js} +1 -1
- package/dist/index-mp5sn43f.js +1084 -0
- package/dist/{index-3bmnp41g.js → index-n6hxg8as.js} +507 -419
- package/dist/index-ngfhvfpd.js +30 -0
- package/dist/{index-e0znv5gn.js → index-p5r7qpdd.js} +2 -93
- package/dist/{index-n0f51dfn.js → index-p81267c2.js} +608 -549
- package/dist/{index-wc4x00bn.js → index-qwhynv6x.js} +1 -1
- package/dist/index-r7nmqpsg.js +154 -0
- package/dist/{index-bx75zwt7.js → index-rewkc2hj.js} +5 -4
- package/dist/{index-9f8ztey6.js → index-sees8yf8.js} +2 -2
- package/dist/{index-vjpvjqpn.js → index-v38qyerb.js} +16 -2
- package/dist/{index-2c2bjw3s.js → index-vcvkq30w.js} +3 -3
- package/dist/index-wqgjfstn.js +18 -0
- package/dist/{index-f477k430.js → index-x4799c19.js} +1 -1
- package/dist/{index-cxqhvq21.js → index-xnj9bgxe.js} +142 -129
- package/dist/index-xsqjkha9.js +281 -0
- package/dist/{index-6kyksz9y.js → index-yw4fzmdz.js} +1 -1
- package/dist/{index-3xwxfj4z.js → index-zeemqhqx.js} +1 -1
- package/dist/{index-tmwcrptx.js → index-zfrhfn82.js} +1 -1
- package/dist/index-znfs20ss.js +98 -0
- package/dist/internal/backoff.d.ts +29 -0
- package/dist/internal/backoff.d.ts.map +1 -0
- package/dist/internal/canonical-json.d.ts +21 -11
- package/dist/internal/canonical-json.d.ts.map +1 -1
- package/dist/internal/channel.d.ts.map +1 -0
- package/dist/internal/logger.d.ts.map +1 -0
- package/dist/internal/request.d.ts.map +1 -0
- package/dist/internal/stable-digest.d.ts +0 -43
- package/dist/internal/stable-digest.d.ts.map +1 -1
- package/dist/internal/typed.d.ts +0 -8
- package/dist/internal/typed.d.ts.map +1 -1
- package/dist/internal/zod-issues.d.ts +38 -0
- package/dist/internal/zod-issues.d.ts.map +1 -0
- package/dist/{tools/json-schema-dialect.d.ts → json-schema/dialect.d.ts} +1 -1
- package/dist/json-schema/dialect.d.ts.map +1 -0
- package/dist/json-schema/json-schema.d.ts.map +1 -0
- package/dist/live/watch-delta.d.ts.map +1 -1
- package/dist/{oauth.d.ts → oauth/authorization-code.d.ts} +1 -1
- package/dist/oauth/authorization-code.d.ts.map +1 -0
- package/dist/observability/audit.d.ts +2 -2
- package/dist/observability/audit.d.ts.map +1 -1
- package/dist/observability/bounded-logger.d.ts +1 -1
- package/dist/observability/bounded-logger.d.ts.map +1 -1
- package/dist/{internal/observability-sink.d.ts → observability/bounded-sink.d.ts} +2 -2
- package/dist/observability/bounded-sink.d.ts.map +1 -0
- package/dist/observability/context.d.ts +1 -1
- package/dist/observability/context.d.ts.map +1 -1
- package/dist/observability/event.d.ts +1 -1
- package/dist/observability/event.d.ts.map +1 -1
- package/dist/observability/work.d.ts +1 -1
- package/dist/observability/work.d.ts.map +1 -1
- package/dist/primitives/audit.d.ts +1 -1
- package/dist/primitives/audit.d.ts.map +1 -1
- package/dist/primitives/export-operation.d.ts +4 -2
- package/dist/primitives/export-operation.d.ts.map +1 -1
- package/dist/realtime/socket.d.ts +1 -1
- package/dist/realtime/socket.d.ts.map +1 -1
- package/dist/server/context-contribution.d.ts +1 -1
- package/dist/server/context-contribution.d.ts.map +1 -1
- package/dist/server/context.d.ts +2 -2
- package/dist/server/context.d.ts.map +1 -1
- package/dist/server/contract-method.d.ts +15 -0
- package/dist/server/contract-method.d.ts.map +1 -0
- package/dist/server/contract-stream.d.ts +1 -1
- package/dist/server/contract-stream.d.ts.map +1 -1
- package/dist/server/create.d.ts +8 -0
- package/dist/server/create.d.ts.map +1 -1
- package/dist/server/endpoint-dispatch.d.ts +10 -0
- package/dist/server/endpoint-dispatch.d.ts.map +1 -0
- package/dist/server/endpoint-response.d.ts +18 -0
- package/dist/server/endpoint-response.d.ts.map +1 -0
- package/dist/server/error-dispatch.d.ts +17 -1
- package/dist/server/error-dispatch.d.ts.map +1 -1
- package/dist/server/error-hook.d.ts +2 -2
- package/dist/server/error-hook.d.ts.map +1 -1
- package/dist/server/handler-state.d.ts +44 -0
- package/dist/server/handler-state.d.ts.map +1 -0
- package/dist/server/implement.d.ts +1 -1
- package/dist/server/implement.d.ts.map +1 -1
- package/dist/server/middleware/auth.d.ts +1 -1
- package/dist/server/middleware/auth.d.ts.map +1 -1
- package/dist/server/middleware/cors.d.ts +17 -0
- package/dist/server/middleware/cors.d.ts.map +1 -1
- package/dist/server/middleware/trust-fence.d.ts +1 -1
- package/dist/server/middleware/trust-fence.d.ts.map +1 -1
- package/dist/server/multipart.d.ts +1 -1
- package/dist/server/multipart.d.ts.map +1 -1
- package/dist/{tools/oauth-metadata.d.ts → server/oauth/metadata.d.ts} +2 -2
- package/dist/server/oauth/metadata.d.ts.map +1 -0
- package/dist/{tools/oauth-provider.d.ts → server/oauth/provider.d.ts} +2 -2
- package/dist/server/oauth/provider.d.ts.map +1 -0
- package/dist/server/realtime.d.ts +1 -1
- package/dist/server/realtime.d.ts.map +1 -1
- package/dist/server/request-completion.d.ts +16 -0
- package/dist/server/request-completion.d.ts.map +1 -0
- package/dist/server/response-metadata.d.ts +1 -1
- package/dist/server/response-metadata.d.ts.map +1 -1
- package/dist/server/route-table.d.ts +9 -0
- package/dist/server/route-table.d.ts.map +1 -0
- package/dist/server/stream.d.ts +0 -13
- package/dist/server/stream.d.ts.map +1 -1
- package/dist/server/types.d.ts +7 -4
- package/dist/server/types.d.ts.map +1 -1
- package/dist/testing/handler-clients.d.ts +31 -0
- package/dist/testing/handler-clients.d.ts.map +1 -0
- package/dist/testing/managed-resource-conformance-scenarios.d.ts.map +1 -1
- package/dist/testing/surface-conformance.d.ts +2 -1
- package/dist/testing/surface-conformance.d.ts.map +1 -1
- package/dist/testing/surface-manifest.d.ts +30 -4
- package/dist/testing/surface-manifest.d.ts.map +1 -1
- package/dist/tools/{cli-args.d.ts → cli/args.d.ts} +1 -1
- package/dist/tools/cli/args.d.ts.map +1 -0
- package/dist/tools/{cli-checkpoint.d.ts → cli/checkpoint.d.ts} +1 -1
- package/dist/tools/cli/checkpoint.d.ts.map +1 -0
- package/dist/tools/{cli-command.d.ts → cli/command.d.ts} +4 -4
- package/dist/tools/cli/command.d.ts.map +1 -0
- package/dist/tools/{cli.d.ts → cli/config.d.ts} +5 -9
- package/dist/tools/cli/config.d.ts.map +1 -0
- package/dist/tools/cli/create-cli.d.ts +36 -0
- package/dist/tools/cli/create-cli.d.ts.map +1 -0
- package/dist/tools/cli/download.d.ts +8 -0
- package/dist/tools/cli/download.d.ts.map +1 -0
- package/dist/tools/{cli-format.d.ts → cli/format.d.ts} +2 -2
- package/dist/tools/cli/format.d.ts.map +1 -0
- package/dist/tools/cli/help.d.ts +24 -0
- package/dist/tools/cli/help.d.ts.map +1 -0
- package/dist/tools/{cli-installer.d.ts → cli/installer.d.ts} +2 -2
- package/dist/tools/cli/installer.d.ts.map +1 -0
- package/dist/tools/{cli-invoke.d.ts → cli/invoke.d.ts} +8 -8
- package/dist/tools/cli/invoke.d.ts.map +1 -0
- package/dist/tools/cli/io.d.ts +10 -0
- package/dist/tools/cli/io.d.ts.map +1 -0
- package/dist/tools/cli/managed-surface.d.ts +30 -0
- package/dist/tools/cli/managed-surface.d.ts.map +1 -0
- package/dist/tools/{cli-manifest.d.ts → cli/manifest.d.ts} +1 -1
- package/dist/tools/cli/manifest.d.ts.map +1 -0
- package/dist/tools/{cli-policy.d.ts → cli/policy.d.ts} +2 -2
- package/dist/tools/cli/policy.d.ts.map +1 -0
- package/dist/tools/cli/prepare.d.ts +14 -0
- package/dist/tools/cli/prepare.d.ts.map +1 -0
- package/dist/tools/{cli-profile.d.ts → cli/profile.d.ts} +2 -2
- package/dist/tools/cli/profile.d.ts.map +1 -0
- package/dist/tools/cli/run-managed.d.ts +5 -0
- package/dist/tools/cli/run-managed.d.ts.map +1 -0
- package/dist/tools/cli/run-native.d.ts +9 -0
- package/dist/tools/cli/run-native.d.ts.map +1 -0
- package/dist/tools/cli/session.d.ts +40 -0
- package/dist/tools/cli/session.d.ts.map +1 -0
- package/dist/tools/{cli-signature.d.ts → cli/signature.d.ts} +2 -2
- package/dist/tools/cli/signature.d.ts.map +1 -0
- package/dist/tools/{cli-stream.d.ts → cli/stream.d.ts} +4 -4
- package/dist/tools/cli/stream.d.ts.map +1 -0
- package/dist/tools/{cli-update.d.ts → cli/update.d.ts} +3 -3
- package/dist/tools/cli/update.d.ts.map +1 -0
- package/dist/tools/{cli-view.d.ts → cli/view.d.ts} +2 -2
- package/dist/tools/cli/view.d.ts.map +1 -0
- package/dist/tools/{cli-wait.d.ts → cli/wait.d.ts} +2 -2
- package/dist/tools/cli/wait.d.ts.map +1 -0
- package/dist/tools/connections/runtime.d.ts +1 -1
- package/dist/tools/connections/runtime.d.ts.map +1 -1
- package/dist/tools/connections/types.d.ts +3 -3
- package/dist/tools/connections/types.d.ts.map +1 -1
- package/dist/tools/durability-context.d.ts +1 -1
- package/dist/tools/durability-context.d.ts.map +1 -1
- package/dist/tools/execute.d.ts +30 -3
- package/dist/tools/execute.d.ts.map +1 -1
- package/dist/tools/internal/surface-projector.d.ts +8 -6
- package/dist/tools/internal/surface-projector.d.ts.map +1 -1
- package/dist/tools/internal/tool-view.d.ts +41 -0
- package/dist/tools/internal/tool-view.d.ts.map +1 -0
- package/dist/tools/invoker.d.ts +11 -3
- package/dist/tools/invoker.d.ts.map +1 -1
- package/dist/tools/list-names.d.ts +3 -3
- package/dist/tools/list-names.d.ts.map +1 -1
- package/dist/tools/manifest.d.ts +2 -2
- package/dist/tools/manifest.d.ts.map +1 -1
- package/dist/tools/{mcp-app.d.ts → mcp/app.d.ts} +1 -1
- package/dist/tools/mcp/app.d.ts.map +1 -0
- package/dist/tools/{mcp-catalog.d.ts → mcp/catalog.d.ts} +2 -2
- package/dist/tools/mcp/catalog.d.ts.map +1 -0
- package/dist/tools/{mcp-handler.d.ts → mcp/handler.d.ts} +5 -5
- package/dist/tools/mcp/handler.d.ts.map +1 -0
- package/dist/tools/{mcp.d.ts → mcp/mount.d.ts} +9 -9
- package/dist/tools/mcp/mount.d.ts.map +1 -0
- package/dist/tools/{mcp-prepare.d.ts → mcp/prepare.d.ts} +9 -9
- package/dist/tools/mcp/prepare.d.ts.map +1 -0
- package/dist/tools/{mcp-progress.d.ts → mcp/progress.d.ts} +2 -2
- package/dist/tools/mcp/progress.d.ts.map +1 -0
- package/dist/tools/mcp/register.d.ts +35 -0
- package/dist/tools/mcp/register.d.ts.map +1 -0
- package/dist/tools/{mcp-round-policy.d.ts → mcp/round-policy.d.ts} +2 -2
- package/dist/tools/mcp/round-policy.d.ts.map +1 -0
- package/dist/tools/{mcp-round.d.ts → mcp/round.d.ts} +4 -4
- package/dist/tools/mcp/round.d.ts.map +1 -0
- package/dist/tools/mcp/runtime-tools.d.ts +24 -0
- package/dist/tools/mcp/runtime-tools.d.ts.map +1 -0
- package/dist/tools/{mcp-stdio-signals.d.ts → mcp/stdio-signals.d.ts} +3 -3
- package/dist/tools/mcp/stdio-signals.d.ts.map +1 -0
- package/dist/tools/{mcp-stdio.d.ts → mcp/stdio.d.ts} +4 -4
- package/dist/tools/mcp/stdio.d.ts.map +1 -0
- package/dist/tools/{mcp-trace.d.ts → mcp/trace.d.ts} +1 -1
- package/dist/tools/mcp/trace.d.ts.map +1 -0
- package/dist/tools/mount.d.ts +12 -7
- package/dist/tools/mount.d.ts.map +1 -1
- package/dist/tools/native-definition.d.ts +3 -3
- package/dist/tools/native-definition.d.ts.map +1 -1
- package/dist/tools/operations/async-operation-binding-types.d.ts +127 -0
- package/dist/tools/operations/async-operation-binding-types.d.ts.map +1 -0
- package/dist/tools/operations/async-operation-binding.d.ts +28 -0
- package/dist/tools/operations/async-operation-binding.d.ts.map +1 -0
- package/dist/tools/operations/async-operation-canonical-types.d.ts +110 -0
- package/dist/tools/operations/async-operation-canonical-types.d.ts.map +1 -0
- package/dist/tools/operations/async-operation-canonical.d.ts +7 -0
- package/dist/tools/operations/async-operation-canonical.d.ts.map +1 -0
- package/dist/tools/operations/async-operation-contract.d.ts.map +1 -0
- package/dist/tools/operations/async-operation-id.d.ts +23 -0
- package/dist/tools/operations/async-operation-id.d.ts.map +1 -0
- package/dist/tools/operations/async-operation-runtime-tools.d.ts +40 -0
- package/dist/tools/operations/async-operation-runtime-tools.d.ts.map +1 -0
- package/dist/tools/operations/async-operation-runtime-types.d.ts +68 -0
- package/dist/tools/operations/async-operation-runtime-types.d.ts.map +1 -0
- package/dist/tools/operations/async-operation-runtime.d.ts +5 -0
- package/dist/tools/operations/async-operation-runtime.d.ts.map +1 -0
- package/dist/tools/{define-wait-tool.d.ts → operations/define-wait-tool.d.ts} +2 -2
- package/dist/tools/operations/define-wait-tool.d.ts.map +1 -0
- package/dist/tools/operations/mount-wait.d.ts.map +1 -0
- package/dist/tools/operations/wait-core.d.ts.map +1 -0
- package/dist/tools/remote.d.ts +1 -1
- package/dist/tools/remote.d.ts.map +1 -1
- package/dist/tools/runtime-tool.d.ts +11 -4
- package/dist/tools/runtime-tool.d.ts.map +1 -1
- package/dist/tools/schema/coerce.d.ts.map +1 -0
- package/dist/tools/schema/flatten-join.d.ts.map +1 -0
- package/dist/tools/schema/flatten.d.ts.map +1 -0
- package/dist/tools/schema/portable-formats.d.ts.map +1 -0
- package/dist/tools/{presentation.d.ts → schema/presentation.d.ts} +2 -0
- package/dist/tools/schema/presentation.d.ts.map +1 -0
- package/dist/tools/schema/schema.d.ts.map +1 -0
- package/dist/tools/schema/untyped-properties.d.ts.map +1 -0
- package/dist/tools/surface.d.ts +2 -3
- package/dist/tools/surface.d.ts.map +1 -1
- package/dist/tools/toolkit.d.ts +4 -4
- package/dist/tools/toolkit.d.ts.map +1 -1
- package/dist/tools/{define-download-tool.d.ts → transfer/define-download-tool.d.ts} +4 -4
- package/dist/tools/transfer/define-download-tool.d.ts.map +1 -0
- package/dist/tools/{define-upload-tool.d.ts → transfer/define-upload-tool.d.ts} +3 -3
- package/dist/tools/transfer/define-upload-tool.d.ts.map +1 -0
- package/dist/tools/{define-view-file-tool.d.ts → transfer/define-view-file-tool.d.ts} +2 -2
- package/dist/tools/transfer/define-view-file-tool.d.ts.map +1 -0
- package/dist/tools/{download-core.d.ts → transfer/download-core.d.ts} +2 -2
- package/dist/tools/transfer/download-core.d.ts.map +1 -0
- package/dist/tools/{managed-file-error.d.ts → transfer/managed-file-error.d.ts} +1 -1
- package/dist/tools/transfer/managed-file-error.d.ts.map +1 -0
- package/dist/tools/{mount-download.d.ts → transfer/mount-download.d.ts} +1 -1
- package/dist/tools/transfer/mount-download.d.ts.map +1 -0
- package/dist/tools/{mount-upload.d.ts → transfer/mount-upload.d.ts} +1 -1
- package/dist/tools/transfer/mount-upload.d.ts.map +1 -0
- package/dist/tools/transfer/native-result.d.ts.map +1 -0
- package/dist/tools/{upload-core.d.ts → transfer/upload-core.d.ts} +1 -1
- package/dist/tools/transfer/upload-core.d.ts.map +1 -0
- package/dist/tools/transfer/view-file-contract.d.ts.map +1 -0
- package/dist/tools/{view-file.d.ts → transfer/view-file.d.ts} +1 -1
- package/dist/tools/transfer/view-file.d.ts.map +1 -0
- package/dist/tools/transports.d.ts +1 -1
- package/dist/tools/transports.d.ts.map +1 -1
- package/dist/tracking/contract.d.ts +1 -1
- package/dist/tracking/contract.d.ts.map +1 -1
- package/llms/agent-runtime-browser.txt +33 -0
- package/llms/agent-runtime-coding-tools.txt +58 -0
- package/llms/agent-runtime-harness.txt +45 -0
- package/llms/agent-runtime-openrouter.txt +22 -0
- package/llms/agent-runtime-sandbox.txt +159 -0
- package/llms/agent-runtime-sqlite-bun.txt +29 -0
- package/llms/agent-runtime-sqlite-node.txt +26 -0
- package/llms/agent-runtime-testing.txt +30 -0
- package/llms/agent-runtime.2.txt +550 -0
- package/llms/agent-runtime.3.txt +311 -0
- package/llms/agent-runtime.txt +893 -0
- package/llms/application-diagnostic-journal.txt +30 -0
- package/llms/application-grammy.txt +27 -0
- package/llms/application-opentelemetry.txt +27 -0
- package/llms/application-schemas.txt +42 -0
- package/llms/application.2.txt +223 -0
- package/llms/application.txt +1144 -0
- package/llms/cli.txt +977 -0
- package/llms/contract.txt +606 -0
- package/llms/declaration.txt +286 -0
- package/llms/files.txt +30 -0
- package/llms/geo.txt +114 -0
- package/llms/google.txt +27 -0
- package/llms/live.txt +471 -0
- package/llms/node.txt +43 -0
- package/llms/oauth.txt +136 -0
- package/llms/observability.txt +893 -0
- package/llms/primitives.txt +158 -0
- package/llms/react.txt +184 -0
- package/llms/release.txt +176 -0
- package/llms/remote.txt +25 -0
- package/llms/server.2.txt +361 -0
- package/llms/server.3.txt +1031 -0
- package/llms/server.4.txt +905 -0
- package/llms/server.5.txt +250 -0
- package/llms/server.txt +996 -0
- package/llms/stitchkit.2.txt +836 -0
- package/llms/stitchkit.3.txt +147 -0
- package/llms/stitchkit.txt +260 -0
- package/llms/telegram.txt +30 -0
- package/llms/testing.txt +676 -0
- package/llms/tools-connections.txt +45 -0
- package/llms/tools-contract.txt +9 -0
- package/llms/tools-invoker.txt +9 -0
- package/llms/tools.2.txt +838 -0
- package/llms/tools.txt +1004 -0
- package/llms/tracking-server.txt +32 -0
- package/llms/tracking.txt +263 -0
- package/llms/upgrading-0.37.0-0.50.0.txt +947 -0
- package/llms/upgrading-0.53.0-0.67.0.txt +1174 -0
- package/llms/upgrading-0.68.0-0.94.0.txt +1159 -0
- package/llms/upgrading.txt +215 -0
- package/llms-full.txt +214 -75
- package/llms.txt +54 -5
- package/package.json +84 -83
- package/dist/agent-runtime/durability-contract.d.ts.map +0 -1
- package/dist/agent-runtime/durability-json.d.ts.map +0 -1
- package/dist/agent-runtime/durability-ledger.d.ts.map +0 -1
- package/dist/agent-runtime/durability-scheduler.d.ts.map +0 -1
- package/dist/agent-runtime/durability.d.ts.map +0 -1
- package/dist/agent-runtime/store-driver.d.ts.map +0 -1
- package/dist/agent-runtime-browser.d.ts +0 -5
- package/dist/agent-runtime-browser.d.ts.map +0 -1
- package/dist/agent-runtime-coding-tools.d.ts.map +0 -1
- package/dist/agent-runtime-coding-tools.js +0 -23
- package/dist/agent-runtime-harness.d.ts.map +0 -1
- package/dist/agent-runtime-openrouter.d.ts.map +0 -1
- package/dist/agent-runtime-sandbox.d.ts.map +0 -1
- package/dist/agent-runtime-sqlite-bun.d.ts.map +0 -1
- package/dist/agent-runtime-sqlite-node.d.ts.map +0 -1
- package/dist/agent-runtime-testing.d.ts +0 -3
- package/dist/agent-runtime-testing.d.ts.map +0 -1
- package/dist/agent-runtime-testing.js +0 -156
- package/dist/agent-runtime.d.ts.map +0 -1
- package/dist/application/channel.d.ts.map +0 -1
- package/dist/application-diagnostic-journal.d.ts.map +0 -1
- package/dist/application-grammy.d.ts.map +0 -1
- package/dist/application-opentelemetry.d.ts.map +0 -1
- package/dist/application-schemas.d.ts.map +0 -1
- package/dist/application.d.ts.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/contract/index.d.ts +0 -8
- package/dist/contract/index.d.ts.map +0 -1
- package/dist/declaration.d.ts.map +0 -1
- package/dist/files.d.ts.map +0 -1
- package/dist/geo.d.ts.map +0 -1
- package/dist/google.d.ts.map +0 -1
- package/dist/index-0j3vcp5m.js +0 -28
- package/dist/index-a11g2kry.js +0 -866
- package/dist/index-cnyk6te3.js +0 -77
- package/dist/index-fadnxwna.js +0 -1046
- package/dist/index-hrbajay7.js +0 -1196
- package/dist/index-s8cnx02s.js +0 -90
- package/dist/index-v5573g1k.js +0 -142
- package/dist/index-vk3kq9sb.js +0 -3344
- package/dist/index.d.ts.map +0 -1
- package/dist/internal/errors.d.ts.map +0 -1
- package/dist/internal/observability-sink.d.ts.map +0 -1
- package/dist/live.d.ts.map +0 -1
- package/dist/logger.d.ts.map +0 -1
- package/dist/node.d.ts.map +0 -1
- package/dist/oauth.d.ts.map +0 -1
- package/dist/observability/index.d.ts.map +0 -1
- package/dist/primitives.d.ts +0 -3
- package/dist/primitives.d.ts.map +0 -1
- package/dist/react.d.ts.map +0 -1
- package/dist/release.d.ts.map +0 -1
- package/dist/remote.d.ts.map +0 -1
- package/dist/remote.js +0 -88
- package/dist/retained.d.ts.map +0 -1
- package/dist/server/file-state-store.d.ts.map +0 -1
- package/dist/server/index.d.ts.map +0 -1
- package/dist/server/request.d.ts.map +0 -1
- package/dist/telegram.d.ts.map +0 -1
- package/dist/testing/agent-store-conformance.d.ts.map +0 -1
- package/dist/testing.d.ts +0 -39
- package/dist/testing.d.ts.map +0 -1
- package/dist/tool-invoker.d.ts.map +0 -1
- package/dist/tool-invoker.js +0 -21
- package/dist/tools/async-operation-contract.d.ts.map +0 -1
- package/dist/tools/async-operation.d.ts +0 -332
- package/dist/tools/async-operation.d.ts.map +0 -1
- package/dist/tools/cli-args.d.ts.map +0 -1
- package/dist/tools/cli-checkpoint.d.ts.map +0 -1
- package/dist/tools/cli-command.d.ts.map +0 -1
- package/dist/tools/cli-format.d.ts.map +0 -1
- package/dist/tools/cli-installer.d.ts.map +0 -1
- package/dist/tools/cli-invoke.d.ts.map +0 -1
- package/dist/tools/cli-manifest.d.ts.map +0 -1
- package/dist/tools/cli-policy.d.ts.map +0 -1
- package/dist/tools/cli-profile.d.ts.map +0 -1
- package/dist/tools/cli-signature.d.ts.map +0 -1
- package/dist/tools/cli-stream.d.ts.map +0 -1
- package/dist/tools/cli-update.d.ts.map +0 -1
- package/dist/tools/cli-view.d.ts.map +0 -1
- package/dist/tools/cli-wait.d.ts.map +0 -1
- package/dist/tools/cli.d.ts.map +0 -1
- package/dist/tools/coerce.d.ts.map +0 -1
- package/dist/tools/connections/index.d.ts.map +0 -1
- package/dist/tools/define-download-tool.d.ts.map +0 -1
- package/dist/tools/define-upload-tool.d.ts.map +0 -1
- package/dist/tools/define-view-file-tool.d.ts.map +0 -1
- package/dist/tools/define-wait-tool.d.ts.map +0 -1
- package/dist/tools/download-core.d.ts.map +0 -1
- package/dist/tools/flatten-join.d.ts.map +0 -1
- package/dist/tools/flatten.d.ts.map +0 -1
- package/dist/tools/json-schema-dialect.d.ts.map +0 -1
- package/dist/tools/json-schema.d.ts.map +0 -1
- package/dist/tools/managed-file-error.d.ts.map +0 -1
- package/dist/tools/mcp-app.d.ts.map +0 -1
- package/dist/tools/mcp-catalog.d.ts.map +0 -1
- package/dist/tools/mcp-handler.d.ts.map +0 -1
- package/dist/tools/mcp-prepare.d.ts.map +0 -1
- package/dist/tools/mcp-progress.d.ts.map +0 -1
- package/dist/tools/mcp-round-policy.d.ts.map +0 -1
- package/dist/tools/mcp-round.d.ts.map +0 -1
- package/dist/tools/mcp-stdio-signals.d.ts.map +0 -1
- package/dist/tools/mcp-stdio.d.ts.map +0 -1
- package/dist/tools/mcp-trace.d.ts.map +0 -1
- package/dist/tools/mcp.d.ts.map +0 -1
- package/dist/tools/mount-download.d.ts.map +0 -1
- package/dist/tools/mount-upload.d.ts.map +0 -1
- package/dist/tools/mount-wait.d.ts.map +0 -1
- package/dist/tools/native-mcp.d.ts +0 -20
- package/dist/tools/native-mcp.d.ts.map +0 -1
- package/dist/tools/native-result.d.ts.map +0 -1
- package/dist/tools/oauth-metadata.d.ts.map +0 -1
- package/dist/tools/oauth-provider.d.ts.map +0 -1
- package/dist/tools/portable-formats.d.ts.map +0 -1
- package/dist/tools/presentation.d.ts.map +0 -1
- package/dist/tools/schema.d.ts.map +0 -1
- package/dist/tools/untyped-properties.d.ts.map +0 -1
- package/dist/tools/upload-core.d.ts.map +0 -1
- package/dist/tools/view-file-contract.d.ts.map +0 -1
- package/dist/tools/view-file.d.ts.map +0 -1
- package/dist/tools/wait-core.d.ts.map +0 -1
- package/dist/tools-contract.d.ts.map +0 -1
- package/dist/tools.d.ts +0 -50
- package/dist/tools.d.ts.map +0 -1
- package/dist/tracking-server.d.ts.map +0 -1
- package/dist/tracking.d.ts.map +0 -1
- package/dist/upgrade-cli.d.ts.map +0 -1
- package/dist/{retained.d.ts → browser/retained.d.ts} +0 -0
- package/dist/{declaration.d.ts → declaration/declaration.d.ts} +0 -0
- package/dist/{upgrade-cli.d.ts → entrypoints/bin/upgrade-cli.d.ts} +0 -0
- package/dist/{tracking-server.js → entrypoints/tracking/server.js} +0 -0
- package/dist/{google.d.ts → google/google.d.ts} +0 -0
- package/dist/{index-pq95qkbf.js → index-5jm36zv1.js} +0 -0
- package/dist/{index-actkayzn.js → index-70yj2ebz.js} +3 -3
- /package/dist/{application → internal}/channel.d.ts +0 -0
- /package/dist/{logger.d.ts → internal/logger.d.ts} +0 -0
- /package/dist/{server → internal}/request.d.ts +0 -0
- /package/dist/{tools → json-schema}/json-schema.d.ts +0 -0
- /package/dist/tools/{async-operation-contract.d.ts → operations/async-operation-contract.d.ts} +0 -0
- /package/dist/tools/{mount-wait.d.ts → operations/mount-wait.d.ts} +0 -0
- /package/dist/tools/{wait-core.d.ts → operations/wait-core.d.ts} +0 -0
- /package/dist/tools/{coerce.d.ts → schema/coerce.d.ts} +0 -0
- /package/dist/tools/{flatten-join.d.ts → schema/flatten-join.d.ts} +0 -0
- /package/dist/tools/{flatten.d.ts → schema/flatten.d.ts} +0 -0
- /package/dist/tools/{portable-formats.d.ts → schema/portable-formats.d.ts} +0 -0
- /package/dist/tools/{schema.d.ts → schema/schema.d.ts} +0 -0
- /package/dist/tools/{untyped-properties.d.ts → schema/untyped-properties.d.ts} +0 -0
- /package/dist/tools/{native-result.d.ts → transfer/native-result.d.ts} +0 -0
- /package/dist/tools/{view-file-contract.d.ts → transfer/view-file-contract.d.ts} +0 -0
package/llms/tools.txt
ADDED
|
@@ -0,0 +1,1004 @@
|
|
|
1
|
+
# stitchkit/tools — stitchkit docs slice, part 1 of 2
|
|
2
|
+
|
|
3
|
+
> Generated from the `docs/` tree by `bun run gen:llms`. The index of all slices is
|
|
4
|
+
> `llms.txt` in this package.
|
|
5
|
+
> Continues in `llms/tools.2.txt`.
|
|
6
|
+
|
|
7
|
+
Parts of this slice:
|
|
8
|
+
- `llms/tools.txt`: Guide: MCP & agents (docs/guide/mcp-and-agents.md)
|
|
9
|
+
- `llms/tools.2.txt`: Guide: MCP & agents (docs/guide/mcp-and-agents.md) · API reference: `stitchkit/tools` (docs/api/reference.md)
|
|
10
|
+
|
|
11
|
+
==============================================================================
|
|
12
|
+
# Guide: MCP & agents (docs/guide/mcp-and-agents.md)
|
|
13
|
+
==============================================================================
|
|
14
|
+
|
|
15
|
+
# MCP & AI agents
|
|
16
|
+
|
|
17
|
+
The application generated by `bun create stitchkit` includes a working
|
|
18
|
+
stateless MCP endpoint and a separate `bun run tools` manifest command. Both
|
|
19
|
+
are assembled from the same implemented project contracts as HTTP and CLI, so
|
|
20
|
+
the generated project is the canonical end-to-end example for this chapter.
|
|
21
|
+
|
|
22
|
+
The same contract that drives the HTTP API also drives AI tooling. An endpoint
|
|
23
|
+
exposed on `MCP` becomes a [Model Context Protocol](https://modelcontextprotocol.io)
|
|
24
|
+
tool — callable from Claude, Cursor and other MCP clients. An endpoint exposed on
|
|
25
|
+
`AGENT` becomes a [Vercel AI SDK](https://sdk.vercel.ai) tool — callable from an
|
|
26
|
+
agent loop. Contract operations are never re-described by hand; pathless
|
|
27
|
+
runtime operations use one framework definition shared by both tool transports.
|
|
28
|
+
|
|
29
|
+
## Which endpoints become tools
|
|
30
|
+
|
|
31
|
+
By default every endpoint is a tool on every transport. `expose` narrows it:
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
{ method: 'GET', path: '/search', desc: 'Search the catalog' } // HTTP + MCP + AGENT
|
|
35
|
+
{ method: 'POST', path: '/sync', desc: 'Internal sync', expose: ['HTTP'] } // HTTP only
|
|
36
|
+
{ method: 'GET', path: '/lookup', desc: 'Look up a price', expose: ['MCP'] } // MCP tool only
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Four kinds of endpoint are **never** tools, whatever `expose` says: a
|
|
40
|
+
`multipart` upload (not a tool call), a `rawBody` endpoint (HTTP-only by
|
|
41
|
+
construction), a [`responseMeta`](./server.md#typed-json-response-metadata)
|
|
42
|
+
endpoint (outbound HTTP headers mean nothing on a tool call), and a
|
|
43
|
+
[`rawResponse`](./server.md#raw-response-endpoints) endpoint (its answer is
|
|
44
|
+
bytes — a tool result cannot carry them, and it would reach the model as `{}`).
|
|
45
|
+
Pin the full list with `listToolNames` in a snapshot test.
|
|
46
|
+
|
|
47
|
+
`desc` is the tool description the model reads — write it for the model, not
|
|
48
|
+
just for a human. The tool name defaults
|
|
49
|
+
to a verb-aware name from the method + prefix (`list` → `list_widgets`, `get` →
|
|
50
|
+
`get_widget`); set `tool.name` for an explicit one. Derivation normalises **per half**
|
|
51
|
+
(→ ADR 0035): the service half turns everything outside `[a-zA-Z0-9_]` into `_`,
|
|
52
|
+
hyphen included (`bot-status` ⇒ `get_bot_status`), while the method half keeps
|
|
53
|
+
its hyphen (`get-user` ⇒ `get-user_notes`) because such a name has always been
|
|
54
|
+
legal and may already be pinned in a client config. A name is *accepted* if it
|
|
55
|
+
matches `[a-zA-Z0-9_-]`. A name that
|
|
56
|
+
still cannot be delivered (illegal explicit `tool.name`, over 64 characters, or a
|
|
57
|
+
prefix with no usable character) throws at mount rather than at the first model
|
|
58
|
+
call —
|
|
59
|
+
→ [ADR 0035](../decisions/0035-tool-name-derivation-and-validation.md). See
|
|
60
|
+
[Contracts → transports](./contracts.md#transports).
|
|
61
|
+
|
|
62
|
+
### Pinning tool names — `listToolNames`
|
|
63
|
+
|
|
64
|
+
Derived tool names are part of your public surface — an MCP client config or an
|
|
65
|
+
agent prompt refers to them by string. `listToolNames({ services, runtimeTools })`
|
|
66
|
+
resolves the complete mixed surface (the exact resolver the mounts use), with
|
|
67
|
+
its origin, `(service, method)` identity and transports, sorted — a stable shape
|
|
68
|
+
to snapshot:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
import { listToolNames } from 'stitchkit/tools'
|
|
72
|
+
|
|
73
|
+
test('tool names have not drifted', () => {
|
|
74
|
+
expect(listToolNames({ services, runtimeTools })).toMatchSnapshot()
|
|
75
|
+
})
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
A stitchkit upgrade (or a contract refactor) that would shift a derived name
|
|
79
|
+
now fails this test instead of silently breaking the clients that call the
|
|
80
|
+
tool. It is also the mechanical diff when migrating a service: run it before
|
|
81
|
+
and after, compare.
|
|
82
|
+
|
|
83
|
+
> **This is also the guard against a forgotten `expose`.** An endpoint that
|
|
84
|
+
> declares none is a tool on MCP **and** AGENT — the default is fail-open, and
|
|
85
|
+
> there is no contract-level `expose` to set once (→
|
|
86
|
+
> [ADR 0036](../decisions/0036-contract-level-meta.md)). A snapshot of
|
|
87
|
+
> `listToolNames` fails the build the moment an endpoint you meant to keep
|
|
88
|
+
> HTTP-only shows up in the list, which is the one check that catches it however
|
|
89
|
+
> many places the line was forgotten.
|
|
90
|
+
|
|
91
|
+
## In-process calls — `createToolInvoker`
|
|
92
|
+
|
|
93
|
+
When one application operation dispatches to a contract tool, do not mount an
|
|
94
|
+
AI SDK `ToolSet` and call its transport adapter manually. Compile an in-process
|
|
95
|
+
invoker once and call the shared framework runner directly:
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
import { createToolInvoker } from 'stitchkit/tools/invoker'
|
|
99
|
+
|
|
100
|
+
const invoker = createToolInvoker(services, {
|
|
101
|
+
transport: 'AGENT', // required exposure policy
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
const result = await invoker.invoke('update_entity', args, {
|
|
105
|
+
source: 'internal', // default; audit names the real call source
|
|
106
|
+
context: { identity },
|
|
107
|
+
lifecycle,
|
|
108
|
+
hooks,
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
// Composition path: validated data or the exact normalized AppError.
|
|
112
|
+
const data = await invoker.invokeOrThrow('update_entity', args, {
|
|
113
|
+
context: { identity },
|
|
114
|
+
lifecycle,
|
|
115
|
+
hooks,
|
|
116
|
+
})
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`transport` is required and uses the exact existing `MCP`, `AGENT` or `CLI`
|
|
120
|
+
exposure rules; there is no internal bypass mode. The immutable name lookup is
|
|
121
|
+
compiled once. Call-specific identity, context, lifecycle and hooks are passed
|
|
122
|
+
to `invoke` / `invokeOrThrow`, so one registry can safely serve parallel and
|
|
123
|
+
recursive calls without retaining request state. Every invocation gets a fresh
|
|
124
|
+
tool-call context and runs the same extension resolution, input/output
|
|
125
|
+
validation, lifecycle, hooks and output-strip reporter as mounted tools.
|
|
126
|
+
|
|
127
|
+
The dedicated entrypoint needs only the normal `stitchkit`/`zod` install. Use
|
|
128
|
+
the broader `stitchkit/tools` barrel when the same program also mounts MCP or AI
|
|
129
|
+
adapters and has installed their optional peers. Both imports reach the same
|
|
130
|
+
runner; this is dependency isolation, not a second execution implementation.
|
|
131
|
+
|
|
132
|
+
`invoke` returns the canonical discriminated `ToolResult`, not an AI SDK or MCP
|
|
133
|
+
presentation envelope. `invokeOrThrow` returns validated data and throws the
|
|
134
|
+
runner's normalized `AppError` on failure, preserving an application error's
|
|
135
|
+
code, status, message, details and hint without reconstructing it from the
|
|
136
|
+
model-safe envelope. Unexpected throws remain scrubbed. An unknown name throws
|
|
137
|
+
`AppError('NOT_FOUND')` before the runner because there is no operation identity
|
|
138
|
+
against which hooks could run. Duplicate and provider-invalid names fail when
|
|
139
|
+
the invoker is created.
|
|
140
|
+
|
|
141
|
+
The invoker's caller is code, so it gets an endpoint's full answer even where a
|
|
142
|
+
[tool view](#a-different-answer-for-tools--withtoolview) is declared. When the
|
|
143
|
+
invoker backs a transport a model reads, pass `toolSurface: true`: calls then
|
|
144
|
+
get the view's defaults and projected answer, which is what `collectTools` and
|
|
145
|
+
`buildToolManifest` advertise.
|
|
146
|
+
|
|
147
|
+
## MCP — `createMcpHandler`
|
|
148
|
+
|
|
149
|
+
`createMcpHandler` builds a complete stateless Streamable-HTTP MCP endpoint on
|
|
150
|
+
the official TypeScript SDK v2 server package. It owns server creation,
|
|
151
|
+
protocol-era negotiation and shutdown; application code does not import the SDK
|
|
152
|
+
to mount a normal endpoint.
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
import { createMcpHandler, createMcpHttpRoute } from 'stitchkit/tools'
|
|
156
|
+
import { createServer } from 'stitchkit/server'
|
|
157
|
+
|
|
158
|
+
const mcp = createMcpHandler({
|
|
159
|
+
serverInfo: { name: 'my-app', version: '1.0.0' },
|
|
160
|
+
auth: (req) => resolveApiKey(req), // → an identity, or null for 401
|
|
161
|
+
services: [usersService, catalogService],
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
createServer({
|
|
165
|
+
services,
|
|
166
|
+
rawRoutes: [createMcpHttpRoute({ path: '/mcp', handler: mcp })],
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
// During graceful shutdown:
|
|
170
|
+
await mcp.close()
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### `McpHandlerConfig`
|
|
174
|
+
|
|
175
|
+
| Field | Purpose |
|
|
176
|
+
|-------|---------|
|
|
177
|
+
| `serverInfo` | MCP server identity — `{ name, version }` |
|
|
178
|
+
| `auth` | `(req) => identity \| null` — `null` rejects with 401 |
|
|
179
|
+
| `services` | the services to expose — an array, or `(auth) => ServiceDef[]` |
|
|
180
|
+
| `runtimeTools` | managed pathless operations — an array, or `(auth) => RuntimeToolDefinition[]` |
|
|
181
|
+
| `surfaces` | finite `{ key: { services, runtimeTools } }` registry prepared eagerly |
|
|
182
|
+
| `selectSurface` | `(auth) => declaredKey` — required with `surfaces` |
|
|
183
|
+
| `context` | `(auth) => {…}` — values merged into every tool handler's `ctx` |
|
|
184
|
+
| `lifecycle` | `beforeHandle` / `afterHandle` — the tool-side auth gate (see below) |
|
|
185
|
+
| `multiRound` | Typed MRTR state policy for guarded multi-round tool calls |
|
|
186
|
+
| `hooks` | tool-call observability hooks — `afterToolCall` fires on every result |
|
|
187
|
+
| `extend` | extra advertised arguments resolved into handler context |
|
|
188
|
+
| `schemaValidation` | compatibility policy, typed-property guard and portable-format guard |
|
|
189
|
+
| `logger` | a `StitchLogger` for the `'warn'` policy |
|
|
190
|
+
| `rawTools` | `(server, auth) => …` — explicit SDK registration without framework guarantees |
|
|
191
|
+
| `resources` | MCP Apps `ui://` resources mounted on every server |
|
|
192
|
+
| `instructions` | a short host-facing usage hint, surfaced to MCP tool-search |
|
|
193
|
+
| `coerceJsonArgs` | coerce JSON-stringified object/array arguments (default `true`) |
|
|
194
|
+
| `flattenUnionInput` | advertise discriminated unions as one object (default `false`) |
|
|
195
|
+
| `errorHint` | add a project-owned hint to failed tool results |
|
|
196
|
+
| `onOutputStrip` | observe output keys removed by contract validation |
|
|
197
|
+
| `protectedResource` | RFC 9728 metadata used by HTTP `401` responses |
|
|
198
|
+
| `legacy` | `'serve'` (default) or `'reject'` for pre-2026 clients |
|
|
199
|
+
| `security` | optional Host/Origin allowlists at the Fetch boundary |
|
|
200
|
+
| `onTransportRejected` | observe HTTP/protocol rejections without entering lifecycle or tool hooks |
|
|
201
|
+
| `cache` | explicit operation cache hints; omitted means zero/private |
|
|
202
|
+
|
|
203
|
+
Direct `services` / `runtimeTools` factories, `context`, `selectSurface` and
|
|
204
|
+
`rawTools` receive the resolved identity, so a tenant can be shown only its own
|
|
205
|
+
tools and every handler can read `ctx.tenantId`.
|
|
206
|
+
|
|
207
|
+
Use direct factories only when the definitions are genuinely arbitrary per
|
|
208
|
+
identity. For a bounded role/plan set, declare a finite registry instead:
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
const handleMcp = createMcpHandler({
|
|
212
|
+
serverInfo,
|
|
213
|
+
auth,
|
|
214
|
+
surfaces: {
|
|
215
|
+
admin: { services: allServices, runtimeTools: [renderPreview] },
|
|
216
|
+
member: { services: memberServices, runtimeTools: [renderPreview] },
|
|
217
|
+
},
|
|
218
|
+
selectSurface: (identity) => identity.isAdmin ? 'admin' : 'member',
|
|
219
|
+
context: (identity) => ({ identity }),
|
|
220
|
+
})
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Every declared entry is schema-validated and prepared once when the handler is
|
|
224
|
+
constructed. The selected immutable descriptors are shared; the SDK server,
|
|
225
|
+
transport, auth-derived context, lifecycle runner and tool-call context are
|
|
226
|
+
fresh for every request. Unknown keys
|
|
227
|
+
fail before the server connects. The registry never retains auth values.
|
|
228
|
+
|
|
229
|
+
### Stateless transport and protocol eras
|
|
230
|
+
|
|
231
|
+
Every request gets a fresh SDK server, resolved auth/context and tool-call
|
|
232
|
+
runner. Static direct and finite registry schemas are still prepared once when
|
|
233
|
+
the handler is constructed. There is no session map, event store,
|
|
234
|
+
`Mcp-Session-Id` or resumable cross-request SSE state. Process replacement and
|
|
235
|
+
load balancing therefore cannot strand a client on an in-memory session.
|
|
236
|
+
|
|
237
|
+
The default `legacy: 'serve'` lets the official SDK negotiate either modern
|
|
238
|
+
`2026-07-28` or the supported legacy stateless opening on this same endpoint.
|
|
239
|
+
Set `legacy: 'reject'` when every host is modern. Legacy support is protocol
|
|
240
|
+
translation inside the SDK, not a second Stitchkit transport or compatibility
|
|
241
|
+
API. Stateful MCP and subscriptions are intentionally outside this layer.
|
|
242
|
+
|
|
243
|
+
`createMcpHttpRoute` is the framework-owned raw-route adapter. It registers
|
|
244
|
+
`ALL` because Streamable HTTP uses multiple HTTP methods, delegates only to
|
|
245
|
+
`handler.fetch`, and leaves lifecycle ownership with the returned handler.
|
|
246
|
+
|
|
247
|
+
By default, a present `Host` header must match the request URL and a present
|
|
248
|
+
browser `Origin` must be same-origin. Non-browser hosts may omit `Origin`. Behind
|
|
249
|
+
a trusted reverse proxy, reconstruct the public request URL before calling the
|
|
250
|
+
handler or configure exact `security.allowedHosts` / `allowedOrigins`; never
|
|
251
|
+
copy arbitrary forwarded headers into the trusted URL. If a browser calls MCP
|
|
252
|
+
cross-origin, its HTTP server or gateway must also answer CORS preflight and
|
|
253
|
+
expose the protocol headers. `onTransportRejected` is the audit boundary for
|
|
254
|
+
HTTP/security rejections; it is deliberately separate from tool lifecycle and
|
|
255
|
+
must not be used as authorization input.
|
|
256
|
+
|
|
257
|
+
### Modern discovery, routing and cache hints
|
|
258
|
+
|
|
259
|
+
Stitchkit forwards the negotiated protocol era and validated MCP request data
|
|
260
|
+
to both `RequestEvent.mcp` and the current managed call's typed `context.mcp`;
|
|
261
|
+
untrusted routing headers never become application identity. The SDK validates
|
|
262
|
+
`MCP-Protocol-Version`, JSON-RPC shape and routing
|
|
263
|
+
metadata before lifecycle or tool handlers run. Framework-owned tool and
|
|
264
|
+
resource registration preserves declaration order across HTTP and stdio. Tool
|
|
265
|
+
manifests preserve mount order; `listToolNames` is a sorted diagnostics view.
|
|
266
|
+
Consumer-owned raw SDK registrations are outside this guarantee.
|
|
267
|
+
|
|
268
|
+
Caching is opt-in. `cache.operations` maps directly to SDK v2 operation cache
|
|
269
|
+
hints, while each `McpResourceDef` may declare its own `cacheHint`. Omission
|
|
270
|
+
means zero/private: neither a prepared surface nor a deterministic response is
|
|
271
|
+
silently treated as public. Unbounded auth-selected surface factories are
|
|
272
|
+
always forced to zero/private even when an operation policy is present; use a
|
|
273
|
+
finite `surfaces` registry when identities share a provably immutable surface.
|
|
274
|
+
Stitchkit never advertises list-change or subscription capabilities
|
|
275
|
+
without an implementation.
|
|
276
|
+
|
|
277
|
+
### Knowing your catalog is stale — the catalog stamp
|
|
278
|
+
|
|
279
|
+
A client lists the tools once and keeps that list. If the server's contract
|
|
280
|
+
moves afterwards, the client's copy is wrong and *nothing tells it so*: calls
|
|
281
|
+
are refused, and from inside the client a refusal looks like a broken server.
|
|
282
|
+
This is the most expensive shape a contract disagreement takes, because the
|
|
283
|
+
party able to fix it is the one with no evidence.
|
|
284
|
+
|
|
285
|
+
Every advertised tool and every tool result therefore carries the fingerprint of
|
|
286
|
+
the catalog it came from:
|
|
287
|
+
|
|
288
|
+
```ts
|
|
289
|
+
import { readMcpCatalogStamp } from 'stitchkit/tools';
|
|
290
|
+
|
|
291
|
+
const listed = await client.listTools();
|
|
292
|
+
let known = readMcpCatalogStamp(listed.tools[0]?._meta); // { digest, tools }
|
|
293
|
+
|
|
294
|
+
const result = await client.callTool({ name: 'record_journal', arguments });
|
|
295
|
+
const live = readMcpCatalogStamp(result._meta);
|
|
296
|
+
if (live && known && live.digest !== known.digest) {
|
|
297
|
+
// The catalog moved under us. Re-list before blaming the result.
|
|
298
|
+
known = readMcpCatalogStamp((await client.listTools()).tools[0]?._meta);
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
The comparison costs nothing and runs on a response you were already receiving —
|
|
303
|
+
including a refusal, which is exactly when a stale catalog is the likeliest
|
|
304
|
+
explanation. `notifications/tools/list_changed` is the push-shaped answer to the
|
|
305
|
+
same problem and `createMcpHandler` cannot send it: it is stateless by
|
|
306
|
+
construction, so there is no retained session to push down.
|
|
307
|
+
|
|
308
|
+
The digest covers each advertised tool's name, description, input schema, output
|
|
309
|
+
schema and annotations, and nothing else — it moves when the contract moves and
|
|
310
|
+
not when a handler does. Raw SDK registrations stay consumer-owned and are
|
|
311
|
+
outside it.
|
|
312
|
+
|
|
313
|
+
### Shaping arguments before validation — `beforeToolCall`
|
|
314
|
+
|
|
315
|
+
`beforeToolCall` sees the arguments as they arrived and may **replace** them:
|
|
316
|
+
|
|
317
|
+
```ts
|
|
318
|
+
hooks: {
|
|
319
|
+
beforeToolCall: async ({ args }) =>
|
|
320
|
+
typeof args.id === 'string' && args.id.startsWith('@')
|
|
321
|
+
? { ...args, id: await resolveReference(args.id) }
|
|
322
|
+
: undefined, // undefined / null / nothing → unchanged
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
The replacement is validated by the contract schema like any other input, so this
|
|
327
|
+
shapes a call and never bypasses the schema — a hook returning something the
|
|
328
|
+
contract refuses produces an ordinary `VALIDATION_ERROR`. It runs before the
|
|
329
|
+
params/input split, before argument coercion and before both schemas, which is
|
|
330
|
+
why a field declared `z.string()` can receive a reference and still be a string by
|
|
331
|
+
the time it is checked. `lifecycle.beforeHandle` is too late for this: the schemas
|
|
332
|
+
have already answered.
|
|
333
|
+
|
|
334
|
+
The audit trail is unaffected. `afterToolCall` reports what the caller sent as
|
|
335
|
+
`args` and the replacement separately as `effectiveArgs`, so a rewrite is visible
|
|
336
|
+
as a rewrite rather than by overwriting the evidence.
|
|
337
|
+
|
|
338
|
+
### Knowing the outcome of a call — `afterToolCall` and `toolCallId`
|
|
339
|
+
|
|
340
|
+
`afterToolCall` receives the whole `ToolResult` — `{ok: true, data}` or
|
|
341
|
+
`{ok: false, code, …}` — on every exit, including a validation failure that never
|
|
342
|
+
reached the handler, and on all three transports. It is the answer to "did this
|
|
343
|
+
call fail"; deriving that from the serialized error text instead is the mistake
|
|
344
|
+
this section exists to prevent, and it is a mistake that does not announce itself:
|
|
345
|
+
one consumer had five places asking the question and getting five answers.
|
|
346
|
+
|
|
347
|
+
To correlate an outcome with the call the model made, read `context.toolCallId`:
|
|
348
|
+
|
|
349
|
+
```ts
|
|
350
|
+
hooks: {
|
|
351
|
+
afterToolCall: ({ context, result }) => {
|
|
352
|
+
loop.record(context.toolCallId, result.ok ? 'ok' : result.code);
|
|
353
|
+
},
|
|
354
|
+
}
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
Two exits are deliberately **not** reported: a runtime tool presenter that throws
|
|
358
|
+
on the agent surface (the AI SDK calls it after `execute` has already returned)
|
|
359
|
+
and `ToolExecutionControlError`, which is a run being stopped rather than a tool
|
|
360
|
+
failing — check it with `isToolExecutionControlError`.
|
|
361
|
+
|
|
362
|
+
### Restartable tool bodies — `durability`
|
|
363
|
+
|
|
364
|
+
A tool that starts slow work and must report exactly once, including after a host
|
|
365
|
+
restart, can keep that bookkeeping **inside** the tool:
|
|
366
|
+
|
|
367
|
+
```ts
|
|
368
|
+
mountAgent(services, {
|
|
369
|
+
durability: (toolCallId, signal) => myLedgerFor(toolCallId, signal),
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
// in the handler
|
|
373
|
+
const asset = await ctx.step('render', () => renderAsset(ctx.input));
|
|
374
|
+
await ctx.waitFor({ event: 'render-done', id: assetId });
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
`ToolDurability` is the port a tool body sees — `step`, `sleep`, `waitFor`. You
|
|
378
|
+
do not have to implement it: the engine ships from `stitchkit/tools`, and it needs
|
|
379
|
+
a ledger of two methods over storage you already have:
|
|
380
|
+
|
|
381
|
+
```ts
|
|
382
|
+
import { createLocalStepDurability, type StepDurabilityLedger } from 'stitchkit/tools';
|
|
383
|
+
|
|
384
|
+
const ledger: StepDurabilityLedger = {
|
|
385
|
+
appendEvent: (event) => db.durabilityEvents.insert(event), // returns the row with `seq`
|
|
386
|
+
readEvents: ({ conversationId, fromSeq, toSeq }) => db.durabilityEvents.page(…),
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
mountAgent(services, {
|
|
390
|
+
durability: (toolCallId, signal) =>
|
|
391
|
+
createLocalStepDurability({ store: ledger, conversationId, runId: toolCallId, signal }),
|
|
392
|
+
});
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
That gives replay, absolute deadlines and decode refusal without writing them.
|
|
396
|
+
The port is there for an application that already has its own ledger engine.
|
|
397
|
+
|
|
398
|
+
One thing the port deliberately leaves out: **delivery**. `waitFor` parks until
|
|
399
|
+
`{ event, id }` arrives, and a tool body has no business delivering to itself —
|
|
400
|
+
so `deliver` lives on the engine object you constructed, not in the handler
|
|
401
|
+
context. Whatever produces the event (a webhook, a queue consumer, a cron) calls
|
|
402
|
+
`engine.deliver({ event, id, payload })` against the same ledger; the parked
|
|
403
|
+
`waitFor` resolves, and a `waitFor` that starts after the delivery returns at
|
|
404
|
+
once. Taking `agent-runtime` is not required and nothing of the runtime proper
|
|
405
|
+
enters the `stitchkit/tools` graph. An application that *does* run on
|
|
406
|
+
`agent-runtime` gets durability through the run context and needs no option;
|
|
407
|
+
where both exist the runtime's wins, because the run is recorded in its ledger.
|
|
408
|
+
|
|
409
|
+
### Typed MCP call metadata
|
|
410
|
+
|
|
411
|
+
Contract handlers, runtime-tool handlers/factories, lifecycle and tool hooks all
|
|
412
|
+
see the same optional `McpCallContext` for the current invocation:
|
|
413
|
+
|
|
414
|
+
```ts
|
|
415
|
+
const sourceLabel = context.mcp?.clientInfo?.name ?? context.source
|
|
416
|
+
|
|
417
|
+
context.mcp?.era // 'modern' | 'legacy'
|
|
418
|
+
context.mcp?.method // validated MCP method
|
|
419
|
+
context.mcp?.toolName // resolved framework tool name
|
|
420
|
+
context.mcp?.protocolVersion // when supplied by a modern host
|
|
421
|
+
context.mcp?.clientInfo // { name, version } when validated
|
|
422
|
+
context.mcp?.outcome // multi-round attempt outcome
|
|
423
|
+
context.mcp?.round // multi-round attempt number
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
The field is absent on HTTP, Agent, CLI and bring-your-own transports. A legacy
|
|
427
|
+
MCP call exposes `era: 'legacy'` but does not invent modern client information.
|
|
428
|
+
`clientInfo` is the host's self-description: use it for labels or analytics,
|
|
429
|
+
never for authentication, RBAC, tenant selection or rate limiting. Verified
|
|
430
|
+
identity still comes from `auth`; the `context(auth)` callback remains the
|
|
431
|
+
application-context factory and receives no protocol metadata.
|
|
432
|
+
|
|
433
|
+
### Telling the host what a long call is doing — `ctx.reportProgress`
|
|
434
|
+
|
|
435
|
+
A tool that takes ten minutes tells a text host nothing: the call is made, and
|
|
436
|
+
the next thing the host shows is the answer. The protocol has a channel for
|
|
437
|
+
this — the host sends a `progressToken` with the call, the server relates
|
|
438
|
+
progress notifications to it — and a handler reaches it through
|
|
439
|
+
`ctx.reportProgress`:
|
|
440
|
+
|
|
441
|
+
```ts
|
|
442
|
+
render: async (ctx) => {
|
|
443
|
+
await ctx.reportProgress?.({ message: 'queued' })
|
|
444
|
+
const job = await jobs.start(ctx.input)
|
|
445
|
+
await ctx.reportProgress?.({ message: 'rendering', progress: 1, total: 3 })
|
|
446
|
+
return await jobs.finish(job)
|
|
447
|
+
}
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
`reportProgress` is present on every **tool** call — MCP, agent and CLI — so a
|
|
451
|
+
handler never branches on transport, and it does nothing wherever nobody is
|
|
452
|
+
listening. It is absent on the HTTP transport, which has no channel for it, so a
|
|
453
|
+
handler that also serves HTTP writes `ctx.reportProgress?.(…)`. It never throws and never
|
|
454
|
+
rejects: a message about work must not be able to kill the work it describes, so
|
|
455
|
+
a refused notification leaves the host exactly where a host that never asked for
|
|
456
|
+
progress already is.
|
|
457
|
+
|
|
458
|
+
`progress` is a number the protocol requires and a handler often does not have —
|
|
459
|
+
there is a stage to name and no scale to name it on. Omit it and the ordinal of
|
|
460
|
+
the update is sent, with no `total`, so the host shows a counter rather than a
|
|
461
|
+
bar stuck at 3%. That is a fact about what happened; a synthesised percentage
|
|
462
|
+
would be a claim nobody measured.
|
|
463
|
+
|
|
464
|
+
The framework sends nothing on its own. Progress is meaningful only where an
|
|
465
|
+
operation has observable stages, and manufacturing one per call would be
|
|
466
|
+
inventing a second transport beside the one the protocol already provides. The
|
|
467
|
+
one exception is the managed wait tool (`mountWait`), which already polls and
|
|
468
|
+
therefore already knows: when the host asked for progress it reports each poll
|
|
469
|
+
and the phase it last saw, which is the tool whose silence raised the question
|
|
470
|
+
in the first place.
|
|
471
|
+
|
|
472
|
+
The token itself is on `ctx.mcp.progressToken` when a caller wants to know
|
|
473
|
+
whether anyone is listening.
|
|
474
|
+
|
|
475
|
+
### Multi-round tool input (`input_required`)
|
|
476
|
+
|
|
477
|
+
An MCP-only operation can require typed user input before its final side effect:
|
|
478
|
+
|
|
479
|
+
```ts
|
|
480
|
+
const DeleteConfirmationSchema = z.object({ confirmed: z.boolean() })
|
|
481
|
+
|
|
482
|
+
deleteProject: {
|
|
483
|
+
method: 'DELETE',
|
|
484
|
+
path: '/projects/:id',
|
|
485
|
+
expose: ['MCP'],
|
|
486
|
+
input: DeleteProjectSchema,
|
|
487
|
+
output: DeleteProjectResultSchema,
|
|
488
|
+
tool: {
|
|
489
|
+
mcp: {
|
|
490
|
+
inputRequired: [
|
|
491
|
+
{
|
|
492
|
+
key: 'confirmation',
|
|
493
|
+
schema: DeleteConfirmationSchema,
|
|
494
|
+
message: 'Confirm permanent deletion',
|
|
495
|
+
},
|
|
496
|
+
{
|
|
497
|
+
key: 'reason',
|
|
498
|
+
schema: z.object({ value: z.string().min(3) }),
|
|
499
|
+
message: 'Record the reason',
|
|
500
|
+
},
|
|
501
|
+
],
|
|
502
|
+
},
|
|
503
|
+
},
|
|
504
|
+
}
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
Each continuation accepts exactly the currently requested item. Only after the
|
|
508
|
+
ordered sequence completes does the handler receive the exact aggregate as
|
|
509
|
+
`ctx.mcpInput.confirmation` and `ctx.mcpInput.reason`; before then the framework
|
|
510
|
+
returns `input_required` without calling it. Set
|
|
511
|
+
`multiRound.serving.maxRounds` to the maximum declaration size you accept
|
|
512
|
+
(default `10`); empty sequences, duplicate keys and overflow fail first. State
|
|
513
|
+
is bound to principal, full operation identity, current round, accepted
|
|
514
|
+
aggregate and canonical original-argument digest and is
|
|
515
|
+
expiry-checked. Tampered, expired, cross-user or cross-tool state fails before
|
|
516
|
+
the side effect. Output validation applies only to the final result.
|
|
517
|
+
|
|
518
|
+
Every attempt re-runs auth/lifecycle and emits its own tool hooks; audit metadata
|
|
519
|
+
contains the attempt's `mcp.outcome` and `mcp.round`. Stitchkit does not merge
|
|
520
|
+
separate HTTP attempts into one logical trace. Parallel
|
|
521
|
+
rounds have isolated context. HTTP/stdio modern hosts and the supported legacy
|
|
522
|
+
stdio bridge may use this declaration; Agent, CLI and ordinary HTTP invocation
|
|
523
|
+
remain single-round and unchanged. Hosts without the capability receive an
|
|
524
|
+
ordinary unsupported result rather than a falsely advertised round. Signed
|
|
525
|
+
state is tamper-resistant, not an exactly-once replay store; destructive
|
|
526
|
+
handlers must still be idempotent where retries matter.
|
|
527
|
+
|
|
528
|
+
#### Questions chosen from the arguments
|
|
529
|
+
|
|
530
|
+
The list above is fixed when the contract is written, which is right when the
|
|
531
|
+
questions belong to the operation. It is not enough when they belong to the
|
|
532
|
+
**arguments** — one model takes `aspect_ratio`, another `duration`, a third an
|
|
533
|
+
input image — and there a declared list can only be empty. `inputRequired` also
|
|
534
|
+
accepts a function of the parsed call:
|
|
535
|
+
|
|
536
|
+
```ts
|
|
537
|
+
tool: {
|
|
538
|
+
mcp: {
|
|
539
|
+
inputRequired: async ({ input }) => {
|
|
540
|
+
const model = await catalog.get(input.model)
|
|
541
|
+
return model.needsRatio
|
|
542
|
+
? [{ key: 'ratio', schema: RatioSchema, message: 'Which aspect ratio?' }]
|
|
543
|
+
: []
|
|
544
|
+
},
|
|
545
|
+
},
|
|
546
|
+
}
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
It receives the same `params` / `input` the handler receives — parsed, so
|
|
550
|
+
defaults and coercions are already applied. Returning an empty array means this
|
|
551
|
+
call needs nothing and runs straight through. Everything else is unchanged: the
|
|
552
|
+
state is still signed and bound to principal, operation and argument digest, the
|
|
553
|
+
rounds are still counted against `maxRounds`, and a resolved list with duplicate
|
|
554
|
+
keys or more rounds than allowed is refused.
|
|
555
|
+
|
|
556
|
+
**The plan is fingerprinted, and that matters more than it looks.** Between two
|
|
557
|
+
rounds there is a full round trip to the host, and a resolver that reads
|
|
558
|
+
anything outside its arguments — a model catalog, a feature flag — can answer
|
|
559
|
+
differently the second time. Every other check would still pass: same principal,
|
|
560
|
+
same operation, same arguments, round still in range. Round 2's question would
|
|
561
|
+
be asked under round 1's key, and if the schemas happened to be compatible the
|
|
562
|
+
user's answer would be accepted for a question nobody asked. So the resolved
|
|
563
|
+
list is fingerprinted into the signed state and re-checked every round; a plan
|
|
564
|
+
that moved is refused, not asked. A resolver that reads only its arguments never
|
|
565
|
+
sees this.
|
|
566
|
+
|
|
567
|
+
**What a dynamic declaration costs.** One extra pass through the contract
|
|
568
|
+
pipeline per round — `lifecycle.beforeHandle` runs once more and one more
|
|
569
|
+
`toolPhase: 'input-round'` audit row is written. That is the price of ordering:
|
|
570
|
+
the resolver is your code and may reach a network, so it runs **after**
|
|
571
|
+
authorisation, never before, and the only thing that can authorise is a pipeline
|
|
572
|
+
pass. Resolving itself is free — the arguments are parsed by the same pure
|
|
573
|
+
function the call parses with, not by a second run of anything. A fixed list
|
|
574
|
+
pays none of this; its call sequence is unchanged.
|
|
575
|
+
|
|
576
|
+
One thing does change for a fixed list: the signed round state now carries a
|
|
577
|
+
fingerprint of the question plan, and it is checked on every round. A
|
|
578
|
+
conversation already in flight when you deploy this has no fingerprint in its
|
|
579
|
+
state and is refused once with `INVALID_REQUEST_STATE`; the host re-asks and the
|
|
580
|
+
retry succeeds.
|
|
581
|
+
|
|
582
|
+
### Guarding tools — `lifecycle`
|
|
583
|
+
|
|
584
|
+
A tool call runs the same handler an HTTP request would. `lifecycle` makes it
|
|
585
|
+
run the same gate: a `beforeHandle` (throw to reject) and an `afterHandle`
|
|
586
|
+
(transform the result). Pass the **same**
|
|
587
|
+
[`createAuthHook`](./auth-and-errors.md#createauthhook) result used as the HTTP
|
|
588
|
+
server's `authorize` hook and tool calls are scope-checked by identical rules:
|
|
589
|
+
|
|
590
|
+
```ts
|
|
591
|
+
createMcpHandler({ serverInfo, auth, services, lifecycle: { beforeHandle: authHook } })
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
Without it, a tool call bypasses the HTTP `authorize` gate — the contract's
|
|
595
|
+
`scope` is not enforced on the MCP / agent surface. `mountMcp`, `mountAgent` and
|
|
596
|
+
`buildMcpServer` take `lifecycle` too.
|
|
597
|
+
|
|
598
|
+
The observability `hooks` are symmetric with the HTTP side too: `beforeToolCall`
|
|
599
|
+
and `afterToolCall` receive the resolved **`MethodDef`** as `endpoint` —
|
|
600
|
+
the tool-side twin of `afterHandle(ctx, result, endpoint)`. Read
|
|
601
|
+
`endpoint.serviceName` / `.key` / `.meta` directly for an audit row; you do not
|
|
602
|
+
need to rebuild a `toolName → identity` map:
|
|
603
|
+
|
|
604
|
+
```ts
|
|
605
|
+
hooks: {
|
|
606
|
+
afterToolCall: ({ result, durationMs, endpoint }) => {
|
|
607
|
+
audit({
|
|
608
|
+
service: endpoint.serviceName,
|
|
609
|
+
action: endpoint.key,
|
|
610
|
+
ok: result.ok,
|
|
611
|
+
ms: durationMs,
|
|
612
|
+
})
|
|
613
|
+
},
|
|
614
|
+
}
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
> **Tool-path identity.** A tool call has no `req`, so `createAuthHook` resolves
|
|
618
|
+
> identity through `resolveFromContext`, not `resolve`. Set it (read the
|
|
619
|
+
> identity your `auth` / `context` injected) — without it a scoped tool call
|
|
620
|
+
> has no identity and **fails closed**. See
|
|
621
|
+
> [Auth on the tool surface](./auth-and-errors.md#auth-on-the-tool-surface--resolvefromcontext).
|
|
622
|
+
|
|
623
|
+
### MCP schema validation profile
|
|
624
|
+
|
|
625
|
+
A contract schema that JSON Schema cannot represent (a `z.date()`, a `z.map()`)
|
|
626
|
+
cannot become a tool. `schemaValidation.policy` decides what happens:
|
|
627
|
+
|
|
628
|
+
- `'throw'` (default) — fail the build, listing every offending tool. A static
|
|
629
|
+
`services` array is checked when `createMcpHandler` is constructed, so a bad
|
|
630
|
+
schema fails the deploy, not the first request. Better than a tool that
|
|
631
|
+
silently vanishes from the surface.
|
|
632
|
+
- `'warn'` — log through `logger` and drop the tool.
|
|
633
|
+
- `'skip'` — drop the tool silently.
|
|
634
|
+
|
|
635
|
+
`validateMcpSchemas({ services })` runs the same check on its own — useful in a
|
|
636
|
+
startup assertion or a test.
|
|
637
|
+
|
|
638
|
+
For a static `services` array, collection, schema conversion and every enabled
|
|
639
|
+
validation guard run once when the handler is created. Each HTTP request still
|
|
640
|
+
receives a fresh `McpServer`, runner, context and native registration over that
|
|
641
|
+
immutable prepared surface. A `services(auth)` factory
|
|
642
|
+
is deliberately prepared after resolving each identity because its tool set may
|
|
643
|
+
change by tenant.
|
|
644
|
+
|
|
645
|
+
#### Is every property actually usable by a model?
|
|
646
|
+
|
|
647
|
+
A tool schema is the only instruction a model gets about the shape of its
|
|
648
|
+
arguments. A property that carries a `description` and no `type` / `enum` /
|
|
649
|
+
`anyOf` / `$ref` tells it nothing — and nothing fails: the schema converts, the
|
|
650
|
+
mount succeeds, the tool is advertised, and the model then guesses, retrying the
|
|
651
|
+
same wrong guess because the error does not say what the right one would be.
|
|
652
|
+
|
|
653
|
+
```ts
|
|
654
|
+
validateMcpSchemas({
|
|
655
|
+
services,
|
|
656
|
+
policy: 'throw',
|
|
657
|
+
logger,
|
|
658
|
+
extend,
|
|
659
|
+
flattenUnionInput: true,
|
|
660
|
+
requireTypedProperties: true,
|
|
661
|
+
requirePortableFormats: true,
|
|
662
|
+
allowFormats: [],
|
|
663
|
+
})
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
For an arbitrary **JSON value**, declare `z.json()`: its recursive JSON Schema
|
|
667
|
+
describes strings, numbers, booleans, null, arrays and objects, so strict schema
|
|
668
|
+
validation needs no exception. `z.unknown()` means an unknown runtime value —
|
|
669
|
+
including values JSON cannot represent — and therefore gives a model no usable
|
|
670
|
+
shape. The guard is off by default for existing contracts. `allowUntyped` takes
|
|
671
|
+
dotted `tool.property` paths and is reserved for a presentation value that is
|
|
672
|
+
genuinely impossible to represent as JSON Schema. On `createMcpHandler`, put the policy under
|
|
673
|
+
`schemaValidation`; the handler supplies its real `extend` and
|
|
674
|
+
`flattenUnionInput`, so the check cannot vet a different document from the one
|
|
675
|
+
advertised.
|
|
676
|
+
|
|
677
|
+
`requirePortableFormats` rejects custom `format` values common MCP/AJV clients
|
|
678
|
+
do not know, such as the `cuid2` emitted by `z.cuid2()`. Use a portable
|
|
679
|
+
schema/pattern, or list it in `allowFormats` only when every client supports it.
|
|
680
|
+
stitchkit never removes or rewrites the keyword.
|
|
681
|
+
|
|
682
|
+
`findUntypedProperties(jsonSchema)` is the same walk, exported on its own if you
|
|
683
|
+
want to assert on a schema you built elsewhere.
|
|
684
|
+
|
|
685
|
+
### Discriminated unions for weaker models — `flattenUnionInput`
|
|
686
|
+
|
|
687
|
+
A discriminated union in a tool's input becomes a JSON Schema `oneOf` / `anyOf`.
|
|
688
|
+
Capable models (Claude, Gemini, GPT) handle that; weaker / cheaper ones can drop
|
|
689
|
+
the field or mangle its strings. Set `flattenUnionInput: true` (on
|
|
690
|
+
`createMcpHandler` / `mountMcp` / `mountAgent`) to advertise each discriminated
|
|
691
|
+
union as a **single flat object** instead — the discriminator becomes an enum and
|
|
692
|
+
each variant's fields become optional with a `Required if <disc> = …` hint.
|
|
693
|
+
|
|
694
|
+
**A field several variants declare keeps its type.** Flattening puts every
|
|
695
|
+
variant's fields side by side, so a key two variants share has to be advertised
|
|
696
|
+
as one thing. Where they agree, that is what you get; where they disagree — a
|
|
697
|
+
`.refine()` only one of them carries, two different bounds on the same number, an
|
|
698
|
+
enum against a free string — the *constraint* is dropped and the **type** is not.
|
|
699
|
+
A field that is a number in every variant is advertised as a number, not as a
|
|
700
|
+
bare description. When the kinds genuinely differ, the flat projection keeps
|
|
701
|
+
every provable kind in a deterministic JSON Schema type array — for example
|
|
702
|
+
`type: ['string', 'array']` — while dropping constraints that are not sound for
|
|
703
|
+
all branches. Nested `oneOf` / `anyOf` values still contribute their provable
|
|
704
|
+
base kinds without reintroducing union keywords. Only a branch whose kind is
|
|
705
|
+
actually unknowable, such as a free-form schema or unresolved reference, leaves
|
|
706
|
+
the collision unconstrained. → ADRs [0044](../decisions/0044-a-collided-field-keeps-its-type.md)
|
|
707
|
+
and [0065](../decisions/0065-flat-collisions-preserve-every-known-kind.md)
|
|
708
|
+
|
|
709
|
+
It is **deep** because the projection walks the generated JSON Schema document,
|
|
710
|
+
including objects, arrays, tuples and schema-definition nodes. Structurally
|
|
711
|
+
identifiable discriminated object unions are flattened wherever they occur.
|
|
712
|
+
Plain unions and unions hidden behind unresolved external references remain
|
|
713
|
+
unions because Stitchkit cannot soundly invent a discriminator.
|
|
714
|
+
|
|
715
|
+
Use the default `flattenUnionInput: false` when the model must see the exact
|
|
716
|
+
relationship between a discriminator and each branch. The flat type array is a
|
|
717
|
+
sound set of possible JSON kinds, not a reconstruction of those correlations.
|
|
718
|
+
|
|
719
|
+
The flattened form is **lossy but never executable**. Per-variant refinements
|
|
720
|
+
and incompatible constraints are widened in the presentation document; the
|
|
721
|
+
original Zod contract enforces them exactly once inside `executeToolMethod`.
|
|
722
|
+
MCP and AI adapters forward the raw argument object unchanged, so defaults,
|
|
723
|
+
coercions and transforms cannot run before Stitchkit. Strict violations return
|
|
724
|
+
the normal `VALIDATION_ERROR` tool envelope and fire `beforeToolCall` /
|
|
725
|
+
`afterToolCall`. → [ADR 0050](../decisions/0050-presentation-schema-is-not-a-parser.md).
|
|
726
|
+
|
|
727
|
+
## `mountMcp`
|
|
728
|
+
|
|
729
|
+
If you already run an `McpServer` from the SDK, `mountMcp` adds contract tools
|
|
730
|
+
to it instead of owning the lifecycle:
|
|
731
|
+
|
|
732
|
+
```ts
|
|
733
|
+
import { mountMcp } from 'stitchkit/tools'
|
|
734
|
+
|
|
735
|
+
mountMcp(mcpServer, [usersService], { context: { source: 'mcp' } })
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
`createMcpHandler` is the batteries-included path; `mountMcp` is the building
|
|
739
|
+
block under it.
|
|
740
|
+
|
|
741
|
+
## MCP over stdio — `createStdioMcpServer`
|
|
742
|
+
|
|
743
|
+
`createMcpHandler` serves MCP over HTTP. `createStdioMcpServer` serves the same
|
|
744
|
+
contract tools over **stdio** — the server runs as a subprocess of the MCP
|
|
745
|
+
client (Claude Desktop, Claude Code, Cursor, Codex), on the user's machine, so
|
|
746
|
+
it can reach the local filesystem.
|
|
747
|
+
|
|
748
|
+
```ts
|
|
749
|
+
import { bindStdioProcessSignals, createStdioMcpServer } from 'stitchkit/tools'
|
|
750
|
+
|
|
751
|
+
const stdio = await createStdioMcpServer({
|
|
752
|
+
serverInfo: { name: 'my-app', version: '1.0.0' },
|
|
753
|
+
auth: resolveIdentity(), // resolved once at startup, not per request
|
|
754
|
+
services: [usersService],
|
|
755
|
+
})
|
|
756
|
+
|
|
757
|
+
const signals = bindStdioProcessSignals(stdio, {
|
|
758
|
+
onClose: () => stopWorkers(),
|
|
759
|
+
onComplete: () => { process.exitCode = 0 },
|
|
760
|
+
onError: (_phase, error) => {
|
|
761
|
+
console.error(error) // stderr only — stdout is JSON-RPC
|
|
762
|
+
process.exitCode = 1
|
|
763
|
+
},
|
|
764
|
+
})
|
|
765
|
+
|
|
766
|
+
await signals.promise
|
|
767
|
+
```
|
|
768
|
+
|
|
769
|
+
A stdio server is a single process serving one client, so `auth` is a value (or
|
|
770
|
+
a promise of one) resolved once at startup — typically from an env var — rather
|
|
771
|
+
than a per-request `(req) => …`. Keep all logging on **stderr**: stdout is the
|
|
772
|
+
JSON-RPC channel.
|
|
773
|
+
|
|
774
|
+
The default `legacy: 'serve'` negotiates the modern or supported legacy opening
|
|
775
|
+
through the official stdio adapter. Use `legacy: 'reject'` for a modern-only
|
|
776
|
+
binary. Each invocation builds a fresh server; the returned handle owns
|
|
777
|
+
transport shutdown.
|
|
778
|
+
|
|
779
|
+
Signal binding is explicit: `createStdioMcpServer` installs no global process
|
|
780
|
+
listeners by itself. The first `SIGINT`/`SIGTERM` starts exactly one official
|
|
781
|
+
`close()` chain. Stdio has no force primitive, so a later signal restores the
|
|
782
|
+
OS default disposition instead of reporting a fictional forced result.
|
|
783
|
+
`signals.close()` removes an idle binding; the framework never calls
|
|
784
|
+
`process.exit()` or chooses the exit code. See
|
|
785
|
+
[deployment lifecycle](./testing-and-deployment.md#stdio-process-signals).
|
|
786
|
+
|
|
787
|
+
Both transports build the server through the shared `buildMcpServer` — same
|
|
788
|
+
contract/runtime pipeline, same surface selection, context, hooks, raw escape
|
|
789
|
+
hatch and instructions.
|
|
790
|
+
|
|
791
|
+
## OAuth 2.1 — a native remote connector
|
|
792
|
+
|
|
793
|
+
A remote MCP server is connectable from Claude (Desktop / web "custom
|
|
794
|
+
connector") only through the MCP authorization spec: OAuth 2.1 with PKCE, plus
|
|
795
|
+
the discovery documents (RFC 9728 / 8414), Client ID Metadata Documents (CIMD)
|
|
796
|
+
and resource indicators (RFC 8707). A Bearer-only server returns a
|
|
797
|
+
bare `401` and the connector never establishes.
|
|
798
|
+
|
|
799
|
+
stitchkit ships the OAuth **protocol mechanics**; the app supplies only
|
|
800
|
+
**identity and storage**. Three pieces wire it together:
|
|
801
|
+
|
|
802
|
+
```ts
|
|
803
|
+
import { createMcpHandler, createMcpHttpRoute, mountOAuthProvider, oauthProtectedResourceRoute } from 'stitchkit/tools'
|
|
804
|
+
import { createServer } from 'stitchkit/server'
|
|
805
|
+
|
|
806
|
+
const resource = 'https://api.example.com/mcp'
|
|
807
|
+
const issuer = 'https://api.example.com'
|
|
808
|
+
|
|
809
|
+
// 1. Resource server — the 401 now points at the metadata.
|
|
810
|
+
const mcp = createMcpHandler({
|
|
811
|
+
serverInfo: { name: 'my-app', version: '1.0.0' },
|
|
812
|
+
auth: resolveOAuthToken, // validate the Bearer JWT (verifyJwt + audience)
|
|
813
|
+
services,
|
|
814
|
+
protectedResource: { resource, authorizationServers: [issuer] },
|
|
815
|
+
})
|
|
816
|
+
|
|
817
|
+
// 2. Authorization server — CIMD, /authorize (PKCE), /token.
|
|
818
|
+
const oauthRoutes = mountOAuthProvider({
|
|
819
|
+
issuer,
|
|
820
|
+
resource,
|
|
821
|
+
signingSecret: env.OAUTH_SECRET,
|
|
822
|
+
clientRegistration: {
|
|
823
|
+
preRegistered: { get: getFirstPartyClient },
|
|
824
|
+
// CIMD is enabled with secure defaults; DCR remains disabled.
|
|
825
|
+
},
|
|
826
|
+
codes, refreshTokens, // your stores (DB or in-memory)
|
|
827
|
+
authorizeUser, // → { userId, approvedScopes } | Response
|
|
828
|
+
})
|
|
829
|
+
|
|
830
|
+
createServer({
|
|
831
|
+
services,
|
|
832
|
+
rawRoutes: [
|
|
833
|
+
createMcpHttpRoute({ path: '/mcp', handler: mcp }),
|
|
834
|
+
oauthProtectedResourceRoute({ resource, authorizationServers: [issuer] }),
|
|
835
|
+
...oauthRoutes,
|
|
836
|
+
],
|
|
837
|
+
})
|
|
838
|
+
```
|
|
839
|
+
|
|
840
|
+
Access tokens are signed HS256 JWTs (`signJwt`) whose `aud` is the resource and
|
|
841
|
+
whose `iss` is the issuer — validate both in `auth` with
|
|
842
|
+
`verifyJwt(token, secret, { audience: resource, issuer })`. `authorizeUser` is
|
|
843
|
+
where the app authenticates the user (reuse an existing session) and records
|
|
844
|
+
consent; return `{ userId, approvedScopes }`, where approved scopes are a subset
|
|
845
|
+
of the requested/supported values, or a `Response` to redirect the browser to a
|
|
846
|
+
login page first. The AS and resource server can co-locate or live
|
|
847
|
+
on separate origins. See
|
|
848
|
+
[ADR 0015](../decisions/0015-oauth-resource-server.md).
|
|
849
|
+
|
|
850
|
+
Client resolution is deterministic: exact pre-registered client, then an HTTPS
|
|
851
|
+
URL client id resolved as CIMD, then explicitly enabled DCR. CIMD is on by
|
|
852
|
+
default; DCR is off unless `clientRegistration.dcr` supplies both `register` and
|
|
853
|
+
`get`. A CIMD-only deployment therefore exposes neither `/register` nor a
|
|
854
|
+
`registration_endpoint`. The metadata document must declare a `client_id` that
|
|
855
|
+
exactly equals its URL, explicit redirect URIs and
|
|
856
|
+
`token_endpoint_auth_method: 'none'`.
|
|
857
|
+
|
|
858
|
+
The production fetcher rejects credentials, fragments, non-HTTPS URLs and
|
|
859
|
+
private/reserved targets. Every redirect is DNS-resolved and IP-pinned again;
|
|
860
|
+
timeouts, redirect count and body size are bounded. Its bounded cache respects
|
|
861
|
+
`Cache-Control` (including `no-store`/`no-cache`), `Age`, `Expires`, `ETag` and
|
|
862
|
+
`Last-Modified`, coalesces concurrent misses and reports sanitized cache events;
|
|
863
|
+
invalid or unavailable identity receives only a short fail-closed cache entry.
|
|
864
|
+
|
|
865
|
+
Resolution itself is rate-limited on two levels (`CimdCachePolicy`):
|
|
866
|
+
`maxResolutionsPerClient` (default 10) bounds ONE `client_id` per
|
|
867
|
+
`resolutionWindowMs` window (default 60 s) — a client whose document disables
|
|
868
|
+
caching burns its own budget, not the server's — while `maxResolutions`
|
|
869
|
+
(default 120) caps the server-wide outbound rate as the flood backstop.
|
|
870
|
+
Positive and negative cache entries keep separate pools of `maxEntries` each,
|
|
871
|
+
so a flood of unresolvable ids cannot evict warmed clients and a burst of
|
|
872
|
+
successes cannot reset a failing client's backoff.
|
|
873
|
+
|
|
874
|
+
### Authorization hardening (MCP 2026-07-28)
|
|
875
|
+
|
|
876
|
+
- **`iss` on every authorization response (RFC 9207, SEP-2468).** Success *and*
|
|
877
|
+
error redirects carry `iss`, and the AS metadata advertises
|
|
878
|
+
`authorization_response_iss_parameter_supported: true`. A client that talks to
|
|
879
|
+
several authorization servers validates `iss` before redeeming the code, which
|
|
880
|
+
closes the **mix-up attack** — an attacker's server cannot pass its response
|
|
881
|
+
off as this issuer's. Additive on the wire: a client that ignores `iss` is
|
|
882
|
+
unaffected.
|
|
883
|
+
- **`application_type` on registration (SEP-837).** A client may declare
|
|
884
|
+
`"native"` (desktop / CLI) or `"web"` in its DCR body. A **native** client may
|
|
885
|
+
register an `http` loopback redirect (`http://127.0.0.1:…`, RFC 8252 §7.3); a
|
|
886
|
+
**web** client is held to `https` only — that mismatch is the usual cause of
|
|
887
|
+
the `redirect_uri` rejection CLI clients hit. Omit the field and registration
|
|
888
|
+
behaves exactly as before (loopback allowed); an unknown value is rejected
|
|
889
|
+
rather than silently defaulted.
|
|
890
|
+
|
|
891
|
+
> Dynamic Client Registration is an explicit interoperability mode, not the
|
|
892
|
+
> default. Enabling it changes public discovery and adds `/register`; keep it off
|
|
893
|
+
> unless a client that cannot publish CIMD requires it.
|
|
894
|
+
|
|
895
|
+
## Proxying a remote API — `implementRemote`
|
|
896
|
+
|
|
897
|
+
`implement` binds a contract to local handlers. `implementRemote` binds it to a
|
|
898
|
+
remote HTTP API instead — every handler forwards the call to a deployed server
|
|
899
|
+
through the contract's typed client:
|
|
900
|
+
|
|
901
|
+
```ts
|
|
902
|
+
import { createHttpClient } from 'stitchkit'
|
|
903
|
+
import { implementRemote } from 'stitchkit/remote'
|
|
904
|
+
import { createStdioMcpServer } from 'stitchkit/tools'
|
|
905
|
+
|
|
906
|
+
const http = createHttpClient({
|
|
907
|
+
baseUrl: 'https://api.example.com',
|
|
908
|
+
headers: () => ({ Authorization: `Bearer ${apiKey}` }),
|
|
909
|
+
})
|
|
910
|
+
|
|
911
|
+
const stdio = await createStdioMcpServer({
|
|
912
|
+
serverInfo: { name: 'my-app', version: '1.0.0' },
|
|
913
|
+
auth: null,
|
|
914
|
+
services: contracts.map((c) => implementRemote(c, http)),
|
|
915
|
+
})
|
|
916
|
+
|
|
917
|
+
// During graceful shutdown:
|
|
918
|
+
await stdio.close()
|
|
919
|
+
```
|
|
920
|
+
|
|
921
|
+
This is how you ship a thin **local** MCP server for an API that already runs in
|
|
922
|
+
the cloud: the local process owns only the transport and any filesystem-facing
|
|
923
|
+
native tools, while every contract tool proxies to the remote API. One contract,
|
|
924
|
+
no duplicated business logic.
|
|
925
|
+
|
|
926
|
+
`implementRemote(contract, http, { transformArgs })` takes an optional
|
|
927
|
+
`transformArgs` hook that rewrites a call's arguments before they are forwarded
|
|
928
|
+
— e.g. to upload a local file referenced in the args and swap in its URL.
|
|
929
|
+
|
|
930
|
+
## Structured output
|
|
931
|
+
|
|
932
|
+
When a contract endpoint or runtime tool declares `output`, its MCP tool
|
|
933
|
+
registers that exact schema as `outputSchema` and returns the validated value as
|
|
934
|
+
`structuredContent` alongside a JSON text block. Every JSON root type is kept
|
|
935
|
+
unchanged: object, array, string, number, boolean and `null`. Stitchkit does not
|
|
936
|
+
wrap non-object values in `{ result }`; protocol-era adaptation belongs to the
|
|
937
|
+
official SDK.
|
|
938
|
+
|
|
939
|
+
A tool without an output contract advertises no `outputSchema` and returns no
|
|
940
|
+
invented structured value. Its successful MCP result has an empty `content`
|
|
941
|
+
list.
|
|
942
|
+
|
|
943
|
+
## A different answer for tools — `withToolView`
|
|
944
|
+
|
|
945
|
+
An admin page wants the full record; a model wants a card. Every byte of a
|
|
946
|
+
tool result enters the model's context and stays in its history, and personal
|
|
947
|
+
fields a task does not need are better never shown to it. Two endpoints on one
|
|
948
|
+
path (one `expose: ['HTTP']`, one for the tools) duplicate the description, the
|
|
949
|
+
schemas and the handler; branching on `ctx.source` teaches every handler about
|
|
950
|
+
transports and still advertises the full output schema.
|
|
951
|
+
|
|
952
|
+
A **tool view** declares the difference on the endpoint instead:
|
|
953
|
+
|
|
954
|
+
```ts
|
|
955
|
+
import { defineContract, withToolView } from 'stitchkit';
|
|
956
|
+
|
|
957
|
+
export const users = defineContract({ prefix: 'users' }, {
|
|
958
|
+
list: withToolView(
|
|
959
|
+
{
|
|
960
|
+
method: 'GET', path: '/', desc: 'List users', tool: { name: 'user_list' },
|
|
961
|
+
input: UserListQuery, // include: z.array(...).default(['profile', 'stats'])
|
|
962
|
+
output: UserListResponse, // HTTP, OpenAPI and the typed client — unchanged
|
|
963
|
+
},
|
|
964
|
+
{
|
|
965
|
+
defaults: { include: [] }, // what a tool call gets when it passes nothing
|
|
966
|
+
output: UserCardList, // the tool answer and its schema
|
|
967
|
+
project: (full, { input }) => ({ items: full.items.map(toCard) }), // optional: without it, `output` slices
|
|
968
|
+
},
|
|
969
|
+
),
|
|
970
|
+
});
|
|
971
|
+
```
|
|
972
|
+
|
|
973
|
+
- **One handler, one parser.** `defaults` joins the tool call's arguments
|
|
974
|
+
*before* the endpoint's own `input` parses them, so the handler receives an
|
|
975
|
+
ordinary `input` — `include: []` from a tool, the HTTP default from HTTP — and
|
|
976
|
+
loads only what was asked for. An explicit argument wins over the default.
|
|
977
|
+
- **The answer is derived, then checked.** The handler's result is validated
|
|
978
|
+
against the full `output` first, as always; then `project` (a pure,
|
|
979
|
+
synchronous function of the full result and the parsed input) or a slice by
|
|
980
|
+
the view's `output`, then validation against the view's schema. A projection
|
|
981
|
+
that throws, returns a Promise or breaks its schema is `INTERNAL_SERVER_ERROR`
|
|
982
|
+
— a server fault, like any output mismatch.
|
|
983
|
+
- **Where it applies.** The MCP, agent and CLI mounts answer with the view;
|
|
984
|
+
`outputSchema`, `structuredContent`, the advertised input `default`, the
|
|
985
|
+
catalog stamp and the surface snapshot follow it. HTTP, OpenAPI, the typed
|
|
986
|
+
client and the in-process [`createToolInvoker`](#in-process-calls--createtoolinvoker)
|
|
987
|
+
keep the full answer — code, not a model, is calling there.
|
|
988
|
+
- **Three forms, one helper.** With `output` and `project` the answer has its
|
|
989
|
+
own schema. With `project` alone it reshapes values inside the full schema.
|
|
990
|
+
With `output` alone it is a slice, and the full result must fit that schema —
|
|
991
|
+
`withToolView` refuses the endpoint at compile time when it does not.
|
|
992
|
+
- **Exposure.** A view needs a tool transport. With `createContractFactory({
|
|
993
|
+
toolExposure: 'explicit' })` an endpoint without `expose` is HTTP-only, so an
|
|
994
|
+
endpoint with a view names its tool transports in `expose`.
|
|
995
|
+
- **What it refuses.** `defineContract` rejects a view on an endpoint with no
|
|
996
|
+
tool transport or no full `output`, on a raw, `rawBody`, multipart,
|
|
997
|
+
`responseMeta` or streaming endpoint, a view that declares neither `output`
|
|
998
|
+
nor `project`, and a default for a key the input does not have, for a path
|
|
999
|
+
param, or with a value the input would reject.
|
|
1000
|
+
|
|
1001
|
+
A projection adds nothing the full result does not carry: a field the tool
|
|
1002
|
+
answer needs belongs in the full answer, loaded by the handler. Keys a
|
|
1003
|
+
projection returns beyond its schema are reported by `onOutputStrip`; a slice
|
|
1004
|
+
removes keys on purpose and is not reported. → [ADR 0196](../decisions/0196-a-tool-answer-is-a-declared-view.md)
|