@ggui-ai/iframe-runtime 0.6.0 → 0.6.2

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.
@@ -6,8 +6,9 @@
6
6
  *
7
7
  * The iframe plays the MCP Apps HOST role for the embedded content:
8
8
  *
9
- * - `ui/initialize` → respond with minimal context (theme +
10
- * containerDimensions + locale).
9
+ * - `ui/initialize` → respond with a spec-canonical
10
+ * `McpUiInitializeResult` whose `hostContext` carries minimal
11
+ * context (locale + containerDimensions).
11
12
  * - `tools/call` → forward to the ggui server's
12
13
  * `/mcp-apps/tools-call` endpoint. The server enforces source
13
14
  * connector scoping + `_meta.ui.visibility: ['app']`.
@@ -46,8 +47,6 @@ export interface McpAppIframeMountOptions {
46
47
  * NOT have a trailing slash. Empty string = same-origin.
47
48
  */
48
49
  readonly serverBaseUrl?: string;
49
- /** Optional theme override for the `ui/initialize` context. */
50
- readonly theme?: Readonly<Record<string, string>>;
51
50
  /** Optional locale; defaults to `navigator.language` when
52
51
  * available. */
53
52
  readonly locale?: string;
@@ -1,11 +1,5 @@
1
- /** Default permissive-but-safe theme for iframes that don't override. */
2
- const DEFAULT_THEME = {
3
- '--color-primary': '#0284c7',
4
- '--color-surface': '#ffffff',
5
- '--color-text': '#111111',
6
- '--font-family': 'system-ui, -apple-system, sans-serif',
7
- '--border-radius-md': '8px',
8
- };
1
+ import { LATEST_PROTOCOL_VERSION, } from '@modelcontextprotocol/ext-apps';
2
+ const EMBED_HOST_VERSION = typeof __GGUI_RUNTIME_VERSION__ === 'string' ? __GGUI_RUNTIME_VERSION__ : 'dev';
9
3
  // =============================================================================
10
4
  // Helpers
11
5
  // =============================================================================
@@ -108,16 +102,28 @@ export function mountMcpAppIframe(container, opts) {
108
102
  let response;
109
103
  switch (req.method) {
110
104
  case 'ui/initialize': {
111
- response = {
112
- jsonrpc: '2.0',
113
- id,
114
- result: {
115
- theme: opts.theme ?? DEFAULT_THEME,
116
- containerDimensions: dims,
105
+ // Spec-canonical `McpUiInitializeResult` — a spec-compliant
106
+ // embedded app connects via ext-apps `App.connect`, which
107
+ // zod-requires `protocolVersion` + `hostInfo` +
108
+ // `hostCapabilities` + `hostContext`; the pre-App draft shape
109
+ // fails that gate and kills the embedded mount. Adapter
110
+ // boundary — `hostContext` carries `{locale,
111
+ // containerDimensions}` ONLY (no outer ggui render state).
112
+ const requestedRaw = req.params?.['protocolVersion'];
113
+ const requested = typeof requestedRaw === 'string' && requestedRaw.length > 0
114
+ ? requestedRaw
115
+ : LATEST_PROTOCOL_VERSION;
116
+ const result = {
117
+ protocolVersion: requested,
118
+ hostInfo: { name: 'ggui-iframe-runtime-embed-host', version: EMBED_HOST_VERSION },
119
+ hostCapabilities: {},
120
+ hostContext: {
117
121
  locale: opts.locale ??
118
122
  (typeof navigator !== 'undefined' ? navigator.language : 'en-US'),
123
+ containerDimensions: dims,
119
124
  },
120
125
  };
126
+ response = { jsonrpc: '2.0', id, result };
121
127
  break;
122
128
  }
123
129
  case 'tools/call': {
@@ -49,10 +49,10 @@ import { parseServerMessage, } from '@ggui-ai/preview-a2ui';
49
49
  import { Button, Card, Checkbox, Divider, Heading, Icon, Image, Input, Row, Select, Spinner, Stack, Text, } from '@ggui-ai/design/primitives';
50
50
  import { PreviewFragmentEnter, PreviewSurface, StreamingText, } from '@ggui-ai/design/preview';
51
51
  // A2UI Text carries INLINE markdown (the block level comes from
52
- // `variant`) — rendered through the shared @silverprotocol/richtext
53
- // subset via the design system's inline renderer. Streaming-safe:
54
- // prefixes parse to stable ASTs, so re-emitting a longer `text`
55
- // only extends the trailing construct.
52
+ // `variant`) — rendered through the design system's own rich-text
53
+ // subset (`@ggui-ai/design/richtext`) via its inline renderer.
54
+ // Streaming-safe: prefixes parse to stable ASTs, so re-emitting a
55
+ // longer `text` only extends the trailing construct.
56
56
  import { MarkdownInline } from '@ggui-ai/design';
57
57
  const A2UI_ROOT_ID = 'root';
58
58
  const EMPTY_STATE = {
@@ -158,7 +158,7 @@ function renderComponent(component, all) {
158
158
  const headingMatch = /^h([1-6])$/.exec(variant);
159
159
  if (headingMatch) {
160
160
  const level = Number(headingMatch[1]);
161
- return wrap(createElement(Heading, { level }, createElement(StreamingText, null, createElement(MarkdownInline, { text: component.text }))));
161
+ return wrap(createElement(Heading, { level }, createElement(StreamingText, null, createElement(MarkdownInline, { markdown: component.text }))));
162
162
  }
163
163
  // A2UI 'caption' / 'label' map onto Text's size/weight/tone
164
164
  // axes; anything else degrades to default body text.
@@ -167,7 +167,7 @@ function renderComponent(component, all) {
167
167
  : variant === 'label'
168
168
  ? { size: 'sm', weight: 'medium' }
169
169
  : {};
170
- return wrap(createElement(Text, textProps, createElement(StreamingText, null, createElement(MarkdownInline, { text: component.text }))));
170
+ return wrap(createElement(Text, textProps, createElement(StreamingText, null, createElement(MarkdownInline, { markdown: component.text }))));
171
171
  }
172
172
  case 'Image':
173
173
  return wrap(createElement(Image, { src: component.src, alt: component.alt ?? '' }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ggui-ai/iframe-runtime",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "The iframe-local ggui runtime: a self-contained ESM bundle that boots inside an MCP Apps host iframe, runs the protocol-version handshake, opens the live-channel WebSocket, and mounts the rendered UI. Bundles React, ReactDOM, and the ggui design system so generated component code has a single seam to read from.",
5
5
  "keywords": [
6
6
  "ggui",
@@ -35,12 +35,12 @@
35
35
  "qrcode-generator": "^2.0.4",
36
36
  "react": "^19.0.0",
37
37
  "react-dom": "^19.0.0",
38
- "@ggui-ai/live-channel": "0.6.0",
39
- "@ggui-ai/preview-a2ui": "0.6.0",
40
- "@ggui-ai/gadgets": "0.6.0",
41
- "@ggui-ai/protocol": "0.6.0",
42
- "@ggui-ai/design": "0.6.0",
43
- "@ggui-ai/wire": "0.6.0"
38
+ "@ggui-ai/gadgets": "0.6.2",
39
+ "@ggui-ai/design": "0.6.2",
40
+ "@ggui-ai/protocol": "0.6.2",
41
+ "@ggui-ai/preview-a2ui": "0.6.2",
42
+ "@ggui-ai/live-channel": "0.6.2",
43
+ "@ggui-ai/wire": "0.6.2"
44
44
  },
45
45
  "peerDependencies": {
46
46
  "@modelcontextprotocol/sdk": "^1.27.0"