@jini-ai/agentic 0.1.1 → 0.3.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 (176) hide show
  1. package/README.md +92 -0
  2. package/dist/a2ui/agent-to-renderer.d.ts +36 -2
  3. package/dist/a2ui/agent-to-renderer.d.ts.map +1 -1
  4. package/dist/a2ui/agent-to-renderer.js +23 -1
  5. package/dist/a2ui/agent-to-renderer.js.map +1 -1
  6. package/dist/a2ui/interpreter.d.ts +24 -1
  7. package/dist/a2ui/interpreter.d.ts.map +1 -1
  8. package/dist/a2ui/interpreter.js +115 -65
  9. package/dist/a2ui/interpreter.js.map +1 -1
  10. package/dist/a2ui/json-pointer.d.ts.map +1 -1
  11. package/dist/a2ui/json-pointer.js +28 -3
  12. package/dist/a2ui/json-pointer.js.map +1 -1
  13. package/dist/a2ui/renderer-to-agent.d.ts +35 -11
  14. package/dist/a2ui/renderer-to-agent.d.ts.map +1 -1
  15. package/dist/a2ui/renderer-to-agent.js +15 -2
  16. package/dist/a2ui/renderer-to-agent.js.map +1 -1
  17. package/dist/a2ui/resolve.d.ts +1 -1
  18. package/dist/a2ui/resolve.d.ts.map +1 -1
  19. package/dist/a2ui/resolve.js +29 -3
  20. package/dist/a2ui/resolve.js.map +1 -1
  21. package/dist/a2ui/tree.d.ts +27 -2
  22. package/dist/a2ui/tree.d.ts.map +1 -1
  23. package/dist/a2ui/tree.js +48 -9
  24. package/dist/a2ui/tree.js.map +1 -1
  25. package/dist/ag-ui.d.ts.map +1 -1
  26. package/dist/ag-ui.js +30 -1
  27. package/dist/ag-ui.js.map +1 -1
  28. package/dist/core/a2ui/agent-to-renderer.d.ts +613 -0
  29. package/dist/core/a2ui/agent-to-renderer.d.ts.map +1 -0
  30. package/dist/core/a2ui/agent-to-renderer.js +191 -0
  31. package/dist/core/a2ui/agent-to-renderer.js.map +1 -0
  32. package/dist/core/a2ui/catalog.d.ts +73 -0
  33. package/dist/core/a2ui/catalog.d.ts.map +1 -0
  34. package/dist/core/a2ui/catalog.js +304 -0
  35. package/dist/core/a2ui/catalog.js.map +1 -0
  36. package/dist/core/a2ui/common-types.d.ts +401 -0
  37. package/dist/core/a2ui/common-types.d.ts.map +1 -0
  38. package/dist/core/a2ui/common-types.js +130 -0
  39. package/dist/core/a2ui/common-types.js.map +1 -0
  40. package/dist/core/a2ui/index.d.ts +16 -0
  41. package/dist/core/a2ui/index.d.ts.map +1 -0
  42. package/dist/core/a2ui/index.js +16 -0
  43. package/dist/core/a2ui/index.js.map +1 -0
  44. package/dist/core/a2ui/interpreter.d.ts +71 -0
  45. package/dist/core/a2ui/interpreter.d.ts.map +1 -0
  46. package/dist/core/a2ui/interpreter.js +341 -0
  47. package/dist/core/a2ui/interpreter.js.map +1 -0
  48. package/dist/core/a2ui/json-pointer.d.ts +48 -0
  49. package/dist/core/a2ui/json-pointer.d.ts.map +1 -0
  50. package/dist/core/a2ui/json-pointer.js +174 -0
  51. package/dist/core/a2ui/json-pointer.js.map +1 -0
  52. package/dist/core/a2ui/renderer-to-agent.d.ts +342 -0
  53. package/dist/core/a2ui/renderer-to-agent.d.ts.map +1 -0
  54. package/dist/core/a2ui/renderer-to-agent.js +111 -0
  55. package/dist/core/a2ui/renderer-to-agent.js.map +1 -0
  56. package/dist/core/a2ui/resolve.d.ts +28 -0
  57. package/dist/core/a2ui/resolve.d.ts.map +1 -0
  58. package/dist/core/a2ui/resolve.js +144 -0
  59. package/dist/core/a2ui/resolve.js.map +1 -0
  60. package/dist/core/a2ui/tree.d.ts +66 -0
  61. package/dist/core/a2ui/tree.d.ts.map +1 -0
  62. package/dist/core/a2ui/tree.js +74 -0
  63. package/dist/core/a2ui/tree.js.map +1 -0
  64. package/dist/core/ag-ui.d.ts +82 -0
  65. package/dist/core/ag-ui.d.ts.map +1 -0
  66. package/dist/core/ag-ui.js +85 -0
  67. package/dist/core/ag-ui.js.map +1 -0
  68. package/dist/core/capability.d.ts +81 -0
  69. package/dist/core/capability.d.ts.map +1 -0
  70. package/dist/core/capability.js +79 -0
  71. package/dist/core/capability.js.map +1 -0
  72. package/dist/core/dom/dom-page-driver.d.ts +36 -0
  73. package/dist/core/dom/dom-page-driver.d.ts.map +1 -0
  74. package/dist/core/dom/dom-page-driver.js +601 -0
  75. package/dist/core/dom/dom-page-driver.js.map +1 -0
  76. package/dist/core/dom/index.d.ts +17 -0
  77. package/dist/core/dom/index.d.ts.map +1 -0
  78. package/dist/core/dom/index.js +17 -0
  79. package/dist/core/dom/index.js.map +1 -0
  80. package/dist/core/dom/model-context.d.ts +69 -0
  81. package/dist/core/dom/model-context.d.ts.map +1 -0
  82. package/dist/core/dom/model-context.js +44 -0
  83. package/dist/core/dom/model-context.js.map +1 -0
  84. package/dist/core/element-handles.d.ts +120 -0
  85. package/dist/core/element-handles.d.ts.map +1 -0
  86. package/dist/core/element-handles.js +39 -0
  87. package/dist/core/element-handles.js.map +1 -0
  88. package/dist/core/gen-ui/encoder.d.ts +50 -0
  89. package/dist/core/gen-ui/encoder.d.ts.map +1 -0
  90. package/dist/core/gen-ui/encoder.js +97 -0
  91. package/dist/core/gen-ui/encoder.js.map +1 -0
  92. package/dist/core/gen-ui/events.d.ts +59 -0
  93. package/dist/core/gen-ui/events.d.ts.map +1 -0
  94. package/dist/core/gen-ui/events.js +15 -0
  95. package/dist/core/gen-ui/events.js.map +1 -0
  96. package/dist/core/gen-ui/index.d.ts +18 -0
  97. package/dist/core/gen-ui/index.d.ts.map +1 -0
  98. package/dist/core/gen-ui/index.js +17 -0
  99. package/dist/core/gen-ui/index.js.map +1 -0
  100. package/dist/core/guards.d.ts +96 -0
  101. package/dist/core/guards.d.ts.map +1 -0
  102. package/dist/core/guards.js +186 -0
  103. package/dist/core/guards.js.map +1 -0
  104. package/dist/core/handle.d.ts +41 -0
  105. package/dist/core/handle.d.ts.map +1 -0
  106. package/dist/core/handle.js +41 -0
  107. package/dist/core/handle.js.map +1 -0
  108. package/dist/core/index.d.ts +75 -0
  109. package/dist/core/index.d.ts.map +1 -0
  110. package/dist/core/index.js +74 -0
  111. package/dist/core/index.js.map +1 -0
  112. package/dist/core/list-handles.d.ts +43 -0
  113. package/dist/core/list-handles.d.ts.map +1 -0
  114. package/dist/core/list-handles.js +57 -0
  115. package/dist/core/list-handles.js.map +1 -0
  116. package/dist/core/mcp-ui-apps.d.ts +223 -0
  117. package/dist/core/mcp-ui-apps.d.ts.map +1 -0
  118. package/dist/core/mcp-ui-apps.js +252 -0
  119. package/dist/core/mcp-ui-apps.js.map +1 -0
  120. package/dist/core/page-capabilities.d.ts +14 -0
  121. package/dist/core/page-capabilities.d.ts.map +1 -0
  122. package/dist/core/page-capabilities.js +129 -0
  123. package/dist/core/page-capabilities.js.map +1 -0
  124. package/dist/core/page-driver.d.ts +120 -0
  125. package/dist/core/page-driver.d.ts.map +1 -0
  126. package/dist/core/page-driver.js +2 -0
  127. package/dist/core/page-driver.js.map +1 -0
  128. package/dist/core/page-executor.d.ts +94 -0
  129. package/dist/core/page-executor.d.ts.map +1 -0
  130. package/dist/core/page-executor.js +320 -0
  131. package/dist/core/page-executor.js.map +1 -0
  132. package/dist/core/webmcp.d.ts +202 -0
  133. package/dist/core/webmcp.d.ts.map +1 -0
  134. package/dist/core/webmcp.js +173 -0
  135. package/dist/core/webmcp.js.map +1 -0
  136. package/dist/dom/dom-page-driver.d.ts +9 -2
  137. package/dist/dom/dom-page-driver.d.ts.map +1 -1
  138. package/dist/dom/dom-page-driver.js +84 -40
  139. package/dist/dom/dom-page-driver.js.map +1 -1
  140. package/dist/dom/index.d.ts +1 -1
  141. package/dist/dom/index.d.ts.map +1 -1
  142. package/dist/dom/index.js +1 -1
  143. package/dist/dom/index.js.map +1 -1
  144. package/dist/element-handles.d.ts +22 -1
  145. package/dist/element-handles.d.ts.map +1 -1
  146. package/dist/gen-ui/encoder.d.ts +8 -8
  147. package/dist/gen-ui/encoder.d.ts.map +1 -1
  148. package/dist/gen-ui/encoder.js +2 -2
  149. package/dist/gen-ui/encoder.js.map +1 -1
  150. package/dist/gen-ui/events.d.ts +10 -10
  151. package/dist/gen-ui/events.d.ts.map +1 -1
  152. package/dist/gen-ui/index.d.ts +3 -3
  153. package/dist/gen-ui/index.d.ts.map +1 -1
  154. package/dist/gen-ui/index.js +2 -2
  155. package/dist/gen-ui/index.js.map +1 -1
  156. package/dist/guards.d.ts +8 -3
  157. package/dist/guards.d.ts.map +1 -1
  158. package/dist/guards.js +6 -1
  159. package/dist/guards.js.map +1 -1
  160. package/dist/index.d.ts +4 -62
  161. package/dist/index.d.ts.map +1 -1
  162. package/dist/index.js +4 -61
  163. package/dist/index.js.map +1 -1
  164. package/dist/mcp-ui-apps.d.ts +19 -0
  165. package/dist/mcp-ui-apps.d.ts.map +1 -1
  166. package/dist/mcp-ui-apps.js +50 -5
  167. package/dist/mcp-ui-apps.js.map +1 -1
  168. package/dist/page-capabilities.js +6 -6
  169. package/dist/page-capabilities.js.map +1 -1
  170. package/dist/page-driver.d.ts +15 -2
  171. package/dist/page-driver.d.ts.map +1 -1
  172. package/dist/page-executor.d.ts +11 -4
  173. package/dist/page-executor.d.ts.map +1 -1
  174. package/dist/page-executor.js +47 -15
  175. package/dist/page-executor.js.map +1 -1
  176. package/package.json +18 -9
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @module list-handles
3
+ *
4
+ * How a host turns one namespace prefix (its own `agentHandle` base, e.g. `"mcp-server"`) plus a
5
+ * list of items' own stable ids into a distinct, stable base handle per item — the shape every
6
+ * repeated-row/repeated-card list needs, and that a per-host reimplementation risks getting
7
+ * subtly wrong (see {@link buildAgentListHandles}'s own doc for the exact failure mode).
8
+ *
9
+ * The core problem: a `data-agent-element` handle is `[a-z0-9]+(-[a-z0-9]+)*` only (see
10
+ * `element-handles.ts`), but the ids driving a real list (a form field's `id`, a content type's
11
+ * `key`, a database row's numeric id, a configured source's own id, ...) are arbitrary strings.
12
+ * Two different ids can also slugify to the SAME handle. Both are resolved here, once, so every
13
+ * list surface in every host derives its handles the same way instead of each re-deriving (and
14
+ * possibly getting wrong) the same two rules. Lives at this package's universal root — like
15
+ * `handle.ts` and `element-handles.ts` — because it is pure data with no DOM or framework
16
+ * involved, so any host (React, Vue, a server-rendered list) can use it identically.
17
+ */
18
+ /**
19
+ * Builds one distinct, stable base handle per id, positionally aligned with `ids`.
20
+ *
21
+ * Handles are derived from each id's own slug, not its position in the list — an agent reading
22
+ * `page.find_elements` should see `<prefix>-about-us`, not `<prefix>-3`, so the same control keeps
23
+ * the same handle even if rows are later reordered or filtered. An id with nothing sluggable left
24
+ * in it (e.g. `"***"`) falls back to its 1-based position instead, so it still produces a
25
+ * resolvable handle rather than an empty one.
26
+ *
27
+ * Uniqueness is enforced with a suffix SEARCH, not a single `-<index>` append: appending the index
28
+ * alone is not collision-proof (`["x", "x-3", "x"]` would give the third entry the fallback
29
+ * `<prefix>-x-3`, which the second entry already holds). A duplicate handle does not fail loudly —
30
+ * it makes `page.click`/`page.fill` silently resolve to whichever element the DOM reaches first —
31
+ * so this loop is the load-bearing part of the function, not a stylistic choice.
32
+ *
33
+ * @param prefix - The list's own handle namespace (e.g. `"mcp-server"`, `"form-field"`). Must
34
+ * already be a valid, non-empty handle segment — callers own that, same as every other
35
+ * `agentHandle()` base.
36
+ * @param ids - The list items' own stable ids, in the order they are rendered.
37
+ * @returns One base handle per id, positionally aligned with `ids`, all distinct.
38
+ * @complexity Time O(n) typical, O(n²) worst case when every id slugifies identically (the suffix
39
+ * search then walks the full used-set for each collision); n is a list's row/card count, which is
40
+ * operator- or user-authored content and stays small in practice. Space O(n).
41
+ */
42
+ export function buildAgentListHandles(prefix, ids) {
43
+ const used = new Set();
44
+ return ids.map((id, index) => {
45
+ const slug = id.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
46
+ const preferred = `${prefix}-${slug === '' ? index + 1 : slug}`;
47
+ let handle = preferred;
48
+ let suffix = 2;
49
+ while (used.has(handle)) {
50
+ handle = `${preferred}-${suffix}`;
51
+ suffix += 1;
52
+ }
53
+ used.add(handle);
54
+ return handle;
55
+ });
56
+ }
57
+ //# sourceMappingURL=list-handles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-handles.js","sourceRoot":"","sources":["../../src/core/list-handles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAc,EAAE,GAAsB;IAC1E,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE;QAC3B,MAAM,IAAI,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;QAClF,MAAM,SAAS,GAAG,GAAG,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAChE,IAAI,MAAM,GAAG,SAAS,CAAC;QACvB,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACxB,MAAM,GAAG,GAAG,SAAS,IAAI,MAAM,EAAE,CAAC;YAClC,MAAM,IAAI,CAAC,CAAC;QACd,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACjB,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,223 @@
1
+ /**
2
+ * @module mcp-ui
3
+ *
4
+ * The MCP Apps (`mcp-ui`) envelope: JSON-RPC 2.0 over `postMessage` between a host and a
5
+ * sandboxed iframe View.
6
+ *
7
+ * MCP Apps became the first official MCP extension (SEP-1865) on 2026-01-26. Jini borrows its
8
+ * **envelope and lifecycle** rather than inventing a message format, because the hard parts are
9
+ * already settled there: request/response correlation by `id`, and the ordering rule that a host
10
+ * MUST NOT send any request or notification to a View before receiving `initialized` — which is
11
+ * the fix for the "posted before the iframe was listening" race.
12
+ *
13
+ * Re-verified 2026-07-28 against the primary source (`github.com/modelcontextprotocol/ext-apps`,
14
+ * both `specification/2026-01-26/apps.mdx` [Stable] and `specification/draft/apps.mdx`) after an
15
+ * audit found the bucket below had the wrong direction for two lifecycle messages and mis-typed a
16
+ * third as fire-and-forget when the spec defines it as a request needing a response:
17
+ *
18
+ * - `ui/notifications/initialized` and `ui/notifications/size-changed` are **View→Host** (the
19
+ * sequence diagram is unambiguous: `UI ->> H: ui/notifications/initialized`, and the "Host
20
+ * Behavior" prose for size reads "hosts MUST **listen for** ... notifications **from the
21
+ * View**"). They were previously bucketed under `MCP_UI_HOST_NOTIFICATIONS`, i.e. backwards —
22
+ * now under {@link MCP_UI_VIEW_NOTIFICATIONS}.
23
+ * - `ui/resource-teardown` (Host→View) carries an `id` and has success/error response shapes in
24
+ * the spec's own wire examples, and the prose is explicit: "Host SHOULD wait for a response
25
+ * before tearing down the resource (to prevent data loss)." That is a request, not a
26
+ * notification — moved to {@link MCP_UI_HOST_REQUESTS}.
27
+ *
28
+ * The draft spec (not yet Stable, but already fixing the above and adding surface this module
29
+ * now also models) adds: `ui/notifications/request-teardown` (View→Host, the View asking to be
30
+ * torn down), `ui/download-file` and `sampling/createMessage` (View→Host requests), and the
31
+ * Host→App direction of `tools/call`/`tools/list` for Apps that register their own tools (the
32
+ * "App-Provided Tools" section, declared via `appCapabilities.tools` in `ui/initialize`).
33
+ *
34
+ * Two deliberate divergences from the spec, both load-bearing:
35
+ *
36
+ * 1. **Direction.** MCP Apps is primarily View→Host: the embedded UI calls tools. Host→View is a
37
+ * *fixed* lifecycle set with no generic "host asks the View to do something" (the App-tools
38
+ * addition above is the one exception, and it is opt-in and capability-gated). Jini's page
39
+ * verbs therefore ride as an explicitly-namespaced extension ({@link JINI_PAGE_ACTION_METHOD})
40
+ * — ours, not the spec's, and named so no one mistakes it.
41
+ * 2. **Sandbox.** The spec mandates `sandbox="allow-scripts allow-same-origin"`, which is safe
42
+ * *there* because the View is served from a separate origin behind a sandbox proxy. A host
43
+ * serving preview content from its own origin must NOT copy that line: `allow-same-origin`
44
+ * would hand the embedded document access to the host's origin. See
45
+ * {@link MCP_UI_SANDBOX_NOTE}.
46
+ *
47
+ * No transport here — this package touches no browser globals. These are pure builders and
48
+ * parsers; the binding that owns the iframe does the posting.
49
+ */
50
+ /** Requests the View may send the Host. From the 2026-01-26 [Stable] spec plus the draft's additions (marked below). */
51
+ export declare const MCP_UI_VIEW_METHODS: {
52
+ readonly initialize: "ui/initialize";
53
+ /** View→Host: call a server tool via the Host's proxy (distinct from {@link MCP_UI_HOST_REQUESTS.callAppTool}, the reverse direction). */
54
+ readonly callTool: "tools/call";
55
+ readonly readResource: "resources/read";
56
+ readonly log: "notifications/message";
57
+ readonly openLink: "ui/open-link";
58
+ readonly sendMessage: "ui/message";
59
+ readonly requestDisplayMode: "ui/request-display-mode";
60
+ readonly updateModelContext: "ui/update-model-context";
61
+ /** Draft addition. Host-mediated file download from a sandboxed iframe that cannot use `allow-downloads`. */
62
+ readonly downloadFile: "ui/download-file";
63
+ /** Draft addition. Request an LLM completion from the Host; gated behind `hostCapabilities.sampling`. */
64
+ readonly createMessage: "sampling/createMessage";
65
+ readonly ping: "ping";
66
+ };
67
+ /**
68
+ * Notifications the Host may send the View — fire-and-forget, no response expected or allowed.
69
+ * `initialized`/`size-changed` are NOT here: both are sent BY the View (see
70
+ * {@link MCP_UI_VIEW_NOTIFICATIONS}), and `teardown` is NOT here either: it is a request the Host
71
+ * sends TO the View expecting a response (see {@link MCP_UI_HOST_REQUESTS}).
72
+ */
73
+ export declare const MCP_UI_HOST_NOTIFICATIONS: {
74
+ readonly toolInputPartial: "ui/notifications/tool-input-partial";
75
+ readonly toolInput: "ui/notifications/tool-input";
76
+ readonly toolResult: "ui/notifications/tool-result";
77
+ readonly toolCancelled: "ui/notifications/tool-cancelled";
78
+ readonly hostContextChanged: "ui/notifications/host-context-changed";
79
+ };
80
+ /**
81
+ * Notifications the View may send the Host — fire-and-forget, no response expected or allowed.
82
+ * The spec's own "Notifications (Host → View)" heading in the 2026-01-26 text is misleading for
83
+ * two of these (see the module doc's audit note); the draft spec corrects this by giving these
84
+ * two, plus its own new addition, an explicit "Notifications (View → Host)" heading.
85
+ */
86
+ export declare const MCP_UI_VIEW_NOTIFICATIONS: {
87
+ /** The View→Host handshake completion notification. Host MUST NOT send anything to the View before this arrives. */
88
+ readonly initialized: "ui/notifications/initialized";
89
+ /** The View SHOULD send this "when rendered content body size changes." */
90
+ readonly sizeChanged: "ui/notifications/size-changed";
91
+ /** Draft addition. The View asking to be torn down (e.g. a "Done" button); the Host MAY defer or ignore it, but if it accepts, it still owes the View {@link MCP_UI_HOST_REQUESTS.teardown}. */
92
+ readonly requestTeardown: "ui/notifications/request-teardown";
93
+ };
94
+ /**
95
+ * Requests the Host may send the View, needing a response. Distinct from
96
+ * {@link MCP_UI_HOST_NOTIFICATIONS} because a caller building a JSON-RPC envelope for one of
97
+ * these must attach an `id` and correlate the reply — using {@link createJsonRpcNotification}
98
+ * here would silently produce a message the View has no `id` to answer, and a Host that then
99
+ * "waits for a response" (the spec's own words) would wait forever.
100
+ */
101
+ export declare const MCP_UI_HOST_REQUESTS: {
102
+ /**
103
+ * Host MUST send this before tearing down the UI resource, for any reason. Per spec: "Host
104
+ * SHOULD wait for a response before tearing down the resource (to prevent data loss)." — this
105
+ * is the message the bug report flagged: bucketing it as a fire-and-forget notification means a
106
+ * Host never learns whether the View acknowledged before disappearing.
107
+ */
108
+ readonly teardown: "ui/resource-teardown";
109
+ /** Draft addition ("App-Provided Tools"). Host→App: execute a tool the App registered via `appCapabilities.tools`. */
110
+ readonly callAppTool: "tools/call";
111
+ /** Draft addition. Host→App: list the App's registered tools. */
112
+ readonly listAppTools: "tools/list";
113
+ };
114
+ /**
115
+ * Jini's page-action extension. **Not part of MCP Apps** — the namespace is explicit so it can
116
+ * never be mistaken for a spec method, and so a compliant host that does not understand it
117
+ * rejects it as unknown rather than silently mis-handling it.
118
+ */
119
+ export declare const JINI_PAGE_ACTION_METHOD = "x-jini/page-action";
120
+ /**
121
+ * Why a host serving preview content from its own origin must not copy the spec's sandbox line.
122
+ * Kept as an exported string so the reason travels with the code that would otherwise be
123
+ * cargo-culted.
124
+ */
125
+ export declare const MCP_UI_SANDBOX_NOTE: string;
126
+ export interface JsonRpcRequest {
127
+ readonly jsonrpc: '2.0';
128
+ readonly id: number | string;
129
+ readonly method: string;
130
+ readonly params?: Record<string, unknown>;
131
+ }
132
+ export interface JsonRpcNotification {
133
+ readonly jsonrpc: '2.0';
134
+ readonly method: string;
135
+ readonly params?: Record<string, unknown>;
136
+ }
137
+ export interface JsonRpcError {
138
+ readonly code: number;
139
+ readonly message: string;
140
+ readonly data?: unknown;
141
+ }
142
+ export interface JsonRpcResponse {
143
+ readonly jsonrpc: '2.0';
144
+ readonly id: number | string;
145
+ readonly result?: unknown;
146
+ readonly error?: JsonRpcError;
147
+ }
148
+ export type JsonRpcMessage = JsonRpcRequest | JsonRpcNotification | JsonRpcResponse;
149
+ /** JSON-RPC 2.0 reserved codes, used so a View's failures read the same as any other client's. */
150
+ export declare const JSON_RPC_ERROR_CODES: {
151
+ readonly parseError: -32700;
152
+ readonly invalidRequest: -32600;
153
+ readonly methodNotFound: -32601;
154
+ readonly invalidParams: -32602;
155
+ readonly internalError: -32603;
156
+ };
157
+ /**
158
+ * Whether an arbitrary value is a JSON-RPC 2.0 message.
159
+ *
160
+ * Messages arriving over `postMessage` are attacker-influenced input — any page able to reach the
161
+ * frame can post anything. Validate before dispatch; never trust the shape.
162
+ *
163
+ * Found by live adversarial testing against a real sandboxed iframe (2026-07-28), NOT by static
164
+ * review: a request whose `method` is a valid string but whose `id` is present and malformed
165
+ * (e.g. an object, `{ jsonrpc: '2.0', id: { nested: true }, method: 'tools/call' }`) used to pass
166
+ * this check — the `typeof value['method'] === 'string'` branch returned `true` unconditionally,
167
+ * without ever looking at `id`'s type. A Host trusting that then had to build a JSON-RPC response
168
+ * carrying a non-spec `id` back at the View, which the View's own correlation map (keyed by
169
+ * string ids) could never match — not a crash, but a real protocol violation this function exists
170
+ * specifically to catch. Now: if `id` is present at all, its type is checked before anything else,
171
+ * for every message shape (request, notification, or response) — a notification legitimately has
172
+ * no `id`, but a message that HAS one must have a valid one.
173
+ *
174
+ * The 2026-07-29 audit found the rest of that check was still far too generous, in three ways, all
175
+ * of them reachable from anything able to post at the frame:
176
+ *
177
+ * - **`params` went unread.** Any string `method` returned `true` immediately, so
178
+ * `{method: 'tools/call', params: 'nope'}` reached dispatch and a handler reading
179
+ * `params.capabilityId` got `undefined` rather than a refusal. §4.2 fixes the type: Array or
180
+ * Object.
181
+ * - **The four shapes were not kept apart.** JSON-RPC 2.0 defines request, notification, success
182
+ * response and error response as distinct, mutually exclusive objects. A message carrying both
183
+ * `method` and `result` passed as a request; one carrying both `result` and `error` passed as a
184
+ * response, which §5 forbids in as many words ("Either the result member or error member MUST be
185
+ * included, but both members MUST NOT be included").
186
+ * - **`error` was accepted as any value at all**, `error: "boom"` included, so a host formatting
187
+ * `error.message` back to a user read a property off a string.
188
+ *
189
+ * A message whose `method` is present but not a string is rejected outright rather than falling
190
+ * through to the response branch — reinterpreting a malformed request as a response is how one
191
+ * bad message becomes two wrong behaviors.
192
+ *
193
+ * @param value - The raw `event.data`.
194
+ * @returns True when the value is a well-formed JSON-RPC message.
195
+ */
196
+ export declare function isJsonRpcMessage(value: unknown): value is JsonRpcMessage;
197
+ /** Whether a validated message expects a response (as opposed to being a notification). */
198
+ export declare function isJsonRpcRequest(message: JsonRpcMessage): message is JsonRpcRequest;
199
+ /**
200
+ * Builds a request.
201
+ *
202
+ * @param id - Correlation id, unique per in-flight request. Doubles as the idempotency key: a
203
+ * transport that redelivers (an SSE reconnect, a repeated post) must not execute twice.
204
+ * @param method - Method name.
205
+ * @param params - Optional parameters.
206
+ */
207
+ export declare function createJsonRpcRequest(id: number | string, method: string, params?: Record<string, unknown>): JsonRpcRequest;
208
+ /** Builds a notification — no `id`, so no response is expected or allowed. */
209
+ export declare function createJsonRpcNotification(method: string, params?: Record<string, unknown>): JsonRpcNotification;
210
+ /** Builds a success response for `id`. */
211
+ export declare function createJsonRpcResult(id: number | string, result: unknown): JsonRpcResponse;
212
+ /** Builds an error response for `id`. */
213
+ export declare function createJsonRpcError(id: number | string, code: number, message: string, data?: unknown): JsonRpcResponse;
214
+ /**
215
+ * Builds a Jini page-action request.
216
+ *
217
+ * @param id - Correlation/idempotency id.
218
+ * @param capabilityId - A `page.*` capability id.
219
+ * @param input - Capability arguments.
220
+ * @returns The namespaced extension request.
221
+ */
222
+ export declare function createPageActionRequest(id: number | string, capabilityId: string, input: Record<string, unknown>): JsonRpcRequest;
223
+ //# sourceMappingURL=mcp-ui-apps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-ui-apps.d.ts","sourceRoot":"","sources":["../../src/core/mcp-ui-apps.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,252 @@
1
+ /**
2
+ * @module mcp-ui
3
+ *
4
+ * The MCP Apps (`mcp-ui`) envelope: JSON-RPC 2.0 over `postMessage` between a host and a
5
+ * sandboxed iframe View.
6
+ *
7
+ * MCP Apps became the first official MCP extension (SEP-1865) on 2026-01-26. Jini borrows its
8
+ * **envelope and lifecycle** rather than inventing a message format, because the hard parts are
9
+ * already settled there: request/response correlation by `id`, and the ordering rule that a host
10
+ * MUST NOT send any request or notification to a View before receiving `initialized` — which is
11
+ * the fix for the "posted before the iframe was listening" race.
12
+ *
13
+ * Re-verified 2026-07-28 against the primary source (`github.com/modelcontextprotocol/ext-apps`,
14
+ * both `specification/2026-01-26/apps.mdx` [Stable] and `specification/draft/apps.mdx`) after an
15
+ * audit found the bucket below had the wrong direction for two lifecycle messages and mis-typed a
16
+ * third as fire-and-forget when the spec defines it as a request needing a response:
17
+ *
18
+ * - `ui/notifications/initialized` and `ui/notifications/size-changed` are **View→Host** (the
19
+ * sequence diagram is unambiguous: `UI ->> H: ui/notifications/initialized`, and the "Host
20
+ * Behavior" prose for size reads "hosts MUST **listen for** ... notifications **from the
21
+ * View**"). They were previously bucketed under `MCP_UI_HOST_NOTIFICATIONS`, i.e. backwards —
22
+ * now under {@link MCP_UI_VIEW_NOTIFICATIONS}.
23
+ * - `ui/resource-teardown` (Host→View) carries an `id` and has success/error response shapes in
24
+ * the spec's own wire examples, and the prose is explicit: "Host SHOULD wait for a response
25
+ * before tearing down the resource (to prevent data loss)." That is a request, not a
26
+ * notification — moved to {@link MCP_UI_HOST_REQUESTS}.
27
+ *
28
+ * The draft spec (not yet Stable, but already fixing the above and adding surface this module
29
+ * now also models) adds: `ui/notifications/request-teardown` (View→Host, the View asking to be
30
+ * torn down), `ui/download-file` and `sampling/createMessage` (View→Host requests), and the
31
+ * Host→App direction of `tools/call`/`tools/list` for Apps that register their own tools (the
32
+ * "App-Provided Tools" section, declared via `appCapabilities.tools` in `ui/initialize`).
33
+ *
34
+ * Two deliberate divergences from the spec, both load-bearing:
35
+ *
36
+ * 1. **Direction.** MCP Apps is primarily View→Host: the embedded UI calls tools. Host→View is a
37
+ * *fixed* lifecycle set with no generic "host asks the View to do something" (the App-tools
38
+ * addition above is the one exception, and it is opt-in and capability-gated). Jini's page
39
+ * verbs therefore ride as an explicitly-namespaced extension ({@link JINI_PAGE_ACTION_METHOD})
40
+ * — ours, not the spec's, and named so no one mistakes it.
41
+ * 2. **Sandbox.** The spec mandates `sandbox="allow-scripts allow-same-origin"`, which is safe
42
+ * *there* because the View is served from a separate origin behind a sandbox proxy. A host
43
+ * serving preview content from its own origin must NOT copy that line: `allow-same-origin`
44
+ * would hand the embedded document access to the host's origin. See
45
+ * {@link MCP_UI_SANDBOX_NOTE}.
46
+ *
47
+ * No transport here — this package touches no browser globals. These are pure builders and
48
+ * parsers; the binding that owns the iframe does the posting.
49
+ */
50
+ /** Requests the View may send the Host. From the 2026-01-26 [Stable] spec plus the draft's additions (marked below). */
51
+ export const MCP_UI_VIEW_METHODS = {
52
+ initialize: 'ui/initialize',
53
+ /** View→Host: call a server tool via the Host's proxy (distinct from {@link MCP_UI_HOST_REQUESTS.callAppTool}, the reverse direction). */
54
+ callTool: 'tools/call',
55
+ readResource: 'resources/read',
56
+ log: 'notifications/message',
57
+ openLink: 'ui/open-link',
58
+ sendMessage: 'ui/message',
59
+ requestDisplayMode: 'ui/request-display-mode',
60
+ updateModelContext: 'ui/update-model-context',
61
+ /** Draft addition. Host-mediated file download from a sandboxed iframe that cannot use `allow-downloads`. */
62
+ downloadFile: 'ui/download-file',
63
+ /** Draft addition. Request an LLM completion from the Host; gated behind `hostCapabilities.sampling`. */
64
+ createMessage: 'sampling/createMessage',
65
+ ping: 'ping',
66
+ };
67
+ /**
68
+ * Notifications the Host may send the View — fire-and-forget, no response expected or allowed.
69
+ * `initialized`/`size-changed` are NOT here: both are sent BY the View (see
70
+ * {@link MCP_UI_VIEW_NOTIFICATIONS}), and `teardown` is NOT here either: it is a request the Host
71
+ * sends TO the View expecting a response (see {@link MCP_UI_HOST_REQUESTS}).
72
+ */
73
+ export const MCP_UI_HOST_NOTIFICATIONS = {
74
+ toolInputPartial: 'ui/notifications/tool-input-partial',
75
+ toolInput: 'ui/notifications/tool-input',
76
+ toolResult: 'ui/notifications/tool-result',
77
+ toolCancelled: 'ui/notifications/tool-cancelled',
78
+ hostContextChanged: 'ui/notifications/host-context-changed',
79
+ };
80
+ /**
81
+ * Notifications the View may send the Host — fire-and-forget, no response expected or allowed.
82
+ * The spec's own "Notifications (Host → View)" heading in the 2026-01-26 text is misleading for
83
+ * two of these (see the module doc's audit note); the draft spec corrects this by giving these
84
+ * two, plus its own new addition, an explicit "Notifications (View → Host)" heading.
85
+ */
86
+ export const MCP_UI_VIEW_NOTIFICATIONS = {
87
+ /** The View→Host handshake completion notification. Host MUST NOT send anything to the View before this arrives. */
88
+ initialized: 'ui/notifications/initialized',
89
+ /** The View SHOULD send this "when rendered content body size changes." */
90
+ sizeChanged: 'ui/notifications/size-changed',
91
+ /** Draft addition. The View asking to be torn down (e.g. a "Done" button); the Host MAY defer or ignore it, but if it accepts, it still owes the View {@link MCP_UI_HOST_REQUESTS.teardown}. */
92
+ requestTeardown: 'ui/notifications/request-teardown',
93
+ };
94
+ /**
95
+ * Requests the Host may send the View, needing a response. Distinct from
96
+ * {@link MCP_UI_HOST_NOTIFICATIONS} because a caller building a JSON-RPC envelope for one of
97
+ * these must attach an `id` and correlate the reply — using {@link createJsonRpcNotification}
98
+ * here would silently produce a message the View has no `id` to answer, and a Host that then
99
+ * "waits for a response" (the spec's own words) would wait forever.
100
+ */
101
+ export const MCP_UI_HOST_REQUESTS = {
102
+ /**
103
+ * Host MUST send this before tearing down the UI resource, for any reason. Per spec: "Host
104
+ * SHOULD wait for a response before tearing down the resource (to prevent data loss)." — this
105
+ * is the message the bug report flagged: bucketing it as a fire-and-forget notification means a
106
+ * Host never learns whether the View acknowledged before disappearing.
107
+ */
108
+ teardown: 'ui/resource-teardown',
109
+ /** Draft addition ("App-Provided Tools"). Host→App: execute a tool the App registered via `appCapabilities.tools`. */
110
+ callAppTool: 'tools/call',
111
+ /** Draft addition. Host→App: list the App's registered tools. */
112
+ listAppTools: 'tools/list',
113
+ };
114
+ /**
115
+ * Jini's page-action extension. **Not part of MCP Apps** — the namespace is explicit so it can
116
+ * never be mistaken for a spec method, and so a compliant host that does not understand it
117
+ * rejects it as unknown rather than silently mis-handling it.
118
+ */
119
+ export const JINI_PAGE_ACTION_METHOD = 'x-jini/page-action';
120
+ /**
121
+ * Why a host serving preview content from its own origin must not copy the spec's sandbox line.
122
+ * Kept as an exported string so the reason travels with the code that would otherwise be
123
+ * cargo-culted.
124
+ */
125
+ export const MCP_UI_SANDBOX_NOTE = 'MCP Apps requires sandbox="allow-scripts allow-same-origin" because its Views are served from '
126
+ + 'a separate origin behind a sandbox proxy. When the embedded document is served from the '
127
+ + "host's own origin, allow-same-origin grants it access to the host — use allow-scripts alone.";
128
+ /** JSON-RPC 2.0 reserved codes, used so a View's failures read the same as any other client's. */
129
+ export const JSON_RPC_ERROR_CODES = {
130
+ parseError: -32700,
131
+ invalidRequest: -32600,
132
+ methodNotFound: -32601,
133
+ invalidParams: -32602,
134
+ internalError: -32603,
135
+ };
136
+ function isRecord(value) {
137
+ // Arrays excluded deliberately: `typeof [] === 'object'`, and an array carrying the right
138
+ // properties would otherwise pass as a message. An array IS meaningful JSON-RPC — it is a
139
+ // *batch* — but this transport does not send or accept batches, so one arriving is either a
140
+ // mistake or a probe, and either way is not the single message every caller here expects.
141
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
142
+ }
143
+ /** `params`, per §4.2, is "Array or Object" — a primitive there is not an under-specified call, it is a malformed one. */
144
+ function hasValidParams(value) {
145
+ if (!('params' in value))
146
+ return true;
147
+ const params = value['params'];
148
+ return typeof params === 'object' && params !== null;
149
+ }
150
+ /** The §5.1 error object: a Number `code` and a String `message` (plus optional `data`). */
151
+ function isJsonRpcErrorObject(value) {
152
+ return isRecord(value) && typeof value['code'] === 'number' && typeof value['message'] === 'string';
153
+ }
154
+ /**
155
+ * Whether an arbitrary value is a JSON-RPC 2.0 message.
156
+ *
157
+ * Messages arriving over `postMessage` are attacker-influenced input — any page able to reach the
158
+ * frame can post anything. Validate before dispatch; never trust the shape.
159
+ *
160
+ * Found by live adversarial testing against a real sandboxed iframe (2026-07-28), NOT by static
161
+ * review: a request whose `method` is a valid string but whose `id` is present and malformed
162
+ * (e.g. an object, `{ jsonrpc: '2.0', id: { nested: true }, method: 'tools/call' }`) used to pass
163
+ * this check — the `typeof value['method'] === 'string'` branch returned `true` unconditionally,
164
+ * without ever looking at `id`'s type. A Host trusting that then had to build a JSON-RPC response
165
+ * carrying a non-spec `id` back at the View, which the View's own correlation map (keyed by
166
+ * string ids) could never match — not a crash, but a real protocol violation this function exists
167
+ * specifically to catch. Now: if `id` is present at all, its type is checked before anything else,
168
+ * for every message shape (request, notification, or response) — a notification legitimately has
169
+ * no `id`, but a message that HAS one must have a valid one.
170
+ *
171
+ * The 2026-07-29 audit found the rest of that check was still far too generous, in three ways, all
172
+ * of them reachable from anything able to post at the frame:
173
+ *
174
+ * - **`params` went unread.** Any string `method` returned `true` immediately, so
175
+ * `{method: 'tools/call', params: 'nope'}` reached dispatch and a handler reading
176
+ * `params.capabilityId` got `undefined` rather than a refusal. §4.2 fixes the type: Array or
177
+ * Object.
178
+ * - **The four shapes were not kept apart.** JSON-RPC 2.0 defines request, notification, success
179
+ * response and error response as distinct, mutually exclusive objects. A message carrying both
180
+ * `method` and `result` passed as a request; one carrying both `result` and `error` passed as a
181
+ * response, which §5 forbids in as many words ("Either the result member or error member MUST be
182
+ * included, but both members MUST NOT be included").
183
+ * - **`error` was accepted as any value at all**, `error: "boom"` included, so a host formatting
184
+ * `error.message` back to a user read a property off a string.
185
+ *
186
+ * A message whose `method` is present but not a string is rejected outright rather than falling
187
+ * through to the response branch — reinterpreting a malformed request as a response is how one
188
+ * bad message becomes two wrong behaviors.
189
+ *
190
+ * @param value - The raw `event.data`.
191
+ * @returns True when the value is a well-formed JSON-RPC message.
192
+ */
193
+ export function isJsonRpcMessage(value) {
194
+ if (!isRecord(value) || value['jsonrpc'] !== '2.0')
195
+ return false;
196
+ if ('id' in value && typeof value['id'] !== 'number' && typeof value['id'] !== 'string')
197
+ return false;
198
+ if ('method' in value) {
199
+ // Request or notification: `id` present or not, but never a response's members alongside.
200
+ return typeof value['method'] === 'string'
201
+ && hasValidParams(value)
202
+ && !('result' in value)
203
+ && !('error' in value);
204
+ }
205
+ // Response: correlated by `id`, carrying exactly one of `result` / `error`.
206
+ if (!('id' in value))
207
+ return false;
208
+ const hasResult = 'result' in value;
209
+ const hasError = 'error' in value;
210
+ if (hasResult === hasError)
211
+ return false;
212
+ return hasResult || isJsonRpcErrorObject(value['error']);
213
+ }
214
+ /** Whether a validated message expects a response (as opposed to being a notification). */
215
+ export function isJsonRpcRequest(message) {
216
+ return 'id' in message && typeof message.method === 'string';
217
+ }
218
+ /**
219
+ * Builds a request.
220
+ *
221
+ * @param id - Correlation id, unique per in-flight request. Doubles as the idempotency key: a
222
+ * transport that redelivers (an SSE reconnect, a repeated post) must not execute twice.
223
+ * @param method - Method name.
224
+ * @param params - Optional parameters.
225
+ */
226
+ export function createJsonRpcRequest(id, method, params) {
227
+ return { jsonrpc: '2.0', id, method, ...(params === undefined ? {} : { params }) };
228
+ }
229
+ /** Builds a notification — no `id`, so no response is expected or allowed. */
230
+ export function createJsonRpcNotification(method, params) {
231
+ return { jsonrpc: '2.0', method, ...(params === undefined ? {} : { params }) };
232
+ }
233
+ /** Builds a success response for `id`. */
234
+ export function createJsonRpcResult(id, result) {
235
+ return { jsonrpc: '2.0', id, result };
236
+ }
237
+ /** Builds an error response for `id`. */
238
+ export function createJsonRpcError(id, code, message, data) {
239
+ return { jsonrpc: '2.0', id, error: { code, message, ...(data === undefined ? {} : { data }) } };
240
+ }
241
+ /**
242
+ * Builds a Jini page-action request.
243
+ *
244
+ * @param id - Correlation/idempotency id.
245
+ * @param capabilityId - A `page.*` capability id.
246
+ * @param input - Capability arguments.
247
+ * @returns The namespaced extension request.
248
+ */
249
+ export function createPageActionRequest(id, capabilityId, input) {
250
+ return createJsonRpcRequest(id, JINI_PAGE_ACTION_METHOD, { capabilityId, input });
251
+ }
252
+ //# sourceMappingURL=mcp-ui-apps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-ui-apps.js","sourceRoot":"","sources":["../../src/core/mcp-ui-apps.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @module page-capabilities
3
+ *
4
+ * What an outside caller may ask a *page* to do: find the tagged controls, point at one, and
5
+ * operate it. Every verb addresses an element by its published `data-agent-element` handle —
6
+ * never by a caller-supplied selector, and never by evaluating caller-supplied script.
7
+ *
8
+ * Deliberately small. `click` is unbounded by construction (it carries whatever effect that
9
+ * button has), so the surface stays narrow and the page decides what is reachable by choosing
10
+ * what to tag. Nothing here scans a whole document: a host names the container to search.
11
+ */
12
+ import type { CapabilityDef } from './capability.js';
13
+ export declare const PAGE_CAPABILITIES: readonly CapabilityDef[];
14
+ //# sourceMappingURL=page-capabilities.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-capabilities.d.ts","sourceRoot":"","sources":["../../src/core/page-capabilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAWrD,eAAO,MAAM,iBAAiB,EAAE,SAAS,aAAa,EAiIrD,CAAC"}