@zackbart/connecta 0.10.6 → 0.12.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.
Files changed (97) hide show
  1. package/AGENTS.md +8 -6
  2. package/CHANGELOG.md +80 -0
  3. package/README.md +5 -4
  4. package/bin/connecta.mjs +0 -7
  5. package/dist/activity.d.ts.map +1 -1
  6. package/dist/activity.js.map +1 -1
  7. package/dist/apps-shell.d.ts +38 -0
  8. package/dist/apps-shell.d.ts.map +1 -0
  9. package/dist/apps-shell.js +175 -0
  10. package/dist/apps-shell.js.map +1 -0
  11. package/dist/catalog-service.d.ts +2 -17
  12. package/dist/catalog-service.d.ts.map +1 -1
  13. package/dist/catalog-service.js +4 -6
  14. package/dist/catalog-service.js.map +1 -1
  15. package/dist/connectors/api.d.ts +2 -2
  16. package/dist/connectors/remote-mcp.d.ts +1 -1
  17. package/dist/errors.d.ts +1 -3
  18. package/dist/errors.d.ts.map +1 -1
  19. package/dist/errors.js +1 -1
  20. package/dist/errors.js.map +1 -1
  21. package/dist/execute.d.ts +37 -8
  22. package/dist/execute.d.ts.map +1 -1
  23. package/dist/execute.js +137 -42
  24. package/dist/execute.js.map +1 -1
  25. package/dist/executor-admission.d.ts +8 -0
  26. package/dist/executor-admission.d.ts.map +1 -1
  27. package/dist/executor-admission.js +11 -0
  28. package/dist/executor-admission.js.map +1 -1
  29. package/dist/executors/quickjs.d.ts.map +1 -1
  30. package/dist/executors/quickjs.js +2 -2
  31. package/dist/executors/quickjs.js.map +1 -1
  32. package/dist/index.d.ts +15 -31
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +23 -37
  35. package/dist/index.js.map +1 -1
  36. package/dist/invocation.js +2 -2
  37. package/dist/invocation.js.map +1 -1
  38. package/dist/meta-tools.d.ts +19 -58
  39. package/dist/meta-tools.d.ts.map +1 -1
  40. package/dist/meta-tools.js +34 -431
  41. package/dist/meta-tools.js.map +1 -1
  42. package/dist/registry.d.ts +1 -10
  43. package/dist/registry.d.ts.map +1 -1
  44. package/dist/registry.js +3 -15
  45. package/dist/registry.js.map +1 -1
  46. package/dist/routes/mcp.d.ts.map +1 -1
  47. package/dist/routes/mcp.js +67 -30
  48. package/dist/routes/mcp.js.map +1 -1
  49. package/dist/routes/shared.d.ts +5 -11
  50. package/dist/routes/shared.d.ts.map +1 -1
  51. package/dist/routes/shared.js.map +1 -1
  52. package/dist/server.js +5 -4
  53. package/dist/server.js.map +1 -1
  54. package/dist/skills.d.ts +8 -18
  55. package/dist/skills.d.ts.map +1 -1
  56. package/dist/skills.js +13 -60
  57. package/dist/skills.js.map +1 -1
  58. package/dist/types.d.ts +6 -20
  59. package/dist/types.d.ts.map +1 -1
  60. package/dist/version.d.ts +1 -1
  61. package/dist/version.js +1 -1
  62. package/documentation/code-first-exploration.md +16 -16
  63. package/documentation/code-mode.md +130 -41
  64. package/documentation/connectors.md +1 -1
  65. package/documentation/mcp-2026-07-28.md +1 -1
  66. package/documentation/mcp-ui-design.md +382 -0
  67. package/documentation/meta-tools.md +30 -43
  68. package/documentation/rich-output-design.md +4 -4
  69. package/ethos.md +7 -2
  70. package/examples/node/README.md +1 -2
  71. package/examples/node/src/index.ts +1 -3
  72. package/examples/worker/README.md +8 -13
  73. package/examples/worker/src/index.ts +6 -14
  74. package/examples/worker/wrangler.jsonc +3 -6
  75. package/package.json +1 -1
  76. package/src/activity.ts +5 -0
  77. package/src/apps-shell.ts +179 -0
  78. package/src/catalog-service.ts +6 -26
  79. package/src/connectors/api.ts +2 -2
  80. package/src/connectors/remote-mcp.ts +1 -1
  81. package/src/errors.ts +2 -2
  82. package/src/execute.ts +150 -49
  83. package/src/executor-admission.ts +12 -0
  84. package/src/executors/quickjs.ts +2 -1
  85. package/src/index.ts +40 -69
  86. package/src/invocation.ts +2 -2
  87. package/src/meta-tools.ts +38 -565
  88. package/src/registry.ts +2 -33
  89. package/src/routes/mcp.ts +79 -30
  90. package/src/routes/shared.ts +4 -11
  91. package/src/server.ts +7 -7
  92. package/src/skills.ts +11 -74
  93. package/src/types.ts +6 -21
  94. package/src/version.ts +1 -1
  95. package/templates/node/README.md +2 -1
  96. package/templates/node/package.json +1 -1
  97. package/templates/node/src/index.ts +1 -1
@@ -20,19 +20,11 @@ are stable and cited by the tests in [Verification](#verification).
20
20
 
21
21
  ## Deploy-time capability
22
22
 
23
- The `executor` passed to `createConnecta()` is the complete switch, and it selects
24
- the whole surface rather than one tool
25
- ([#224](https://github.com/zackbart/connecta/issues/224)): with a live `Executor`,
26
- `tools/list` is exactly seven `execute_code`, `search_tools`, `call_tool`,
27
- `call_destructive_tool`, `authorize_connector`, `get_result`, `skills`; without one
28
- it is the nine base meta-tools, whose `list_connectors`, `describe_tools`, and
29
- `batch_call` are what seven folds into `connecta.search`, `connecta.describe`, and
30
- `connecta.batch`.
31
-
32
- No feature flag, and no code tool advertised before it can be honored.
33
- `surface: "classic"` beside an executor is the one override (ten tools, the eval
34
- gate's incremental arm); `surface: "code-first"` without one throws at
35
- construction rather than advertise an absent program surface.
23
+ The `executor` passed to `createConnecta()` is required. `tools/list` is exactly
24
+ seven `execute_code`, `search_tools`, `call_tool`, `call_destructive_tool`,
25
+ `authorize_connector`, `get_result`, and `skills`. Construction fails when the
26
+ executor is missing, and the removed `surface` option is rejected rather than
27
+ ignored ([#273](https://github.com/zackbart/connecta/issues/273)).
36
28
 
37
29
  On Node, install the optional `quickjs-emscripten` peer and use the package's
38
30
  QuickJS subpath:
@@ -51,25 +43,20 @@ const connecta = createConnecta({
51
43
  CPU, wall-time, memory, stack, queue, result, log, and IPC bounds are configured
52
44
  on the executor. Server bundlers must keep the `@zackbart/connecta/quickjs`
53
45
  package files external so the child entry stays on disk. The
54
- [Node example](../examples/node/README.md) is enabled; remove its `executor` field
55
- for the nine-tool compatibility deployment.
46
+ [Node example](../examples/node/README.md) carries the complete setup.
56
47
 
57
- On Cloudflare Workers, the Worker Loader binding is both the paid capability and
58
- the configuration switch:
48
+ On Cloudflare Workers, the Worker Loader binding provides the required sandbox:
59
49
 
60
50
  ```ts
61
51
  createConnecta({
62
- ...(env.LOADER
63
- ? { executor: new DynamicWorkerExecutor({ loader: env.LOADER }) }
64
- : {}),
52
+ executor: new DynamicWorkerExecutor({ loader: env.LOADER }),
65
53
  // connectors, auth, storage…
66
54
  });
67
55
  ```
68
56
 
69
- Leave the binding absent on the Workers Free plan. Its absence must also be
70
- represented as optional in the deployment's `Env` type. The
57
+ Dynamic Workers require the Workers Paid plan. The
71
58
  [Worker example](../examples/worker/README.md#code-mode) carries the complete
72
- binding and package setup.
59
+ required binding and package setup.
73
60
 
74
61
  ## What an executor must implement
75
62
 
@@ -305,8 +292,8 @@ const outcomes = await connecta.batch([
305
292
  order. A success is `{ address, ok: true, data }`. A failure is
306
293
  `{ address, ok: false, error, errorDetails }`, where `error` is the message and
307
294
  `errorDetails` is the typed object described in [Errors](#errors) — the same two
308
- field names `batch_call` uses. One failing call never rejects the batch, and more
309
- than ten calls throws.
295
+ field names the host's internal batch path uses. One failing call never rejects
296
+ the batch, and more than ten calls throws.
310
297
 
311
298
  **S8.** `connecta.batch` is the classification channel: because a thrown host
312
299
  error crosses the bridge as a bare message (`E1`), a batch of one is the supported
@@ -381,7 +368,9 @@ guest: admission rejection (`executor_overloaded`, retryable, with
381
368
  (`executor_closed`), deadline expiry, and sandbox crashes end the run and are
382
369
  reported to the model as an error result. One seam: a host call still in flight
383
370
  when the run is cancelled fails with `cancelled`, catchable on the way out but
384
- never worth acting on (`Y3`).
371
+ never worth acting on (`Y3`). When shutdown tears down a program that had
372
+ already started, accepted blocks and UI are reported as discarded under `M4`
373
+ and `U3`; a failure before execution started carries no discard fields.
385
374
 
386
375
  **E6.** An error the program raises itself — a `TypeError`, a call to a
387
376
  `connecta` member that is not a provider function (including an inherited one
@@ -500,6 +489,97 @@ response, and `emit` resolving means "accepted," never "delivered."
500
489
  aggregate — count and serialized bytes, numbers only (`R8`), present only
501
490
  when something was emitted.
502
491
 
492
+ ## Rendered output
493
+
494
+ `connecta.emit` gave programs pixels; it did not give them a *view*. This is the
495
+ one the human looks at directly while the model keeps its cheap textual summary:
496
+ one MCP Apps view per successful run, assembled where composition already
497
+ happens. Programs supply HTML content and nothing else — the only `ui://` URI in
498
+ the system is connecta's build-time shell, so nothing a client could dereference
499
+ is derived from anything a program said. The argument, the refused shapes, and
500
+ the security posture live in the [design record](./mcp-ui-design.md)
501
+ ([#266](https://github.com/zackbart/connecta/issues/266),
502
+ [#277](https://github.com/zackbart/connecta/issues/277)); this section is the
503
+ contract, and it wins where the two disagree.
504
+
505
+ **U1.** `connecta.ui(html)` accepts exactly one argument: a non-empty string of
506
+ HTML. A non-string, an empty string, an options bag, or an MCP block object
507
+ throws catchably and nothing is accepted. There is no options parameter and no
508
+ sugar form, for `M1`'s reason: sugar is how a one-shape contract grows hair.
509
+
510
+ **U2.** At most one payload per run. A second call throws catchably, naming the
511
+ constraint; the first accepted payload stands. One tool result renders one view,
512
+ and last-wins would silently discard a payload the program deliberately
513
+ supplied.
514
+
515
+ **U3.** Delivered on success only, and out of model context: the tool result
516
+ gains `_meta["connecta/ui"] = { html }` and the JSON envelope gains `ui: true`,
517
+ so the model learns a view rendered without seeing its bytes. `structuredContent`
518
+ stays the envelope alone. The single-label `connecta/ui` prefix is deliberate —
519
+ connecta has no domain to reverse, and fabricating one to satisfy MCP's
520
+ reverse-DNS SHOULD would be a worse answer than the shape the key format's MUST
521
+ already permits. A program that never calls `connecta.ui` produces the
522
+ byte-for-byte ordinary response (`R6`). A failed program delivers nothing and
523
+ reports `uiDiscarded: true` *only* when a payload had been accepted — a field on
524
+ the structured envelope, a trailing line on the plain-text paths — coexisting
525
+ with `emittedDiscarded: N` when one failure discards both.
526
+
527
+ **U4.** The payload spends the aggregate emit byte budget
528
+ (`ConnectaConfig.execute.maxEmittedBytes`), measured at the call as the
529
+ serialized bytes of `{ html }` — `M5`'s measurement. Over budget throws
530
+ catchably, naming the budget and the room remaining, with nothing partially
531
+ accepted. It spends no block count (`maxEmittedBlocks`: it is not a block) and no
532
+ host-call budget (`L4`). One transport bound covers everything rich a program
533
+ delivers.
534
+
535
+ **U5.** One static shell: a connecta-authored HTML5 document at
536
+ `ui://connecta/program-ui/v1`, mimeType `text/html;profile=mcp-app`, declared on
537
+ `execute_code` via `_meta.ui.resourceUri` together with an explicit
538
+ `_meta.ui.visibility: ["model"]` — the default `["model","app"]` would tell hosts
539
+ the view may call `execute_code`. A `resources/read` handler answers exactly that
540
+ URI and fails on any other; `resources/list` is served and returns an empty list.
541
+ The version segment bumps whenever the shell's bytes change, because hosts cache
542
+ templates by URI.
543
+
544
+ **U6.** The shell is display-only. It renders the payload in a nested iframe
545
+ (`srcdoc`, `sandbox="allow-scripts"`, no `allow-same-origin`) and declares no CSP
546
+ domains, so the host applies its restrictive default and the `about:srcdoc` frame
547
+ inherits `default-src 'none'; connect-src 'none'`. Program UI gets scripts and
548
+ local interactivity and nothing else: no network, no tool calls, no conversation
549
+ messages, no host-mediated links. The shell participates in the Apps lifecycle —
550
+ initialize, tool-result, size-changed, resource-teardown — and forwards no
551
+ channel whatsoever from the inner frame to the host. That isolation makes
552
+ program views fixed-height by construction: with no bridge there is no
553
+ content-height signal, the shell reports only its own box, and content taller
554
+ than that scrolls inside the inner frame rather than growing the view.
555
+
556
+ **U7.** Structural executor parity, per `M8`: `connecta.ui` is a provider
557
+ function, `ExecuteResult` and the `Executor` interface are unchanged, and both
558
+ executors get it through the bridge they already have.
559
+
560
+ **U8.** Request-local and unstreamed, per `M9`. The payload exists only in the
561
+ finished response, and `connecta.ui` resolving means "accepted," never
562
+ "rendered."
563
+
564
+ **U9.** `diagnostics: true` adds a distinct `ui` aggregate — the payload's byte
565
+ size, a number and nothing else (`R8`), present only when a payload was accepted.
566
+ UI bytes are not folded into `emitted`: that aggregate pairs a block count with
567
+ the bytes those blocks cost, and bytes without a block would desync the pair.
568
+
569
+ **U10.** `_meta.ui.resourceUri` is declared unconditionally. A host without the
570
+ extension ignores unknown `_meta` and sees the ordinary envelope, which *is* the
571
+ text fallback the Apps spec mandates; `connecta.ui` never fails because a client
572
+ cannot render. A stateless aggregator cannot reliably know, and connecta is not a
573
+ nanny.
574
+
575
+ **U11.** connecta declares `io.modelcontextprotocol/ui` in its server capability
576
+ declaration, and that is the one extension it advertises. The Apps extension must
577
+ be explicitly negotiated and a conforming client acts on one only when both sides
578
+ declare it, so without this declaration no host reads `_meta.ui.resourceUri`, no
579
+ host fetches the shell, and the whole design is inert. Reading the *client's*
580
+ declaration in order to register tool metadata conditionally stays refused
581
+ (`U10`), knowingly against a spec SHOULD.
582
+
503
583
  ## Retry semantics
504
584
 
505
585
  **Y1.** Connecta retries nothing beneath a program. `call_tool` accepts an
@@ -603,9 +683,9 @@ calls — which makes moving work into the sandbox an optimization, not a blindf
603
683
  server identity. Typed codes derive an optional `friction`: `tool_not_found`,
604
684
  `schema_retry`, `destructive_reroute`, or `auth_required`. The fifth class,
605
685
  `result_too_large`, cannot reach an `execute_code` event: it belongs to a
606
- `call_tool` result — or a `batch_call` child's — too large to return inline,
607
- and a program's own return is refused paging by design rather than truncated
608
- into friction. There is nowhere to put arguments, results, program source, or
686
+ `call_tool` result too large to return inline, and a program's own
687
+ return is refused paging by design rather than truncated into friction. There is
688
+ nowhere to put arguments, results, program source, or
609
689
  raw error text; a caught failure is still recorded. `address` is
610
690
  canonical (`A1`) where a tool resolved, otherwise the name the program used —
611
691
  for a shortcut its sanitized alias, the honest record of what was attempted.
@@ -692,8 +772,8 @@ entry. Programs that ran before still run.
692
772
 
693
773
  - **`connecta.batch` failures gained `errorDetails`** (`S7`). They carried only a
694
774
  message, which left a program unable to tell a policy refusal from a transient
695
- failure. Additive, and it reuses `batch_call`'s field names so one shape covers
696
- both surfaces.
775
+ failure. Additive, and it reuses the host's internal batch field names, so a
776
+ program and the host describe a failed call the same way.
697
777
  - **A policy refusal can no longer look retryable** (`E7`). Pinned in code rather
698
778
  than read out of message text, so a connector named `svc-503` stops flipping a
699
779
  permanent refusal to `retryable: true`. This reaches the call tools too.
@@ -710,9 +790,12 @@ The middle three were places where the contract described behavior the code did
710
790
  not quite have. The code moved, because the described behavior is the one worth
711
791
  having.
712
792
 
713
- One surface was added since: [emitted output](#emitted-output) (`M1`–`M10`,
714
- [#270](https://github.com/zackbart/connecta/issues/270)) additive by
715
- construction, with the byte-for-byte no-emit promise pinned by test.
793
+ Two surfaces were added since, both additive by construction and each with its
794
+ byte-for-byte no-call promise pinned by test:
795
+ [emitted output](#emitted-output) (`M1`–`M10`,
796
+ [#270](https://github.com/zackbart/connecta/issues/270)) and
797
+ [rendered output](#rendered-output) (`U1`–`U11`,
798
+ [#277](https://github.com/zackbart/connecta/issues/277)).
716
799
 
717
800
  ## Verification
718
801
 
@@ -746,7 +829,7 @@ the upstream `Executor` shape assignable.
746
829
  | `E2`, `E8` | `test/guest-api-contract.test.ts` (code → `retryable`, batch and uncaught validation recovery), `test/meta-tools.test.ts` (direct, destructive, batch, provider fallback), `test/validate.test.ts` (bounded payload-free findings), `test/errors.test.ts` |
747
830
  | `E3` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (`auth_required`) |
748
831
  | `E4` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (destructive) |
749
- | `E5` | `test/guest-api-contract.test.ts` (execution-failure channel, in-flight `cancelled`), `test/execute.test.ts` (admission), `test/executor-admission.test.ts` |
832
+ | `E5` | `test/guest-api-contract.test.ts` (execution-failure channel, in-flight `cancelled`), `test/execute.test.ts` (admission), `test/executor-admission.test.ts`, `test/quickjs-executor.test.ts` (mid-run shutdown) |
750
833
  | `E6`, `X8` | `test/guest-api-contract.test.ts` (unknown and inherited members, wrapped-message precedence), `test/quickjs-executor.test.ts` |
751
834
  | `E7` | `test/guest-api-contract.test.ts` (refusals about a `503`-named connector), `test/errors.test.ts` |
752
835
  | `R1`, `R3` | `test/guest-api-contract.test.ts` (pass-through, truncation is success) |
@@ -766,22 +849,28 @@ the upstream `Executor` shape assignable.
766
849
  | `V1`–`V4` | `test/guest-api-contract.test.ts` (dispatched calls, every refusal class including an address no connector owns, the friction each derives, no event for the execution itself), `test/activity.test.ts` (the shared code → friction table, and the identity clamp) |
767
850
  | `M1` | `test/guest-api-contract.test.ts` (invalid emits throw catchably, accept nothing), `test/execute-emit.test.ts` (every rejected shape) |
768
851
  | `M2`, `M3` | `test/guest-api-contract.test.ts` (delivery order, truncated return plus delivered blocks), `test/execute-emit.test.ts` (envelope, `structuredContent`, byte-for-byte no-emit path) |
769
- | `M4` | `test/guest-api-contract.test.ts` (discard is visible), `test/execute-emit.test.ts` (structured and plain paths) |
852
+ | `M4` | `test/guest-api-contract.test.ts` (discard is visible), `test/execute-emit.test.ts` (structured and plain paths), `test/quickjs-executor.test.ts` (mid-run shutdown) |
770
853
  | `M5`, `M7` | `test/execute-emit.test.ts` (both budgets fail the crossing block; host-call budget untouched) |
771
854
  | `M6`, `M9` | verdicts; `M1`'s strict typing and `M2`'s collect-then-deliver are their enforcement |
772
855
  | `M8` | two arms passing one case table, `test/codemode-compat.test.ts` |
773
856
  | `M10` | `test/execute-emit.test.ts` (aggregate present, numbers only, absent when nothing emitted) |
857
+ | `U1`, `U2` | `test/guest-api-contract.test.ts` (invalid and repeated calls throw catchably, first payload stands), `test/execute-ui.test.ts` (every rejected shape) |
858
+ | `U3` | `test/guest-api-contract.test.ts` (`_meta` payload and `ui: true`, identical on both executors), `test/execute-ui.test.ts` (`structuredContent`, byte-for-byte no-call path, discard structured and plain, coexistence with `emittedDiscarded`), `test/quickjs-executor.test.ts` (mid-run shutdown) |
859
+ | `U4` | `test/execute-ui.test.ts` (one shared byte aggregate crossed in either order; block count and host-call budget untouched) |
860
+ | `U5`, `U10`, `U11` | `test/server.test.ts` (the shell URI, mimeType, and body; every other URI fails; empty listing; `execute_code`'s `_meta.ui`; exactly one declared extension) |
861
+ | `U6` | `test/execute-ui.test.ts` (valid HTML5, `srcdoc` and sandbox attributes, no `allow-same-origin`, no path from the inner frame to the host) |
862
+ | `U7`, `U8` | two arms passing one case table, `test/codemode-compat.test.ts` |
863
+ | `U9` | `test/execute-ui.test.ts` (a `ui` byte aggregate distinct from `emitted`, absent when nothing was accepted) |
774
864
  | `X3` | `test/quickjs-executor.test.ts` (cancels a running child) |
775
865
  | `X4` | `test/guest-api-contract.test.ts` (string logs only) |
776
866
  | `X6` | `test/quickjs-executor.test.ts` (never-settling await) |
777
867
  | `X7` | `P3`'s tests; the Workers superset is deliberately unused |
778
868
 
779
- The surface itself is checked by `test/server.test.ts` (the exact seven, nine, and
780
- ten tool lists) and `test/code-first-surface.test.ts` (the fold's construction
781
- rules, refusals, copy, and measured size). The release audit compares the same
782
- two shapes:
869
+ The surface itself is checked by `test/server.test.ts` (the exact seven-tool
870
+ list) and `test/code-first-surface.test.ts` (the fold's construction rules, the
871
+ required executor, the refusals a removed top-level tool now gets, copy, and
872
+ measured size). There is one shape left to audit, so there is one audit:
783
873
 
784
874
  ```sh
785
875
  npm --prefix eval/current-version run audit
786
- npm --prefix eval/current-version run audit -- --executor disabled
787
876
  ```
@@ -33,7 +33,7 @@ Connecta deliberately sits between protocol generations
33
33
  [#206](https://github.com/zackbart/connecta/issues/206).
34
34
  - **Multi-round-trip results:** a downstream `input_required` result becomes a
35
35
  non-retryable `input_required_unsupported` failure. `call_tool`, the
36
- `execute_code` host bridge, and classic's `batch_call` all preserve the
36
+ `execute_code` host bridge and internal batch path both preserve the
37
37
  structured code. Relaying the
38
38
  opaque `requestState` is architecturally possible but gated until real hosts
39
39
  and downstreams adopt it.
@@ -17,7 +17,7 @@ deliberately gated. The migration is tracked in
17
17
  | 8 | `ttlMs` and `cacheScope` on cacheable lists | adopt | `tools/list` returns `ttlMs: 3_600_000` and `cacheScope: "private"`. |
18
18
  | 9 | Honor downstream list cache hints | gated | Keep the fixed five-minute TTL plus fingerprint until refresh-churn evidence warrants complexity ([#206](https://github.com/zackbart/connecta/issues/206)). |
19
19
  | 10 | Native Tasks extension | refuse | Tasks address duration, while `get_result` addresses response size. Polling plus paging would add round trips without replacing the stash. |
20
- | 11 | Extensions capability framework | decline | No client consumes a Connecta extension declaration. |
20
+ | 11 | Extensions capability framework | decline | Decline as a general surface. The one extension Connecta declares is `io.modelcontextprotocol/ui`, which the MCP Apps extension requires before a host will use the program-UI shell template at all ([#266](https://github.com/zackbart/connecta/issues/266)). |
21
21
  | 12 | `Mcp-Method` and `Mcp-Name` POST headers | adopt | SDK v2 handles the headers; CORS allows `mcp-method, mcp-name`. |
22
22
  | 13 | RFC 9207 `iss` validation and `application_type` | adopt via SDK | The callback preserves all query parameters for SDK validation. |
23
23
  | 14 | Credentials keyed to issuer; re-register when AS changes | adopt | Version-2 credential envelopes store issuer; mismatch advances the generation epoch and invalidates registration and tokens. |