@frontmcp/uipack 1.11.2 → 1.11.3
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/CLAUDE.md +4 -4
- package/README.md +20 -15
- package/adapters/code-highlight.d.ts +20 -0
- package/adapters/code-highlight.d.ts.map +1 -0
- package/adapters/index.d.ts +4 -2
- package/adapters/index.d.ts.map +1 -1
- package/adapters/index.js +36 -16
- package/adapters/markdown.d.ts +10 -2
- package/adapters/markdown.d.ts.map +1 -1
- package/adapters/mdx.d.ts +34 -0
- package/adapters/mdx.d.ts.map +1 -0
- package/adapters/project-require.d.ts +22 -0
- package/adapters/project-require.d.ts.map +1 -0
- package/adapters/render-options.d.ts +28 -0
- package/adapters/render-options.d.ts.map +1 -0
- package/adapters/response-builder.d.ts +9 -0
- package/adapters/response-builder.d.ts.map +1 -1
- package/adapters/server-react.d.ts +22 -0
- package/adapters/server-react.d.ts.map +1 -0
- package/adapters/serving-mode.d.ts +4 -1
- package/adapters/serving-mode.d.ts.map +1 -1
- package/adapters/template-renderer.d.ts +42 -2
- package/adapters/template-renderer.d.ts.map +1 -1
- package/component/index.js +25 -11
- package/component/loader.d.ts +5 -0
- package/component/loader.d.ts.map +1 -1
- package/component/renderer.d.ts.map +1 -1
- package/component/server-render.d.ts +21 -0
- package/component/server-render.d.ts.map +1 -0
- package/component/transpiler.d.ts +17 -13
- package/component/transpiler.d.ts.map +1 -1
- package/component/types.d.ts +7 -0
- package/component/types.d.ts.map +1 -1
- package/esm/adapters/index.mjs +36 -16
- package/esm/component/index.mjs +25 -11
- package/esm/index.mjs +71 -18
- package/esm/package.json +24 -3
- package/esm/shell/index.mjs +34 -1
- package/index.d.ts +1 -1
- package/index.d.ts.map +1 -1
- package/index.js +72 -19
- package/package.json +24 -3
- package/resolver/cdn-registry.d.ts +1 -1
- package/resolver/cdn-registry.d.ts.map +1 -1
- package/resolver/esm-sh.resolver.d.ts +1 -1
- package/resolver/esm-sh.resolver.d.ts.map +1 -1
- package/resolver/import-map.d.ts +1 -1
- package/resolver/import-map.d.ts.map +1 -1
- package/resolver/import-rewriter.d.ts.map +1 -1
- package/shell/custom-shell-resolver.d.ts +1 -1
- package/shell/custom-shell-resolver.d.ts.map +1 -1
- package/shell/custom-shell-validator.d.ts +1 -1
- package/shell/custom-shell-validator.d.ts.map +1 -1
- package/shell/index.d.ts +2 -0
- package/shell/index.d.ts.map +1 -1
- package/shell/index.js +35 -2
- package/shell/sanitize-css.d.ts +18 -0
- package/shell/sanitize-css.d.ts.map +1 -0
- package/shell/sanitize-html.d.ts +28 -0
- package/shell/sanitize-html.d.ts.map +1 -0
- package/shell/url-widget-shell.d.ts +35 -0
- package/shell/url-widget-shell.d.ts.map +1 -0
- package/types/ui-config.d.ts +207 -198
- package/types/ui-config.d.ts.map +1 -1
- package/types/ui-runtime.d.ts +11 -12
- package/types/ui-runtime.d.ts.map +1 -1
- package/typings/cache/memory-cache.d.ts +1 -1
- package/typings/cache/memory-cache.d.ts.map +1 -1
- package/typings/type-fetcher.d.ts +2 -2
- package/typings/type-fetcher.d.ts.map +1 -1
package/types/ui-config.d.ts
CHANGED
|
@@ -59,90 +59,90 @@ export interface UIContentSecurityPolicy {
|
|
|
59
59
|
resourceDomains?: string[];
|
|
60
60
|
}
|
|
61
61
|
/**
|
|
62
|
-
*
|
|
62
|
+
* Sanitization of widget markup (`ui.contentSecurity`).
|
|
63
63
|
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
64
|
+
* Without `contentSecurity`, template markup reaches the page as written: a `<script>`, an
|
|
65
|
+
* `onclick` or a `javascript:` link in markup a template builds (`ctx.helpers.html`, `trustedHtml`,
|
|
66
|
+
* an HTML string) is kept, which is what widgets with inline scripts rely on. Values interpolated
|
|
67
|
+
* into `` html`…` `` are escaped either way, and so are plain string results unless
|
|
68
|
+
* `escapeStringResults: false`.
|
|
66
69
|
*
|
|
67
|
-
*
|
|
70
|
+
* With `contentSecurity` set, even to `{}`, the markup FrontMCP builds on the server from the
|
|
71
|
+
* template is sanitized before it goes into the page. The sanitizer reads the markup as the
|
|
72
|
+
* browser's HTML tokenizer does and writes every tag back out, each attribute value decoded once,
|
|
73
|
+
* checked, and written back escaped, so the page gets exactly what was checked. It removes:
|
|
68
74
|
*
|
|
69
|
-
*
|
|
75
|
+
* - `<script>` elements and `on*` handler attributes;
|
|
76
|
+
* - `srcdoc`, and `<object>`, `<embed>`, `<applet>`, `<base>` and `<meta>` elements;
|
|
77
|
+
* - SVG animation elements (`<animate>`, `<set>`, `<animateMotion>`, `<animateTransform>`), which
|
|
78
|
+
* can set any attribute of their parent, an `href` included;
|
|
79
|
+
* - `data-tool-call` and `data-tool-args`, with which the bridge calls a tool when the element is
|
|
80
|
+
* clicked;
|
|
81
|
+
* - every URL attribute (`href`, `src`, `action`, `formaction`, `xlink:href`, `srcset`, `ping`, …)
|
|
82
|
+
* whose scheme isn't `http:`, `https:` or `mailto:`; relative URLs stay, and so do raster
|
|
83
|
+
* `data:image/…` URLs in `<img src>`;
|
|
84
|
+
* - `@import` rules in `<style>` elements, `<link rel="stylesheet">` to another origin, and
|
|
85
|
+
* `position: fixed` and `position: sticky` in `style` attributes, which would let the markup lay
|
|
86
|
+
* itself over the widget;
|
|
87
|
+
* - comments, doctypes and processing instructions.
|
|
70
88
|
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
* │ ChatGPT / Claude Desktop │
|
|
74
|
-
* │ ┌─────────────────────────────────────────────┐│
|
|
75
|
-
* │ │ Outer Sandbox Iframe ││
|
|
76
|
-
* │ │ - sandbox="allow-scripts allow-same-origin"││
|
|
77
|
-
* │ │ - No access to parent cookies ││
|
|
78
|
-
* │ │ ┌─────────────────────────────────────────┐││
|
|
79
|
-
* │ │ │ Inner Widget Iframe │││
|
|
80
|
-
* │ │ │ - CSP: script-src 'self' 'unsafe-inline'│││
|
|
81
|
-
* │ │ │ - CSP: connect-src based on config │││
|
|
82
|
-
* │ │ │ - Your widget HTML renders here │││
|
|
83
|
-
* │ │ └─────────────────────────────────────────┘││
|
|
84
|
-
* │ └─────────────────────────────────────────────┘│
|
|
85
|
-
* └─────────────────────────────────────────────────┘
|
|
86
|
-
* ```
|
|
89
|
+
* Other CSS is not filtered: a `<style>` element can still position or hide elements, and
|
|
90
|
+
* `url(…)` in CSS still loads from the origins the widget's Content-Security-Policy allows.
|
|
87
91
|
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
+
* It applies to HTML, Markdown and MDX strings, to a template function's result, and to a
|
|
93
|
+
* component rendered on the server with `uiType: 'react'`. The page FrontMCP builds around the
|
|
94
|
+
* markup (the bridge, the call's data) is not touched, and a `{ file }` widget, which renders in
|
|
95
|
+
* the page, can't take it: the server refuses to start such a tool. It must be a plain object whose
|
|
96
|
+
* flags are booleans; anything else fails startup.
|
|
92
97
|
*
|
|
93
|
-
*
|
|
98
|
+
* Both OpenAI and Claude render widgets in sandboxed iframes, so script in a widget is contained,
|
|
99
|
+
* but it can still read the widget's data, call tools the widget may call and show a fake UI.
|
|
100
|
+
* Sanitize when the markup carries values you don't control and you'd rather not rely on escaping
|
|
101
|
+
* every one of them.
|
|
94
102
|
*/
|
|
95
103
|
export interface UIContentSecurity {
|
|
96
104
|
/**
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
* - `/`, `#` (relative paths, anchors)
|
|
102
|
-
* - `mailto:` (email links)
|
|
103
|
-
*
|
|
104
|
-
* When `true`, allows any URL scheme including:
|
|
105
|
-
* - `javascript:` (inline script execution)
|
|
106
|
-
* - `data:` (data URIs)
|
|
107
|
-
* - `vbscript:` (legacy script)
|
|
105
|
+
* Keep any scheme but `data:` in the attributes that navigate when the user follows them: `href`
|
|
106
|
+
* of `<a>` and `<area>`, `action` of `<form>`, and `formaction` of `<button>` and `<input>`. A
|
|
107
|
+
* `javascript:` link then runs when it is clicked. Every other URL attribute, such as `src` of an
|
|
108
|
+
* `<iframe>`, `<frame>` or `<img>`, keeps the `http:` / `https:` / `mailto:` rule.
|
|
108
109
|
*
|
|
109
110
|
* @default false
|
|
110
111
|
*/
|
|
111
112
|
allowUnsafeLinks?: boolean;
|
|
112
113
|
/**
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
* When `true`, these elements are preserved in the output.
|
|
120
|
-
*
|
|
121
|
-
* **Note:** Even with this enabled, CSP may still block script execution
|
|
122
|
-
* depending on the platform's iframe sandbox settings.
|
|
114
|
+
* Keep script written in the markup: `<script>` elements without a `src` (or SVG `href`), and
|
|
115
|
+
* `on*` event handler attributes. A `<script src>`, `<object>`, `<embed>`, `<applet>` and
|
|
116
|
+
* `srcdoc` are still removed. Inline script can do anything script can, loading more script
|
|
117
|
+
* included, so this turns script protection off for whoever controls the markup: set it only for
|
|
118
|
+
* markup you trust. Hosts may still block a script through the widget's Content-Security-Policy.
|
|
123
119
|
*
|
|
124
120
|
* @default false
|
|
125
121
|
*/
|
|
126
122
|
allowInlineScripts?: boolean;
|
|
127
123
|
/**
|
|
128
|
-
*
|
|
124
|
+
* Keep `data-tool-call` and `data-tool-args`. The bridge calls the tool `data-tool-call` names,
|
|
125
|
+
* with the JSON in `data-tool-args`, when the element (or anything inside it) is clicked, so
|
|
126
|
+
* whoever controls the markup chooses which tool a click calls and with what. Set it only when
|
|
127
|
+
* the markup's tool-call attributes are your own.
|
|
129
128
|
*
|
|
130
|
-
*
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
* - No HTML escaping is performed
|
|
137
|
-
*
|
|
138
|
-
* This is useful for:
|
|
139
|
-
* - Embedding trusted third-party widgets
|
|
140
|
-
* - Complex interactive dashboards from trusted sources
|
|
141
|
-
* - Content that was pre-sanitized server-side
|
|
129
|
+
* @default false
|
|
130
|
+
*/
|
|
131
|
+
allowToolCallAttributes?: boolean;
|
|
132
|
+
/**
|
|
133
|
+
* Skip sanitization: the markup is used as written, as if `contentSecurity` were unset. Only for
|
|
134
|
+
* markup you fully trust.
|
|
142
135
|
*
|
|
143
136
|
* @default false
|
|
144
137
|
*/
|
|
145
138
|
bypassSanitization?: boolean;
|
|
139
|
+
/**
|
|
140
|
+
* The longest markup, in characters, that is sanitized. Longer markup is not rendered: the render
|
|
141
|
+
* fails, and the tool call returns without its widget.
|
|
142
|
+
*
|
|
143
|
+
* @default 2097152 (2 Mi)
|
|
144
|
+
*/
|
|
145
|
+
maxMarkupLength?: number;
|
|
146
146
|
}
|
|
147
147
|
/**
|
|
148
148
|
* Helper functions available in template context.
|
|
@@ -222,7 +222,8 @@ export type TemplateBuilderFn<In = unknown, Out = unknown> = (ctx: TemplateConte
|
|
|
222
222
|
* Widget serving mode determines how the widget HTML is delivered to the client.
|
|
223
223
|
*
|
|
224
224
|
* - `'auto'` (default): Automatically select mode based on client capabilities.
|
|
225
|
-
* For
|
|
225
|
+
* For ext-apps and Claude: uses 'inline'. For OpenAI: uses 'static', so no result carries
|
|
226
|
+
* the page: the OpenAI Apps SDK renders the widget from its `ui://` resource.
|
|
226
227
|
* For unsupported clients (e.g., Gemini): skips UI entirely (returns JSON only).
|
|
227
228
|
*
|
|
228
229
|
* - `'inline'`: HTML embedded directly in tool response `_meta['ui/html']`.
|
|
@@ -236,9 +237,13 @@ export type TemplateBuilderFn<In = unknown, Out = unknown> = (ctx: TemplateConte
|
|
|
236
237
|
* - `'hybrid'`: Shell (React runtime + bridge) pre-compiled at startup.
|
|
237
238
|
* Component code transpiled per-request and delivered in `_meta['ui/component']`.
|
|
238
239
|
*
|
|
239
|
-
* - `'direct-url'`:
|
|
240
|
+
* - `'direct-url'`: Compiled at startup, as with `'static'`, and served on a route of the server
|
|
241
|
+
* (`directPath`). The `ui://` resource is a small page that frames that URL and relays the host's
|
|
242
|
+
* bridge messages. Results carry no page.
|
|
240
243
|
*
|
|
241
|
-
* - `'custom-url'`:
|
|
244
|
+
* - `'custom-url'`: The page at `customWidgetUrl` (a CDN, a separate deployment) is the widget; the
|
|
245
|
+
* `ui://` resource frames it, as for `'direct-url'`. FrontMCP doesn't render `template` for it.
|
|
246
|
+
* Results carry no page.
|
|
242
247
|
*
|
|
243
248
|
* ## Claude target caveat (issue #447)
|
|
244
249
|
*
|
|
@@ -293,8 +298,10 @@ export interface UITemplateConfig<In = unknown, Out = unknown> {
|
|
|
293
298
|
* Supports multiple formats (auto-detected by renderer):
|
|
294
299
|
* - Template builder function: `(ctx) => string` - receives input/output/helpers, returns HTML
|
|
295
300
|
* - Static HTML/MDX string: `"<div>...</div>"` or `"# Title\n<Card />"`
|
|
296
|
-
* - React component: `MyWidget` -
|
|
301
|
+
* - React component: `MyWidget` - rendered on the server with `uiType: 'react'`, with props output/input/loading
|
|
297
302
|
* - FileSource object: `{ file: './my-widget.tsx' }` - transpiled client-side via esm.sh CDN
|
|
303
|
+
*
|
|
304
|
+
* Not rendered for `servingMode: 'custom-url'`, whose page is at `customWidgetUrl`.
|
|
298
305
|
*/
|
|
299
306
|
template: TemplateBuilderFn<In, Out> | string | ((props: any) => any) | FileSource;
|
|
300
307
|
/**
|
|
@@ -303,47 +310,17 @@ export interface UITemplateConfig<In = unknown, Out = unknown> {
|
|
|
303
310
|
*/
|
|
304
311
|
csp?: UIContentSecurityPolicy;
|
|
305
312
|
/**
|
|
306
|
-
*
|
|
307
|
-
*
|
|
308
|
-
*
|
|
309
|
-
* - Removes `<script>` tags and event handlers (onclick, onerror, etc.)
|
|
310
|
-
* - Validates URL schemes in links (blocks `javascript:`, `data:`, `vbscript:`)
|
|
311
|
-
*
|
|
312
|
-
* These protections can be disabled for trusted content that requires
|
|
313
|
-
* inline scripts, custom event handlers, or special URL schemes.
|
|
314
|
-
*
|
|
315
|
-
* ## Security Context
|
|
316
|
-
*
|
|
317
|
-
* **OpenAI/Claude run widgets in double-iframe isolation:**
|
|
318
|
-
* - Outer sandbox iframe with restricted permissions
|
|
319
|
-
* - Inner content iframe with CSP headers
|
|
320
|
-
* - No access to parent window or cookies
|
|
321
|
-
* - Network requests restricted by CSP
|
|
322
|
-
*
|
|
323
|
-
* This isolation provides defense-in-depth, making XSS less impactful.
|
|
324
|
-
* However, XSS can still:
|
|
325
|
-
* - Steal widget state/data
|
|
326
|
-
* - Make unauthorized API calls (within CSP limits)
|
|
327
|
-
* - Phish users with fake UI
|
|
328
|
-
*
|
|
329
|
-
* **Best Practice:** Keep XSS protection enabled unless you have a specific
|
|
330
|
-
* need for inline scripts/handlers AND trust your content source completely.
|
|
313
|
+
* Sanitize the markup FrontMCP builds on the server from the template. Unset (the default), it is
|
|
314
|
+
* used as written; set, even to `{}`, scripts, event handlers and unsafe links are removed unless
|
|
315
|
+
* the flags allow them. See {@link UIContentSecurity}.
|
|
331
316
|
*
|
|
332
317
|
* @example
|
|
333
318
|
* ```typescript
|
|
334
|
-
* //
|
|
335
|
-
* ui: { template: MyWidget }
|
|
336
|
-
*
|
|
337
|
-
* // Allow inline scripts for trusted dashboard
|
|
338
|
-
* ui: {
|
|
339
|
-
* template: TrustedDashboard,
|
|
340
|
-
* contentSecurity: { allowInlineScripts: true }
|
|
341
|
-
* }
|
|
342
|
-
*
|
|
343
|
-
* // Bypass all sanitization for fully trusted HTML
|
|
319
|
+
* // Render the HTML a tool returns, without its scripts, handlers or unsafe links
|
|
344
320
|
* ui: {
|
|
345
|
-
* template:
|
|
346
|
-
*
|
|
321
|
+
* template: (ctx) => ctx.output.summaryHtml,
|
|
322
|
+
* escapeStringResults: false,
|
|
323
|
+
* contentSecurity: {},
|
|
347
324
|
* }
|
|
348
325
|
* ```
|
|
349
326
|
*/
|
|
@@ -451,8 +428,9 @@ export interface UITemplateConfig<In = unknown, Out = unknown> {
|
|
|
451
428
|
* How the widget HTML should be served to the client.
|
|
452
429
|
*
|
|
453
430
|
* - `'auto'` (default): Automatically select mode based on client capabilities.
|
|
454
|
-
* For
|
|
455
|
-
* For
|
|
431
|
+
* For ext-apps and Claude clients: uses `'inline'` with `_meta`.
|
|
432
|
+
* For OpenAI clients: uses `'static'`, so no result carries the page, not even the one a widget's
|
|
433
|
+
* own `window.openai.callTool()` gets: the OpenAI Apps SDK renders the widget from its `ui://` resource.
|
|
456
434
|
* For unsupported clients (Gemini, unknown): skips UI (returns JSON only).
|
|
457
435
|
*
|
|
458
436
|
* - `'inline'`: HTML embedded directly in tool response `_meta['ui/html']`.
|
|
@@ -465,11 +443,16 @@ export interface UITemplateConfig<In = unknown, Out = unknown> {
|
|
|
465
443
|
* - `'hybrid'`: Shell (React runtime + bridge) pre-compiled at startup.
|
|
466
444
|
* Component code transpiled per-request and delivered in `_meta['ui/component']`.
|
|
467
445
|
*
|
|
468
|
-
* - `'direct-url'`:
|
|
469
|
-
*
|
|
446
|
+
* - `'direct-url'`: Compiled at startup, as with `'static'`, and served from the server's own
|
|
447
|
+
* HTTP route (`directPath`). The `ui://` resource is a small page that frames that URL, so the
|
|
448
|
+
* widget runs on the server's origin, and relays the host's bridge messages to it. The resource
|
|
449
|
+
* declares the URL's origin as a frame: `_meta.ui.csp.frameDomains` (MCP Apps) and
|
|
450
|
+
* `_meta['openai/widgetCSP'].frame_domains` (OpenAI Apps SDK). Results carry no page; the host
|
|
451
|
+
* sends each call's data to the widget.
|
|
470
452
|
*
|
|
471
|
-
* - `'custom-url'`:
|
|
472
|
-
*
|
|
453
|
+
* - `'custom-url'`: The page at `customWidgetUrl`, such as a CDN's, is the widget. The `ui://`
|
|
454
|
+
* resource frames it and declares its origin as a frame, as for `'direct-url'`. FrontMCP doesn't
|
|
455
|
+
* render `template` for this mode. Results carry no page.
|
|
473
456
|
*
|
|
474
457
|
* When unset, the FrontMCP SDK uses the app's `@App({ ui: { servingMode } })` default, else the
|
|
475
458
|
* server's `@FrontMcp({ ui: { servingMode } })`, else `'auto'`.
|
|
@@ -478,39 +461,64 @@ export interface UITemplateConfig<In = unknown, Out = unknown> {
|
|
|
478
461
|
*/
|
|
479
462
|
servingMode?: WidgetServingMode;
|
|
480
463
|
/**
|
|
481
|
-
*
|
|
482
|
-
*
|
|
483
|
-
*
|
|
464
|
+
* The URL of the widget page when `servingMode: 'custom-url'`: an `https://` URL (or `http://` on
|
|
465
|
+
* localhost), such as a CDN's. The `ui://` resource frames it, declares its origin as a frame
|
|
466
|
+
* (`_meta.ui.csp.frameDomains`, `_meta['openai/widgetCSP'].frame_domains`) and relays the host's
|
|
467
|
+
* bridge messages to it.
|
|
468
|
+
*
|
|
469
|
+
* The page is yours: FrontMCP doesn't render `template` for it, and it must answer the host over
|
|
470
|
+
* the MCP Apps bridge (JSON-RPC over `postMessage` to its parent): a page built with `buildShell()`
|
|
471
|
+
* from `@frontmcp/uipack/shell` has FrontMCP's bridge, and `@modelcontextprotocol/ext-apps` works
|
|
472
|
+
* too. It must allow framing (no `X-Frame-Options: DENY`).
|
|
473
|
+
*
|
|
474
|
+
* The URL is used as written: FrontMCP adds no token or call data to it, and the page gets each
|
|
475
|
+
* call's result from the host. Startup refuses a URL with a `{…}` placeholder or credentials, a
|
|
476
|
+
* `'custom-url'` widget without this option, and this option on a widget not served `'custom-url'`.
|
|
484
477
|
*
|
|
485
478
|
* @example
|
|
486
479
|
* ```typescript
|
|
487
|
-
* customWidgetUrl: 'https://cdn.example.com/widgets/weather.html
|
|
480
|
+
* ui: { template: '', servingMode: 'custom-url', customWidgetUrl: 'https://cdn.example.com/widgets/weather.html' }
|
|
488
481
|
* ```
|
|
489
482
|
*/
|
|
490
483
|
customWidgetUrl?: string;
|
|
491
484
|
/**
|
|
492
|
-
*
|
|
493
|
-
*
|
|
485
|
+
* The route a `servingMode: 'direct-url'` widget is served on, from the server's root. Default:
|
|
486
|
+
* `/widgets/` and the tool name (characters other than letters, digits, `.`, `_`, `~` and `-`
|
|
487
|
+
* become `-`).
|
|
488
|
+
*
|
|
489
|
+
* The route answers `GET` without auth, in every auth mode, because a host loads it in a frame,
|
|
490
|
+
* which sends no credentials. It serves the page compiled at startup, which holds no call's data.
|
|
491
|
+
* The URL the `ui://` resource frames starts with `FRONTMCP_PUBLIC_URL` when set, else with the
|
|
492
|
+
* scheme and host the `resources/read` request came to. Startup refuses a path that collides with
|
|
493
|
+
* another route of the server or another widget, and a `directPath` on a widget not served
|
|
494
|
+
* `'direct-url'`.
|
|
494
495
|
*
|
|
495
496
|
* @example
|
|
496
497
|
* ```typescript
|
|
497
|
-
* directPath: '/widgets/weather'
|
|
498
|
-
* //
|
|
498
|
+
* ui: { template: WeatherWidget, servingMode: 'direct-url', directPath: '/widgets/weather' }
|
|
499
|
+
* // ui://widget/get_weather.html frames https://mcp.example.com/widgets/weather
|
|
499
500
|
* ```
|
|
500
501
|
*/
|
|
501
502
|
directPath?: string;
|
|
502
503
|
/**
|
|
503
|
-
*
|
|
504
|
-
*
|
|
504
|
+
* React components for an MDX template. With `mdxComponents` set, a string template is MDX: it is
|
|
505
|
+
* compiled once with `@mdx-js/mdx` and rendered to HTML on the server with React for each render,
|
|
506
|
+
* with these components for the tags it names (and for HTML elements it overrides, such as `h1`).
|
|
507
|
+
* Its expressions read the call's data as `input`, `output` and `helpers`; the data is rendered as
|
|
508
|
+
* escaped text, never compiled. The page carries the rendered HTML, not React, so event handlers
|
|
509
|
+
* in the template don't run in the page.
|
|
510
|
+
*
|
|
511
|
+
* Needs `@mdx-js/mdx`, `react` and `react-dom` installed (and `remark-gfm` for
|
|
512
|
+
* `runtimeOptions.markdown.gfm`); `runtimeOptions.markdown.highlightTheme` highlights its fenced
|
|
513
|
+
* code. The template compiles at startup, so a syntax error or a missing package fails it. Only a
|
|
514
|
+
* string template can be MDX: a template function's result carries the call's data, and compiling
|
|
515
|
+
* it would run that data as code, so `mdxComponents` on a function fails startup.
|
|
505
516
|
*
|
|
506
517
|
* @example
|
|
507
518
|
* ```typescript
|
|
508
519
|
* ui: {
|
|
509
|
-
* template: `#
|
|
510
|
-
* mdxComponents: {
|
|
511
|
-
* Alert: ({ type, children }) => <div className={type}>{children}</div>,
|
|
512
|
-
* Card: MyCardComponent,
|
|
513
|
-
* }
|
|
520
|
+
* template: `# {output.title}\n\n<Alert type="info">{output.items.length} items</Alert>`,
|
|
521
|
+
* mdxComponents: { Alert },
|
|
514
522
|
* }
|
|
515
523
|
* ```
|
|
516
524
|
*/
|
|
@@ -561,72 +569,62 @@ export interface UITemplateConfig<In = unknown, Out = unknown> {
|
|
|
561
569
|
*/
|
|
562
570
|
sandboxDomain?: string;
|
|
563
571
|
/**
|
|
564
|
-
*
|
|
565
|
-
*
|
|
566
|
-
* **Default: `false`**
|
|
567
|
-
*
|
|
568
|
-
* When `false` (default):
|
|
569
|
-
* - SSR output is static HTML
|
|
570
|
-
* - No React runtime is loaded on the client
|
|
571
|
-
* - All interactivity is handled by the FrontMCP Bridge IIFE
|
|
572
|
-
* - This prevents React Hydration Error #418 in MCP clients
|
|
572
|
+
* Render a React widget on the server and hydrate it in the page.
|
|
573
573
|
*
|
|
574
|
-
*
|
|
575
|
-
*
|
|
576
|
-
*
|
|
577
|
-
*
|
|
574
|
+
* Applies to a `{ file }` `.tsx` / `.jsx` widget. FrontMCP bundles the widget for the server too,
|
|
575
|
+
* renders it there with the call's data (the props the page's mount gives it: `output`, `input`,
|
|
576
|
+
* `loading`) inside `McpBridgeProvider`, and puts that HTML in the page's `#root`; the page's mount
|
|
577
|
+
* then calls `hydrateRoot` with the same props instead of rendering into an empty root. The widget
|
|
578
|
+
* shows its content before its script runs, and stays interactive.
|
|
578
579
|
*
|
|
579
|
-
*
|
|
580
|
-
*
|
|
581
|
-
*
|
|
582
|
-
*
|
|
583
|
-
* different execution contexts, mismatches frequently occur causing
|
|
584
|
-
* React Error #418 ("Hydration failed...").
|
|
580
|
+
* Hydration expects the page to render what the server did: a widget whose first render reads
|
|
581
|
+
* `window`, the time or random values, or a host-specific hook value, may not match, and React then
|
|
582
|
+
* renders it again in the page (logging a recoverable error). A widget compiled at startup
|
|
583
|
+
* (`servingMode: 'static'`) is rendered with no data, in its `loading` state.
|
|
585
584
|
*
|
|
586
|
-
*
|
|
587
|
-
*
|
|
588
|
-
*
|
|
589
|
-
*
|
|
590
|
-
* **Only enable if:**
|
|
591
|
-
* - You need React state management on the client
|
|
592
|
-
* - You're sure your template produces deterministic HTML
|
|
593
|
-
* - You've tested hydration works in your target MCP client
|
|
594
|
-
*
|
|
595
|
-
* @example
|
|
596
|
-
* ```typescript
|
|
597
|
-
* // Disable hydration (default behavior - recommended)
|
|
598
|
-
* ui: {
|
|
599
|
-
* template: MyReactComponent,
|
|
600
|
-
* hydrate: false
|
|
601
|
-
* }
|
|
585
|
+
* A component reference (`template: MyWidget`) has no source file to bundle for the page, so it
|
|
586
|
+
* can't be hydrated: render it on the server only with `uiType: 'react'`, or use `{ file }`. Any
|
|
587
|
+
* other template fails startup with `hydrate: true`.
|
|
602
588
|
*
|
|
603
|
-
*
|
|
604
|
-
* ui: {
|
|
605
|
-
* template: MyStatefulComponent,
|
|
606
|
-
* hydrate: true
|
|
607
|
-
* }
|
|
608
|
-
* ```
|
|
589
|
+
* @default false
|
|
609
590
|
*/
|
|
610
591
|
hydrate?: boolean;
|
|
611
592
|
/**
|
|
612
|
-
*
|
|
593
|
+
* The renderer, instead of the one detected from the template.
|
|
594
|
+
*
|
|
595
|
+
* - `'auto'` (default): detected. A string with both `<` and `>` is HTML, any other string is
|
|
596
|
+
* Markdown (MDX with `mdxComponents`), a function is an HTML builder unless it is a React
|
|
597
|
+
* component, and `{ file: '….tsx' }` is a React widget.
|
|
598
|
+
* - `'html'`: a string is used as written, even without `<` and `>`, and a function is called as
|
|
599
|
+
* an HTML builder, even with a capitalized name.
|
|
600
|
+
* - `'markdown'`: a string is converted from Markdown even with `<` and `>` (raw HTML is escaped),
|
|
601
|
+
* and so is a template function's string result.
|
|
602
|
+
* - `'mdx'`: a string is rendered as MDX on the server, with `mdxComponents` if set.
|
|
603
|
+
* - `'react'`: a component reference (function, class, `memo` / `forwardRef`) is rendered to
|
|
604
|
+
* static HTML on the server with React, with the widget props (`output`, `input`, `loading`);
|
|
605
|
+
* it can't be bundled for the page, so its handlers don't run there. A `{ file }` `.tsx` /
|
|
606
|
+
* `.jsx` widget is bundled for the page as with `'auto'`.
|
|
613
607
|
*
|
|
614
|
-
*
|
|
615
|
-
*
|
|
616
|
-
* - `'mdx'`: MDX template
|
|
617
|
-
* - `'markdown'`: Pure Markdown
|
|
618
|
-
* - `'auto'`: Auto-detect from template (default)
|
|
608
|
+
* A template the renderer can't take fails startup, such as `'react'` on a string or `'mdx'` on a
|
|
609
|
+
* function. `'react'`, `'mdx'` and `hydrate` load `react` and `react-dom` from the server's project.
|
|
619
610
|
*
|
|
620
611
|
* @default 'auto'
|
|
621
612
|
*/
|
|
622
613
|
uiType?: 'html' | 'react' | 'mdx' | 'markdown' | 'auto';
|
|
623
614
|
/**
|
|
624
|
-
*
|
|
615
|
+
* When the widget page is built.
|
|
616
|
+
*
|
|
617
|
+
* - `'static'`: once, without a call's data; the host sends each call's result to the page.
|
|
618
|
+
* - `'dynamic'`: for each call, with that call's data in the page.
|
|
625
619
|
*
|
|
626
|
-
*
|
|
627
|
-
*
|
|
620
|
+
* It picks the serving mode where `servingMode` leaves the choice open: with `servingMode` unset
|
|
621
|
+
* (an app or server default included) or `'auto'`, `'dynamic'` serves `'inline'` on every
|
|
622
|
+
* platform, and `'static'` serves `'static'`, or keeps an inherited `'hybrid'`, `'direct-url'` or
|
|
623
|
+
* `'custom-url'`, which build the page once as well. Startup refuses a tool's own `servingMode`
|
|
624
|
+
* that contradicts it: `'dynamic'` goes with `'inline'` only, and `'static'` with anything but
|
|
625
|
+
* `'inline'`.
|
|
628
626
|
*
|
|
629
|
-
*
|
|
627
|
+
* Unset (the default): `servingMode` alone decides, as before this option worked.
|
|
630
628
|
*/
|
|
631
629
|
bundlingMode?: 'static' | 'dynamic';
|
|
632
630
|
/**
|
|
@@ -657,43 +655,54 @@ export interface UITemplateConfig<In = unknown, Out = unknown> {
|
|
|
657
655
|
* Runtime options for specific renderers.
|
|
658
656
|
*/
|
|
659
657
|
runtimeOptions?: {
|
|
660
|
-
/**
|
|
658
|
+
/** Same as {@link UITemplateConfig.hydrate}, which wins when both are set. */
|
|
661
659
|
hydrate?: boolean;
|
|
662
|
-
/**
|
|
660
|
+
/**
|
|
661
|
+
* How a Markdown template (a string template without both `<` and `>`) is converted to HTML.
|
|
662
|
+
* Unset, the converter writes headings, paragraphs, lists, fenced code, emphasis, inline code
|
|
663
|
+
* and links. Setting `gfm` or `highlightTheme` on a template that isn't Markdown fails startup.
|
|
664
|
+
*
|
|
665
|
+
* @example
|
|
666
|
+
* ```typescript
|
|
667
|
+
* ui: {
|
|
668
|
+
* template: '| Region | Sales |\n|---|---:|\n| EU | 12 |\n\n```ts\nconst total = 12;\n```',
|
|
669
|
+
* runtimeOptions: { markdown: { gfm: true, highlightTheme: 'github' } },
|
|
670
|
+
* }
|
|
671
|
+
* ```
|
|
672
|
+
*/
|
|
663
673
|
markdown?: {
|
|
664
|
-
/**
|
|
674
|
+
/**
|
|
675
|
+
* GitHub-flavored Markdown: tables (with `:---:` alignment), task list items (`- [x]`),
|
|
676
|
+
* `~~strikethrough~~`, and links for bare `https://` and `www.` URLs. Raw HTML stays escaped.
|
|
677
|
+
*/
|
|
665
678
|
gfm?: boolean;
|
|
666
|
-
/**
|
|
679
|
+
/**
|
|
680
|
+
* Highlight fenced code that names its language (```` ```ts ````) on the server with highlight.js,
|
|
681
|
+
* an optional peer to install, and put this theme's stylesheet in the page: the name of a
|
|
682
|
+
* stylesheet in `highlight.js/styles`, such as `'github'`, `'github-dark'` or
|
|
683
|
+
* `'base16/dracula'`. A missing highlight.js or theme fails startup.
|
|
684
|
+
*/
|
|
667
685
|
highlightTheme?: string;
|
|
668
686
|
};
|
|
669
687
|
};
|
|
670
688
|
/**
|
|
671
|
-
*
|
|
689
|
+
* Turns on the "dual payload" for clients that render no widget, and is the text it opens with.
|
|
672
690
|
*
|
|
673
|
-
*
|
|
674
|
-
*
|
|
675
|
-
* 1.
|
|
676
|
-
* 2.
|
|
691
|
+
* A `tools/call` from a client FrontMCP detects as `'claude'` (a Claude client that declares no
|
|
692
|
+
* MCP Apps support, so it renders no widget) gets two text blocks:
|
|
693
|
+
* 1. the JSON of the result, as without this option;
|
|
694
|
+
* 2. `{htmlResponsePrefix}:` and the page rendered with this call's data, in an `html` code fence,
|
|
695
|
+
* which such a client can show (an Artifact in Claude).
|
|
677
696
|
*
|
|
678
|
-
*
|
|
679
|
-
*
|
|
680
|
-
*
|
|
697
|
+
* The page is rendered for the call whatever `servingMode` is, and goes to that caller only. MCP
|
|
698
|
+
* Apps hosts, ChatGPT and every other client get the result as without this option, and so do
|
|
699
|
+
* calls a widget or an agent makes. Unset (the default): no client gets the second block. Startup
|
|
700
|
+
* refuses an empty value or one longer than 500 characters.
|
|
681
701
|
*
|
|
682
702
|
* @example
|
|
683
703
|
* ```typescript
|
|
684
|
-
*
|
|
685
|
-
*
|
|
686
|
-
* template: WeatherWidget,
|
|
687
|
-
* htmlResponsePrefix: 'Here is the weather dashboard',
|
|
688
|
-
* }
|
|
689
|
-
* // Output block 2: "Here is the weather dashboard:\n\n```html\n..."
|
|
690
|
-
*
|
|
691
|
-
* // Stock tool
|
|
692
|
-
* ui: {
|
|
693
|
-
* template: StockWidget,
|
|
694
|
-
* htmlResponsePrefix: 'Here is the stock information',
|
|
695
|
-
* }
|
|
696
|
-
* // Output block 2: "Here is the stock information:\n\n```html\n..."
|
|
704
|
+
* ui: { template: WeatherWidget, htmlResponsePrefix: 'Here is the weather dashboard' }
|
|
705
|
+
* // Block 2: "Here is the weather dashboard:\n\n```html\n<!DOCTYPE html>…\n```"
|
|
697
706
|
* ```
|
|
698
707
|
*/
|
|
699
708
|
htmlResponsePrefix?: string;
|
package/types/ui-config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui-config.d.ts","sourceRoot":"","sources":["../../src/types/ui-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,gCAAgC;IAChC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,yCAAyC;IACzC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gCAAgC;IAChC,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACzE,0BAA0B;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,2BAA2B;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2BAA2B;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAMD;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,uBAAuB;IACtC;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAE1B;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED
|
|
1
|
+
{"version":3,"file":"ui-config.d.ts","sourceRoot":"","sources":["../../src/types/ui-config.ts"],"names":[],"mappings":"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"}
|
package/types/ui-runtime.d.ts
CHANGED
|
@@ -45,24 +45,25 @@ type WidgetSizeValue = _WidgetSizeValue;
|
|
|
45
45
|
*/
|
|
46
46
|
export type UIType = 'html' | 'react' | 'mdx' | 'markdown' | 'auto';
|
|
47
47
|
/**
|
|
48
|
-
* Widget bundling strategy.
|
|
48
|
+
* Widget bundling strategy (a tool's `ui.bundlingMode`).
|
|
49
49
|
*
|
|
50
|
-
* - `'static'`: Widget
|
|
51
|
-
*
|
|
52
|
-
* Data is injected at runtime via FrontMCP Bridge. **Default mode.**
|
|
50
|
+
* - `'static'`: Widget page is built once, at startup, and served from `ui://widget/{toolName}`.
|
|
51
|
+
* Data reaches it at runtime via the FrontMCP Bridge.
|
|
53
52
|
*
|
|
54
|
-
* - `'dynamic'`: Fresh HTML is generated for each tool invocation
|
|
55
|
-
*
|
|
53
|
+
* - `'dynamic'`: Fresh HTML is generated for each tool invocation, with that call's data
|
|
54
|
+
* (served `'inline'`).
|
|
55
|
+
*
|
|
56
|
+
* Unset, the tool's `servingMode` alone decides. See `UITemplateConfig.bundlingMode`.
|
|
56
57
|
*
|
|
57
58
|
* @example
|
|
58
59
|
* ```typescript
|
|
59
|
-
* //
|
|
60
|
+
* // Built once at startup; the host sends each call's data
|
|
60
61
|
* ui: {
|
|
61
62
|
* template: WeatherWidget,
|
|
62
63
|
* bundlingMode: 'static'
|
|
63
64
|
* }
|
|
64
65
|
*
|
|
65
|
-
* //
|
|
66
|
+
* // Built for each call, with its data
|
|
66
67
|
* ui: {
|
|
67
68
|
* template: (ctx) => `<div>${ctx.output.debug}</div>`,
|
|
68
69
|
* bundlingMode: 'dynamic'
|
|
@@ -110,7 +111,7 @@ export type ResourceMode = 'cdn' | 'inline';
|
|
|
110
111
|
* - `'dual-payload'`: Return TWO TextContent blocks for Claude Artifacts.
|
|
111
112
|
* Block 0: Pure JSON stringified data (for programmatic parsing).
|
|
112
113
|
* Block 1: Markdown-wrapped HTML (```html...```) for visual rendering.
|
|
113
|
-
*
|
|
114
|
+
* The FrontMCP SDK sends it to a `'claude'` client when a tool sets `ui.htmlResponsePrefix`.
|
|
114
115
|
*
|
|
115
116
|
* @example
|
|
116
117
|
* ```typescript
|
|
@@ -620,10 +621,8 @@ export interface WidgetConfig<Input = Record<string, unknown>, Output = unknown>
|
|
|
620
621
|
/**
|
|
621
622
|
* Bundling mode.
|
|
622
623
|
*
|
|
623
|
-
* - `'static'`: Pre-compile widget shell, inject data at runtime
|
|
624
|
+
* - `'static'`: Pre-compile widget shell, inject data at runtime
|
|
624
625
|
* - `'dynamic'`: Generate fresh HTML per tool invocation
|
|
625
|
-
*
|
|
626
|
-
* @default 'static'
|
|
627
626
|
*/
|
|
628
627
|
bundlingMode?: BundlingMode;
|
|
629
628
|
/**
|