mountly-mcp 0.0.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +283 -20
- package/dist/artifact/index.d.ts +49 -0
- package/dist/artifact/index.js +21 -0
- package/dist/artifact/index.js.map +1 -0
- package/dist/bridge/iframe-entry.d.ts +1 -0
- package/dist/bridge/iframe-entry.js +270 -220
- package/dist/bridge/index.d.ts +20 -15
- package/dist/bridge/index.js +2 -2
- package/dist/build/emit-html.d.ts +30 -0
- package/dist/build/emit-meta.d.ts +17 -0
- package/dist/build/index.d.ts +33 -48
- package/dist/build/index.js +9 -135
- package/dist/build/index.js.map +1 -1
- package/dist/chunk-33DMFKKD.js +111 -0
- package/dist/chunk-33DMFKKD.js.map +1 -0
- package/dist/chunk-4HC3OWAQ.js +185 -0
- package/dist/chunk-4HC3OWAQ.js.map +1 -0
- package/dist/chunk-5EHNJCMF.js +58 -0
- package/dist/chunk-5EHNJCMF.js.map +1 -0
- package/dist/chunk-6QHKKFO3.js +30 -0
- package/dist/chunk-6QHKKFO3.js.map +1 -0
- package/dist/chunk-AEVQKFXX.js +119 -0
- package/dist/chunk-AEVQKFXX.js.map +1 -0
- package/dist/chunk-DKK26TRS.js +199 -0
- package/dist/chunk-DKK26TRS.js.map +1 -0
- package/dist/chunk-JVQZGKBL.js +171 -0
- package/dist/chunk-JVQZGKBL.js.map +1 -0
- package/dist/chunk-KWVGW5Q7.js +582 -0
- package/dist/chunk-KWVGW5Q7.js.map +1 -0
- package/dist/{chunk-A64ZILAS.js → chunk-M4WFJR3C.js} +3 -2
- package/dist/{chunk-A64ZILAS.js.map → chunk-M4WFJR3C.js.map} +1 -1
- package/dist/chunk-MTJDRWGD.js +196 -0
- package/dist/chunk-MTJDRWGD.js.map +1 -0
- package/dist/chunk-SADNMGP6.js +16 -0
- package/dist/chunk-SADNMGP6.js.map +1 -0
- package/dist/chunk-UECZA34Q.js +52 -0
- package/dist/chunk-UECZA34Q.js.map +1 -0
- package/dist/chunk-YJA4H6IB.js +13 -0
- package/dist/chunk-YJA4H6IB.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +297 -0
- package/dist/cli.js.map +1 -0
- package/dist/connect-server-7L4HGKKL.js +7 -0
- package/dist/connect-server-7L4HGKKL.js.map +1 -0
- package/dist/create.d.ts +10 -0
- package/dist/create.js +107 -0
- package/dist/create.js.map +1 -0
- package/dist/dev/connect-server.d.ts +13 -0
- package/dist/dev/host-entry.d.ts +13 -0
- package/dist/dev/host-entry.js +18330 -0
- package/dist/dev/index.d.ts +45 -0
- package/dist/dev/index.js +14 -0
- package/dist/dev/index.js.map +1 -0
- package/dist/dev/sandbox-entry.d.ts +7 -0
- package/dist/dev/sandbox-entry.js +80 -0
- package/dist/html.d.ts +4 -0
- package/dist/index.d.ts +7 -26
- package/dist/index.js +16 -3
- package/dist/json-render/app.d.ts +22 -0
- package/dist/json-render/app.js +10 -0
- package/dist/json-render/app.js.map +1 -0
- package/dist/json-render/generative-view.d.ts +57 -0
- package/dist/json-render/index.d.ts +10 -0
- package/dist/json-render/index.js +120 -0
- package/dist/json-render/index.js.map +1 -0
- package/dist/json-render/mcp.d.ts +49 -0
- package/dist/json-render/mcp.js +11 -0
- package/dist/json-render/mcp.js.map +1 -0
- package/dist/json-render/server.d.ts +72 -0
- package/dist/json-render/server.js +98 -0
- package/dist/json-render/server.js.map +1 -0
- package/dist/json-render/spec-stream.d.ts +26 -0
- package/dist/json-render/use-spec-stream.d.ts +26 -0
- package/dist/publish.d.ts +10 -0
- package/dist/react/context.d.ts +14 -0
- package/dist/react/create-view.d.ts +8 -0
- package/dist/react/hooks.d.ts +46 -0
- package/dist/react/index.d.ts +3 -0
- package/dist/react/index.js +36 -0
- package/dist/react/index.js.map +1 -0
- package/dist/sandbox/index.d.ts +16 -0
- package/dist/sandbox/index.js +8 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/schema.d.ts +20 -0
- package/dist/server/index.d.ts +73 -0
- package/dist/server/index.js +235 -0
- package/dist/server/index.js.map +1 -0
- package/dist/svelte/index.d.ts +29 -0
- package/dist/svelte/index.js +13 -0
- package/dist/svelte/index.js.map +1 -0
- package/dist/testing/index.d.ts +27 -0
- package/dist/testing/index.js +312 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/render-artifact.d.ts +35 -0
- package/dist/types.d.ts +65 -0
- package/dist/vite/index.d.ts +23 -0
- package/dist/vite/index.js +211 -0
- package/dist/vite/index.js.map +1 -0
- package/dist/vue/index.d.ts +51 -0
- package/dist/vue/index.js +93 -0
- package/dist/vue/index.js.map +1 -0
- package/package.json +162 -20
- package/templates/react/.gitignore.tmpl +4 -0
- package/templates/react/README.md.tmpl +15 -0
- package/templates/react/mcp.fixtures.json.tmpl +4 -0
- package/templates/react/package.json.tmpl +27 -0
- package/templates/react/server.mjs.tmpl +70 -0
- package/templates/react/src/view.tsx.tmpl +160 -0
- package/templates/react/tsconfig.json.tmpl +15 -0
- package/templates/react/vite.config.ts.tmpl +22 -0
- package/templates/svelte/.gitignore.tmpl +4 -0
- package/templates/svelte/README.md.tmpl +14 -0
- package/templates/svelte/mcp.fixtures.json.tmpl +4 -0
- package/templates/svelte/package.json.tmpl +26 -0
- package/templates/svelte/server.mjs.tmpl +70 -0
- package/templates/svelte/src/Dashboard.svelte.tmpl +158 -0
- package/templates/svelte/src/view.ts.tmpl +14 -0
- package/templates/svelte/tsconfig.json.tmpl +14 -0
- package/templates/svelte/vite.config.ts.tmpl +22 -0
- package/templates/vue/.gitignore.tmpl +4 -0
- package/templates/vue/README.md.tmpl +14 -0
- package/templates/vue/mcp.fixtures.json.tmpl +4 -0
- package/templates/vue/package.json.tmpl +26 -0
- package/templates/vue/server.mjs.tmpl +70 -0
- package/templates/vue/src/Dashboard.vue.tmpl +159 -0
- package/templates/vue/src/view.ts.tmpl +14 -0
- package/templates/vue/tsconfig.json.tmpl +15 -0
- package/templates/vue/vite.config.ts.tmpl +22 -0
- package/dist/chunk-BUGGLMNA.js +0 -132
- package/dist/chunk-BUGGLMNA.js.map +0 -1
- package/dist/types-B9JAWm4W.d.ts +0 -62
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export interface DevHostOptions {
|
|
2
|
+
/** Built View HTML. Its `.meta.json` sidecar is read alongside. */
|
|
3
|
+
htmlPath: string;
|
|
4
|
+
/**
|
|
5
|
+
* Named samples, each becoming a button in the host chrome.
|
|
6
|
+
*
|
|
7
|
+
* Without `callTool` the value is delivered straight through as
|
|
8
|
+
* `structuredContent`. With `callTool` it is the tool's *arguments*, and
|
|
9
|
+
* what the view receives is whatever the real tool returns.
|
|
10
|
+
*/
|
|
11
|
+
fixtures?: Record<string, unknown>;
|
|
12
|
+
/**
|
|
13
|
+
* Run a real tool. Supplied when the developer points `dev` at their server,
|
|
14
|
+
* and used both for the fixture buttons and for `tools/call` requests the
|
|
15
|
+
* view makes itself — so app-only tools behave as they will in production.
|
|
16
|
+
*/
|
|
17
|
+
callTool?: (name: string, args: unknown) => Promise<unknown>;
|
|
18
|
+
/** Arguments delivered as `ui/notifications/tool-input`. */
|
|
19
|
+
toolInput?: Record<string, unknown>;
|
|
20
|
+
/** Shown in the host chrome. Defaults to the sidecar's resource name. */
|
|
21
|
+
toolName?: string;
|
|
22
|
+
/** Defaults to 5179, incrementing until a free port is found. */
|
|
23
|
+
hostPort?: number;
|
|
24
|
+
/** Defaults to `hostPort + 1`, incrementing until a free port is found. */
|
|
25
|
+
sandboxPort?: number;
|
|
26
|
+
}
|
|
27
|
+
export interface DevHost {
|
|
28
|
+
hostUrl: string;
|
|
29
|
+
sandboxUrl: string;
|
|
30
|
+
/** Tell connected browsers to reload — call after a rebuild. */
|
|
31
|
+
reload(): void;
|
|
32
|
+
close(): Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
export declare function startDevHost(options: DevHostOptions): Promise<DevHost>;
|
|
35
|
+
/**
|
|
36
|
+
* The MCP Apps sandbox proxy document (spec §8.4), ready to serve from an
|
|
37
|
+
* origin distinct from the host page.
|
|
38
|
+
*
|
|
39
|
+
* Exported because this is the security boundary — it builds the CSP from the
|
|
40
|
+
* sidecar and decides what the view may execute and reach. Anything standing
|
|
41
|
+
* up a host, including the example harnesses in this repo, should serve this
|
|
42
|
+
* rather than keep a copy that drifts from it.
|
|
43
|
+
*/
|
|
44
|
+
export declare function sandboxProxyHtml(hostOrigin: string): Promise<string>;
|
|
45
|
+
export { connectMcpServer, type ConnectedMcpServer } from "./connect-server.js";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
sandboxProxyHtml,
|
|
3
|
+
startDevHost
|
|
4
|
+
} from "../chunk-KWVGW5Q7.js";
|
|
5
|
+
import {
|
|
6
|
+
connectMcpServer
|
|
7
|
+
} from "../chunk-UECZA34Q.js";
|
|
8
|
+
import "../chunk-YJA4H6IB.js";
|
|
9
|
+
export {
|
|
10
|
+
connectMcpServer,
|
|
11
|
+
sandboxProxyHtml,
|
|
12
|
+
startDevHost
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
(() => {
|
|
3
|
+
// src/dev/sandbox-entry.ts
|
|
4
|
+
var config = globalThis.__mountlyMcpSandbox__;
|
|
5
|
+
if (!config) throw new Error("mountly-mcp: sandbox proxy has no host origin");
|
|
6
|
+
var HOST = window.parent;
|
|
7
|
+
var HOST_ORIGIN = config.hostOrigin;
|
|
8
|
+
function buildCspMeta(csp) {
|
|
9
|
+
const join = (values) => (values ?? []).join(" ").trim();
|
|
10
|
+
const connect = join(csp.connectDomains);
|
|
11
|
+
const resource = join(csp.resourceDomains);
|
|
12
|
+
const frame = join(csp.frameDomains);
|
|
13
|
+
const baseUri = join(csp.baseUriDomains);
|
|
14
|
+
const withResource = (directive) => directive + (resource ? ` ${resource}` : "");
|
|
15
|
+
const directives = [
|
|
16
|
+
"default-src 'none'",
|
|
17
|
+
// Inline scripts are allowed because the bundle arrives via srcdoc. Nothing
|
|
18
|
+
// grants eval, matching what hosts enforce, so a view that reaches for it
|
|
19
|
+
// fails here rather than in production.
|
|
20
|
+
withResource("script-src 'self' 'unsafe-inline'"),
|
|
21
|
+
withResource("style-src 'self' 'unsafe-inline'"),
|
|
22
|
+
withResource("img-src 'self' data:"),
|
|
23
|
+
withResource("font-src 'self' data:"),
|
|
24
|
+
withResource("media-src 'self' data:"),
|
|
25
|
+
`connect-src ${connect || "'none'"}`,
|
|
26
|
+
`frame-src ${frame || "'none'"}`,
|
|
27
|
+
`base-uri ${baseUri || "'self'"}`,
|
|
28
|
+
"object-src 'none'"
|
|
29
|
+
];
|
|
30
|
+
return `<meta http-equiv="Content-Security-Policy" content="${directives.join("; ").replace(/"/g, """)}">`;
|
|
31
|
+
}
|
|
32
|
+
function buildAllow(permissions) {
|
|
33
|
+
const parts = [];
|
|
34
|
+
if (permissions.camera) parts.push("camera");
|
|
35
|
+
if (permissions.microphone) parts.push("microphone");
|
|
36
|
+
if (permissions.geolocation) parts.push("geolocation");
|
|
37
|
+
if (permissions.clipboardWrite) parts.push("clipboard-write");
|
|
38
|
+
return parts.join("; ");
|
|
39
|
+
}
|
|
40
|
+
function injectCsp(html, csp) {
|
|
41
|
+
const meta = buildCspMeta(csp);
|
|
42
|
+
if (/<head[^>]*>/i.test(html)) return html.replace(/<head[^>]*>/i, (match) => match + meta);
|
|
43
|
+
return meta + html;
|
|
44
|
+
}
|
|
45
|
+
var inner;
|
|
46
|
+
function bootInner(payload) {
|
|
47
|
+
if (typeof payload.html !== "string" || payload.html.length === 0) return;
|
|
48
|
+
const iframe = document.createElement("iframe");
|
|
49
|
+
iframe.id = "inner";
|
|
50
|
+
iframe.setAttribute("sandbox", payload.sandbox ?? "allow-scripts");
|
|
51
|
+
const allow = buildAllow(payload.permissions ?? {});
|
|
52
|
+
if (allow) iframe.setAttribute("allow", allow);
|
|
53
|
+
iframe.setAttribute("srcdoc", injectCsp(payload.html, payload.csp ?? {}));
|
|
54
|
+
document.body.appendChild(iframe);
|
|
55
|
+
inner = iframe;
|
|
56
|
+
}
|
|
57
|
+
window.addEventListener("message", (event) => {
|
|
58
|
+
const fromHost = event.source === HOST;
|
|
59
|
+
if (fromHost && event.origin !== HOST_ORIGIN) return;
|
|
60
|
+
const message = event.data;
|
|
61
|
+
if (!message || message.jsonrpc !== "2.0") return;
|
|
62
|
+
if (fromHost) {
|
|
63
|
+
if (message.method === "ui/notifications/sandbox-resource-ready") {
|
|
64
|
+
bootInner(message.params ?? {});
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
inner?.contentWindow?.postMessage(message, "*");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (inner && event.source === inner.contentWindow) {
|
|
71
|
+
if (typeof message.method === "string" && message.method.startsWith("ui/notifications/sandbox-"))
|
|
72
|
+
return;
|
|
73
|
+
HOST.postMessage(message, "*");
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
HOST.postMessage(
|
|
77
|
+
{ jsonrpc: "2.0", method: "ui/notifications/sandbox-proxy-ready", params: {} },
|
|
78
|
+
"*"
|
|
79
|
+
);
|
|
80
|
+
})();
|
package/dist/html.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Keep generated JavaScript from terminating the inline script that owns it. */
|
|
2
|
+
export declare function escapeInlineScript(value: string): string;
|
|
3
|
+
/** Serialize a value so no HTML tag can begin inside an inline script. */
|
|
4
|
+
export declare function serializeInlineScriptValue(value: unknown): string;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,26 +1,7 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
3
|
-
export
|
|
4
|
-
export {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
* Spec constants — re-exported from the canonical SDK so they cannot drift.
|
|
9
|
-
* See `@modelcontextprotocol/ext-apps` for the source of truth.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
declare const MCP_APPS_URI_SCHEME: "ui://";
|
|
13
|
-
/**
|
|
14
|
-
* Implementation-specific error codes for mountly-mcp's host/bridge layer.
|
|
15
|
-
* The spec doesn't standardize these; they appear in `notifications/message`
|
|
16
|
-
* params so hosts can categorize widget failures.
|
|
17
|
-
*/
|
|
18
|
-
declare const MCP_ERROR_CODES: {
|
|
19
|
-
readonly INITIALIZE_TIMEOUT: "mountly-mcp/initialize-timeout";
|
|
20
|
-
readonly TOOL_CALL_FAILED: "mountly-mcp/tool-call-failed";
|
|
21
|
-
readonly WIDGET_MOUNT_THREW: "mountly-mcp/widget-mount-threw";
|
|
22
|
-
readonly INVALID_ORIGIN: "mountly-mcp/invalid-origin";
|
|
23
|
-
};
|
|
24
|
-
type McpErrorCode = (typeof MCP_ERROR_CODES)[keyof typeof MCP_ERROR_CODES];
|
|
25
|
-
|
|
26
|
-
export { MCP_APPS_URI_SCHEME, MCP_ERROR_CODES, type McpErrorCode };
|
|
1
|
+
export * from "./types.js";
|
|
2
|
+
export * from "./schema.js";
|
|
3
|
+
export * from "./publish.js";
|
|
4
|
+
export { runBridge, App, PostMessageTransport } from "./bridge/index.js";
|
|
5
|
+
export type { RunBridgeOptions, RunningBridge } from "./bridge/index.js";
|
|
6
|
+
export { sandboxProxyHtml } from "./sandbox/index.js";
|
|
7
|
+
export type { SandboxProxyHtmlOptions } from "./sandbox/index.js";
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
sandboxProxyHtml
|
|
3
|
+
} from "./chunk-6QHKKFO3.js";
|
|
4
|
+
import {
|
|
5
|
+
MCP_VIEW_GLOBAL_KEY,
|
|
6
|
+
getPublishedMcpView,
|
|
7
|
+
publishMcpView
|
|
8
|
+
} from "./chunk-SADNMGP6.js";
|
|
1
9
|
import {
|
|
2
10
|
App,
|
|
3
11
|
PostMessageTransport,
|
|
4
12
|
runBridge
|
|
5
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-JVQZGKBL.js";
|
|
6
14
|
import {
|
|
7
15
|
EXTENSION_ID,
|
|
8
16
|
LATEST_PROTOCOL_VERSION,
|
|
@@ -10,7 +18,8 @@ import {
|
|
|
10
18
|
MCP_ERROR_CODES,
|
|
11
19
|
RESOURCE_MIME_TYPE,
|
|
12
20
|
RESOURCE_URI_META_KEY
|
|
13
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-M4WFJR3C.js";
|
|
22
|
+
import "./chunk-YJA4H6IB.js";
|
|
14
23
|
export {
|
|
15
24
|
App,
|
|
16
25
|
EXTENSION_ID,
|
|
@@ -18,8 +27,12 @@ export {
|
|
|
18
27
|
LATEST_PROTOCOL_VERSION as MCP_APPS_PROTOCOL_VERSION,
|
|
19
28
|
MCP_APPS_URI_SCHEME,
|
|
20
29
|
MCP_ERROR_CODES,
|
|
30
|
+
MCP_VIEW_GLOBAL_KEY,
|
|
21
31
|
PostMessageTransport,
|
|
22
32
|
RESOURCE_URI_META_KEY,
|
|
23
|
-
|
|
33
|
+
getPublishedMcpView,
|
|
34
|
+
publishMcpView,
|
|
35
|
+
runBridge,
|
|
36
|
+
sandboxProxyHtml
|
|
24
37
|
};
|
|
25
38
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { App } from "@modelcontextprotocol/ext-apps";
|
|
2
|
+
import type { Spec } from "@json-render/core";
|
|
3
|
+
export interface UseJsonRenderAppOptions {
|
|
4
|
+
name: string;
|
|
5
|
+
version: string;
|
|
6
|
+
}
|
|
7
|
+
export interface UseJsonRenderAppReturn {
|
|
8
|
+
spec: Spec | null;
|
|
9
|
+
loading: boolean;
|
|
10
|
+
connected: boolean;
|
|
11
|
+
connecting: boolean;
|
|
12
|
+
error: Error | null;
|
|
13
|
+
app: App | null;
|
|
14
|
+
callServerTool: (name: string, args?: Record<string, unknown>) => Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
export declare function useJsonRenderApp(options: UseJsonRenderAppOptions): UseJsonRenderAppReturn;
|
|
17
|
+
export interface BuildAppHtmlOptions {
|
|
18
|
+
title?: string;
|
|
19
|
+
js: string;
|
|
20
|
+
css?: string;
|
|
21
|
+
}
|
|
22
|
+
export declare function buildAppHtml(options: BuildAppHtmlOptions): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { type ComponentMap } from "@json-render/react";
|
|
2
|
+
import type { Catalog, SchemaDefinition } from "@json-render/core";
|
|
3
|
+
import type { App } from "@modelcontextprotocol/ext-apps";
|
|
4
|
+
import type { AdapterOptions } from "mountly/adapter";
|
|
5
|
+
import type { McpView } from "../types.js";
|
|
6
|
+
/** The catalog-data constraint createRenderer infers against. */
|
|
7
|
+
type CatalogData = {
|
|
8
|
+
components: Record<string, {
|
|
9
|
+
props: unknown;
|
|
10
|
+
}>;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Route a generated UI's actions back to the MCP host. Called with the action
|
|
14
|
+
* name, its (resolved) params, and the view-side `App` handle.
|
|
15
|
+
*/
|
|
16
|
+
export type ActionRouter = (name: string, params: Record<string, unknown> | undefined, mcp: App) => void;
|
|
17
|
+
/**
|
|
18
|
+
* Default router: an `ask` action with a string `prompt` param sends a
|
|
19
|
+
* follow-up user turn to the model via `App.sendMessage`. This is the agent
|
|
20
|
+
* loop json-render alone cannot do — it has no concept of an MCP host.
|
|
21
|
+
*/
|
|
22
|
+
export declare const defaultActionRouter: ActionRouter;
|
|
23
|
+
/**
|
|
24
|
+
* Identity helper that types a components map against a catalog (so it can be
|
|
25
|
+
* defined once and reused by both `createGenerativeView` and `createRenderer`)
|
|
26
|
+
* without losing per-component prop inference.
|
|
27
|
+
*
|
|
28
|
+
* ```ts
|
|
29
|
+
* export const components = defineComponents(catalog, {
|
|
30
|
+
* Metric: ({ element }) => <span>{element.props.value}</span>,
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare function defineComponents<TDef extends SchemaDefinition, TCatalog extends CatalogData>(_catalog: Catalog<TDef, TCatalog>, components: ComponentMap<TCatalog["components"]>): ComponentMap<TCatalog["components"]>;
|
|
35
|
+
export interface GenerativeViewOptions<TDef extends SchemaDefinition, TCatalog extends CatalogData> extends AdapterOptions {
|
|
36
|
+
/** The json-render catalog — the vocabulary the agent may compose. */
|
|
37
|
+
catalog: Catalog<TDef, TCatalog>;
|
|
38
|
+
/** Native component implementations for each catalog type. */
|
|
39
|
+
components: ComponentMap<TCatalog["components"]>;
|
|
40
|
+
/**
|
|
41
|
+
* How a generated UI's actions reach the agent. Defaults to
|
|
42
|
+
* {@link defaultActionRouter} (`ask` → `App.sendMessage`).
|
|
43
|
+
*/
|
|
44
|
+
onAction?: ActionRouter;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Turn a json-render catalog + components into a mountly MCP Apps View.
|
|
48
|
+
*
|
|
49
|
+
* Reads the spec from the tool result, renders it natively (resolving `$state`
|
|
50
|
+
* from `spec.state`), and routes actions back to the MCP host.
|
|
51
|
+
*
|
|
52
|
+
* ```ts
|
|
53
|
+
* createGenerativeView({ catalog, components, styles, shadow: true });
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare function createGenerativeView<TDef extends SchemaDefinition, TCatalog extends CatalogData>(options: GenerativeViewOptions<TDef, TCatalog>): McpView;
|
|
57
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { type ActionRouter, type GenerativeViewOptions, createGenerativeView, defaultActionRouter, defineComponents, } from "./generative-view.js";
|
|
2
|
+
export { type JsonRenderToolOptions, type RegisterJsonRenderResourceOptions, type RegisterJsonRenderToolOptions, type CreateJsonRenderMcpAppOptions, createJsonRenderMcpApp, registerJsonRenderTool, registerJsonRenderResource, } from "./mcp.js";
|
|
3
|
+
export { type BuildAppHtmlOptions, type UseJsonRenderAppOptions, type UseJsonRenderAppReturn, buildAppHtml, useJsonRenderApp, } from "./app.js";
|
|
4
|
+
export { createRenderer } from "@json-render/react";
|
|
5
|
+
export type { ComponentMap, ComponentRenderProps } from "@json-render/react";
|
|
6
|
+
export { compileSpecStream, compileTextStreamToSpecs, createJsonRenderTransform, createSpecStreamCompiler, parseSpecStreamLine, specToPatchLines, } from "./spec-stream.js";
|
|
7
|
+
export type { Spec } from "@json-render/core";
|
|
8
|
+
export { type SpecStreamState, type UseSpecStreamOptions, useSpecStream, } from "./use-spec-stream.js";
|
|
9
|
+
export { useChatUI, useUIStream } from "@json-render/react";
|
|
10
|
+
export type { UseUIStreamOptions, UseUIStreamReturn } from "@json-render/react";
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createJsonRenderMcpApp,
|
|
3
|
+
registerJsonRenderResource,
|
|
4
|
+
registerJsonRenderTool
|
|
5
|
+
} from "../chunk-4HC3OWAQ.js";
|
|
6
|
+
import {
|
|
7
|
+
compileSpecStream,
|
|
8
|
+
compileTextStreamToSpecs,
|
|
9
|
+
createJsonRenderTransform,
|
|
10
|
+
createSpecStreamCompiler,
|
|
11
|
+
parseSpecStreamLine,
|
|
12
|
+
specToPatchLines
|
|
13
|
+
} from "../chunk-5EHNJCMF.js";
|
|
14
|
+
import {
|
|
15
|
+
createMcpView,
|
|
16
|
+
useMcpApp,
|
|
17
|
+
useToolResult
|
|
18
|
+
} from "../chunk-AEVQKFXX.js";
|
|
19
|
+
import "../chunk-SADNMGP6.js";
|
|
20
|
+
import {
|
|
21
|
+
buildAppHtml,
|
|
22
|
+
useJsonRenderApp
|
|
23
|
+
} from "../chunk-33DMFKKD.js";
|
|
24
|
+
import "../chunk-YJA4H6IB.js";
|
|
25
|
+
|
|
26
|
+
// src/json-render/generative-view.tsx
|
|
27
|
+
import { createElement } from "react";
|
|
28
|
+
import { createRenderer } from "@json-render/react";
|
|
29
|
+
var defaultActionRouter = (name, params, mcp) => {
|
|
30
|
+
if (name !== "ask") return;
|
|
31
|
+
const prompt = params?.prompt;
|
|
32
|
+
const text = typeof prompt === "string" ? prompt : "";
|
|
33
|
+
if (text) {
|
|
34
|
+
void mcp.sendMessage({ role: "user", content: [{ type: "text", text }] });
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
function defineComponents(_catalog, components) {
|
|
38
|
+
return components;
|
|
39
|
+
}
|
|
40
|
+
function createGenerativeView(options) {
|
|
41
|
+
const { catalog, components, onAction = defaultActionRouter, ...adapter } = options;
|
|
42
|
+
const Rendered = createRenderer(catalog, components);
|
|
43
|
+
function GenerativeView() {
|
|
44
|
+
const mcp = useMcpApp();
|
|
45
|
+
const result = useToolResult();
|
|
46
|
+
const spec = result?.structuredContent?.spec ?? null;
|
|
47
|
+
if (!spec) return null;
|
|
48
|
+
return createElement(Rendered, {
|
|
49
|
+
spec,
|
|
50
|
+
state: spec.state,
|
|
51
|
+
onAction: (name, params) => onAction(name, params, mcp)
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
return createMcpView(GenerativeView, adapter);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// src/json-render/index.ts
|
|
58
|
+
import { createRenderer as createRenderer2 } from "@json-render/react";
|
|
59
|
+
|
|
60
|
+
// src/json-render/use-spec-stream.ts
|
|
61
|
+
import { useEffect, useState } from "react";
|
|
62
|
+
import { createSpecStreamCompiler as createSpecStreamCompiler2 } from "@json-render/core";
|
|
63
|
+
function useSpecStream(target, options = {}) {
|
|
64
|
+
const { intervalMs = 90 } = options;
|
|
65
|
+
const [spec, setSpec] = useState(null);
|
|
66
|
+
const [loading, setLoading] = useState(false);
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (!target) {
|
|
69
|
+
setSpec(null);
|
|
70
|
+
setLoading(false);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
let cancelled = false;
|
|
74
|
+
const compiler = createSpecStreamCompiler2();
|
|
75
|
+
const lines = specToPatchLines(target);
|
|
76
|
+
setLoading(true);
|
|
77
|
+
void (async () => {
|
|
78
|
+
for (const line of lines) {
|
|
79
|
+
if (cancelled) return;
|
|
80
|
+
const { result } = compiler.push(`${line}
|
|
81
|
+
`);
|
|
82
|
+
setSpec({ ...result });
|
|
83
|
+
if (intervalMs > 0) {
|
|
84
|
+
await new Promise((r) => setTimeout(r, intervalMs));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (cancelled) return;
|
|
88
|
+
setSpec(compiler.getResult());
|
|
89
|
+
setLoading(false);
|
|
90
|
+
})();
|
|
91
|
+
return () => {
|
|
92
|
+
cancelled = true;
|
|
93
|
+
};
|
|
94
|
+
}, [target, intervalMs]);
|
|
95
|
+
return { spec, state: spec?.state, loading };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// src/json-render/index.ts
|
|
99
|
+
import { useChatUI, useUIStream } from "@json-render/react";
|
|
100
|
+
export {
|
|
101
|
+
buildAppHtml,
|
|
102
|
+
compileSpecStream,
|
|
103
|
+
compileTextStreamToSpecs,
|
|
104
|
+
createGenerativeView,
|
|
105
|
+
createJsonRenderMcpApp,
|
|
106
|
+
createJsonRenderTransform,
|
|
107
|
+
createRenderer2 as createRenderer,
|
|
108
|
+
createSpecStreamCompiler,
|
|
109
|
+
defaultActionRouter,
|
|
110
|
+
defineComponents,
|
|
111
|
+
parseSpecStreamLine,
|
|
112
|
+
registerJsonRenderResource,
|
|
113
|
+
registerJsonRenderTool,
|
|
114
|
+
specToPatchLines,
|
|
115
|
+
useChatUI,
|
|
116
|
+
useJsonRenderApp,
|
|
117
|
+
useSpecStream,
|
|
118
|
+
useUIStream
|
|
119
|
+
};
|
|
120
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/json-render/generative-view.tsx","../../src/json-render/index.ts","../../src/json-render/use-spec-stream.ts"],"sourcesContent":["import { createElement } from \"react\";\nimport { type ComponentMap, createRenderer } from \"@json-render/react\";\nimport type { Catalog, SchemaDefinition, Spec } from \"@json-render/core\";\nimport { createMcpView, useMcpApp, useToolResult } from \"../react/index.js\";\nimport type { App } from \"@modelcontextprotocol/ext-apps\";\nimport type { AdapterOptions } from \"mountly/adapter\";\nimport type { McpView } from \"../types.js\";\n\n/** The catalog-data constraint createRenderer infers against. */\ntype CatalogData = { components: Record<string, { props: unknown }> };\n\n/**\n * Route a generated UI's actions back to the MCP host. Called with the action\n * name, its (resolved) params, and the view-side `App` handle.\n */\nexport type ActionRouter = (\n name: string,\n params: Record<string, unknown> | undefined,\n mcp: App,\n) => void;\n\n/**\n * Default router: an `ask` action with a string `prompt` param sends a\n * follow-up user turn to the model via `App.sendMessage`. This is the agent\n * loop json-render alone cannot do — it has no concept of an MCP host.\n */\nexport const defaultActionRouter: ActionRouter = (name, params, mcp) => {\n if (name !== \"ask\") return;\n const prompt = params?.prompt;\n const text = typeof prompt === \"string\" ? prompt : \"\";\n if (text) {\n void mcp.sendMessage({ role: \"user\", content: [{ type: \"text\", text }] });\n }\n};\n\n/**\n * Identity helper that types a components map against a catalog (so it can be\n * defined once and reused by both `createGenerativeView` and `createRenderer`)\n * without losing per-component prop inference.\n *\n * ```ts\n * export const components = defineComponents(catalog, {\n * Metric: ({ element }) => <span>{element.props.value}</span>,\n * });\n * ```\n */\nexport function defineComponents<TDef extends SchemaDefinition, TCatalog extends CatalogData>(\n _catalog: Catalog<TDef, TCatalog>,\n components: ComponentMap<TCatalog[\"components\"]>,\n): ComponentMap<TCatalog[\"components\"]> {\n return components;\n}\n\nexport interface GenerativeViewOptions<\n TDef extends SchemaDefinition,\n TCatalog extends CatalogData,\n> extends AdapterOptions {\n /** The json-render catalog — the vocabulary the agent may compose. */\n catalog: Catalog<TDef, TCatalog>;\n /** Native component implementations for each catalog type. */\n components: ComponentMap<TCatalog[\"components\"]>;\n /**\n * How a generated UI's actions reach the agent. Defaults to\n * {@link defaultActionRouter} (`ask` → `App.sendMessage`).\n */\n onAction?: ActionRouter;\n}\n\ninterface ToolResultShape {\n structuredContent?: { spec?: Spec };\n}\n\n/**\n * Turn a json-render catalog + components into a mountly MCP Apps View.\n *\n * Reads the spec from the tool result, renders it natively (resolving `$state`\n * from `spec.state`), and routes actions back to the MCP host.\n *\n * ```ts\n * createGenerativeView({ catalog, components, styles, shadow: true });\n * ```\n */\nexport function createGenerativeView<TDef extends SchemaDefinition, TCatalog extends CatalogData>(\n options: GenerativeViewOptions<TDef, TCatalog>,\n): McpView {\n const { catalog, components, onAction = defaultActionRouter, ...adapter } = options;\n const Rendered = createRenderer(catalog, components);\n\n function GenerativeView() {\n const mcp = useMcpApp();\n const result = useToolResult<ToolResultShape>();\n const spec = result?.structuredContent?.spec ?? null;\n if (!spec) return null;\n return createElement(Rendered, {\n spec,\n state: spec.state,\n onAction: (name: string, params?: Record<string, unknown>) => onAction(name, params, mcp),\n });\n }\n\n return createMcpView(GenerativeView, adapter);\n}\n","export {\n type ActionRouter,\n type GenerativeViewOptions,\n createGenerativeView,\n defaultActionRouter,\n defineComponents,\n} from \"./generative-view.js\";\nexport {\n type JsonRenderToolOptions,\n type RegisterJsonRenderResourceOptions,\n type RegisterJsonRenderToolOptions,\n type CreateJsonRenderMcpAppOptions,\n createJsonRenderMcpApp,\n registerJsonRenderTool,\n registerJsonRenderResource,\n} from \"./mcp.js\";\nexport {\n type BuildAppHtmlOptions,\n type UseJsonRenderAppOptions,\n type UseJsonRenderAppReturn,\n buildAppHtml,\n useJsonRenderApp,\n} from \"./app.js\";\n\n// Convenience re-exports for rendering the same catalog natively (non-MCP) —\n// previews, tests, or a plain mountly feature. Pair with `mountly-react`'s\n// `createWidget` to mount a spec outside an MCP host.\nexport { createRenderer } from \"@json-render/react\";\nexport type { ComponentMap, ComponentRenderProps } from \"@json-render/react\";\n\n// Streaming primitives (json-render's own): replay a known spec as a patch\n// stream, compile patches back into a progressively-built spec, and the AI-SDK\n// transform that classifies a model's UI-message stream into spec patches.\nexport {\n compileSpecStream,\n compileTextStreamToSpecs,\n createJsonRenderTransform,\n createSpecStreamCompiler,\n parseSpecStreamLine,\n specToPatchLines,\n} from \"./spec-stream.js\";\nexport type { Spec } from \"@json-render/core\";\n\n// --- Two ways to stream ---\n//\n// Replay (known spec): `useSpecStream` takes a finished spec — e.g. the one an\n// MCP tool delivered as `structuredContent` — and replays it as a live build,\n// with the compiler, loading flag, and cancellation included.\nexport {\n type SpecStreamState,\n type UseSpecStreamOptions,\n useSpecStream,\n} from \"./use-spec-stream.js\";\n\n// Live (from a model): `useUIStream` / `useChatUI` are json-render's own client\n// hooks — POST a prompt to an endpoint that streams JSONL patches (see\n// `streamSpec` in `mountly-mcp/json-render/server`) and render the spec as it\n// builds. Re-exported so the live path is one import away.\nexport { useChatUI, useUIStream } from \"@json-render/react\";\nexport type { UseUIStreamOptions, UseUIStreamReturn } from \"@json-render/react\";\n","import { useEffect, useState } from \"react\";\nimport type { Spec } from \"@json-render/core\";\nimport { createSpecStreamCompiler } from \"@json-render/core\";\nimport { specToPatchLines } from \"./spec-stream.js\";\n\nexport interface UseSpecStreamOptions {\n /** Delay between patches, ms. Default 90. Set 0 to render instantly. */\n intervalMs?: number;\n}\n\nexport interface SpecStreamState {\n /** The progressively-built spec (partial while streaming, full when done). */\n spec: Spec | null;\n /** Convenience: `spec?.state`, to pass straight to the renderer. */\n state: Record<string, unknown> | undefined;\n /** True while patches are still being applied. */\n loading: boolean;\n}\n\n/**\n * Replay a finished spec as a live json-render stream — and own all the\n * ceremony. Give it the target spec; it scaffolds a `createSpecStreamCompiler`,\n * replays the patches with a delay, exposes the partial spec + `loading` after\n * each step, and cancels cleanly when the target changes (so a self-driving UI\n * that swaps specs mid-stream just works). Re-streams whenever `target` changes.\n *\n * ```tsx\n * const { spec, state, loading } = useSpecStream(specs[view]);\n * return <Renderer spec={spec} state={state} loading={loading} onAction={...} />;\n * ```\n */\nexport function useSpecStream(\n target: Spec | null | undefined,\n options: UseSpecStreamOptions = {},\n): SpecStreamState {\n const { intervalMs = 90 } = options;\n const [spec, setSpec] = useState<Spec | null>(null);\n const [loading, setLoading] = useState(false);\n\n useEffect(() => {\n if (!target) {\n setSpec(null);\n setLoading(false);\n return;\n }\n let cancelled = false;\n const compiler = createSpecStreamCompiler<Spec>();\n const lines = specToPatchLines(target);\n setLoading(true);\n\n void (async () => {\n for (const line of lines) {\n if (cancelled) return;\n const { result } = compiler.push(`${line}\\n`);\n setSpec({ ...result });\n if (intervalMs > 0) {\n await new Promise((r) => setTimeout(r, intervalMs));\n }\n }\n if (cancelled) return;\n setSpec(compiler.getResult());\n setLoading(false);\n })();\n\n return () => {\n cancelled = true;\n };\n }, [target, intervalMs]);\n\n return { spec, state: spec?.state, loading };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,qBAAqB;AAC9B,SAA4B,sBAAsB;AAyB3C,IAAM,sBAAoC,CAAC,MAAM,QAAQ,QAAQ;AACtE,MAAI,SAAS,MAAO;AACpB,QAAM,SAAS,QAAQ;AACvB,QAAM,OAAO,OAAO,WAAW,WAAW,SAAS;AACnD,MAAI,MAAM;AACR,SAAK,IAAI,YAAY,EAAE,MAAM,QAAQ,SAAS,CAAC,EAAE,MAAM,QAAQ,KAAK,CAAC,EAAE,CAAC;AAAA,EAC1E;AACF;AAaO,SAAS,iBACd,UACA,YACsC;AACtC,SAAO;AACT;AA+BO,SAAS,qBACd,SACS;AACT,QAAM,EAAE,SAAS,YAAY,WAAW,qBAAqB,GAAG,QAAQ,IAAI;AAC5E,QAAM,WAAW,eAAe,SAAS,UAAU;AAEnD,WAAS,iBAAiB;AACxB,UAAM,MAAM,UAAU;AACtB,UAAM,SAAS,cAA+B;AAC9C,UAAM,OAAO,QAAQ,mBAAmB,QAAQ;AAChD,QAAI,CAAC,KAAM,QAAO;AAClB,WAAO,cAAc,UAAU;AAAA,MAC7B;AAAA,MACA,OAAO,KAAK;AAAA,MACZ,UAAU,CAAC,MAAc,WAAqC,SAAS,MAAM,QAAQ,GAAG;AAAA,IAC1F,CAAC;AAAA,EACH;AAEA,SAAO,cAAc,gBAAgB,OAAO;AAC9C;;;AC1EA,SAAS,kBAAAA,uBAAsB;;;AC3B/B,SAAS,WAAW,gBAAgB;AAEpC,SAAS,4BAAAC,iCAAgC;AA6BlC,SAAS,cACd,QACA,UAAgC,CAAC,GAChB;AACjB,QAAM,EAAE,aAAa,GAAG,IAAI;AAC5B,QAAM,CAAC,MAAM,OAAO,IAAI,SAAsB,IAAI;AAClD,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAE5C,YAAU,MAAM;AACd,QAAI,CAAC,QAAQ;AACX,cAAQ,IAAI;AACZ,iBAAW,KAAK;AAChB;AAAA,IACF;AACA,QAAI,YAAY;AAChB,UAAM,WAAWC,0BAA+B;AAChD,UAAM,QAAQ,iBAAiB,MAAM;AACrC,eAAW,IAAI;AAEf,UAAM,YAAY;AAChB,iBAAW,QAAQ,OAAO;AACxB,YAAI,UAAW;AACf,cAAM,EAAE,OAAO,IAAI,SAAS,KAAK,GAAG,IAAI;AAAA,CAAI;AAC5C,gBAAQ,EAAE,GAAG,OAAO,CAAC;AACrB,YAAI,aAAa,GAAG;AAClB,gBAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,UAAU,CAAC;AAAA,QACpD;AAAA,MACF;AACA,UAAI,UAAW;AACf,cAAQ,SAAS,UAAU,CAAC;AAC5B,iBAAW,KAAK;AAAA,IAClB,GAAG;AAEH,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,QAAQ,UAAU,CAAC;AAEvB,SAAO,EAAE,MAAM,OAAO,MAAM,OAAO,QAAQ;AAC7C;;;ADZA,SAAS,WAAW,mBAAmB;","names":["createRenderer","createSpecStreamCompiler","createSpecStreamCompiler"]}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { McpUiToolVisibility } from "@modelcontextprotocol/ext-apps";
|
|
3
|
+
import type { Catalog } from "@json-render/core";
|
|
4
|
+
import type { RunningMcpAppServer } from "../server/index.js";
|
|
5
|
+
export interface JsonRenderToolOptions {
|
|
6
|
+
/** MCP tool name. */
|
|
7
|
+
name?: string;
|
|
8
|
+
/** Human-readable tool title. */
|
|
9
|
+
title?: string;
|
|
10
|
+
/** Tool description for model selection. */
|
|
11
|
+
description?: string;
|
|
12
|
+
/** ui:// resource linked to this tool. */
|
|
13
|
+
resourceUri?: string;
|
|
14
|
+
/** Tool visibility in MCP Apps hosts. */
|
|
15
|
+
visibility?: McpUiToolVisibility | ReadonlyArray<McpUiToolVisibility>;
|
|
16
|
+
/** Optional explicit input schema override. */
|
|
17
|
+
inputSchema?: object;
|
|
18
|
+
}
|
|
19
|
+
export interface RegisterJsonRenderResourceOptions {
|
|
20
|
+
resourceUri?: string;
|
|
21
|
+
name?: string;
|
|
22
|
+
description?: string;
|
|
23
|
+
html: string;
|
|
24
|
+
}
|
|
25
|
+
export interface RegisterJsonRenderToolOptions {
|
|
26
|
+
catalog: Catalog;
|
|
27
|
+
name?: string;
|
|
28
|
+
title?: string;
|
|
29
|
+
description?: string;
|
|
30
|
+
resourceUri?: string;
|
|
31
|
+
visibility?: McpUiToolVisibility | ReadonlyArray<McpUiToolVisibility>;
|
|
32
|
+
inputSchema?: object;
|
|
33
|
+
}
|
|
34
|
+
export interface CreateJsonRenderMcpAppOptions {
|
|
35
|
+
name: string;
|
|
36
|
+
version: string;
|
|
37
|
+
catalog: Catalog;
|
|
38
|
+
html: string;
|
|
39
|
+
tool?: JsonRenderToolOptions;
|
|
40
|
+
}
|
|
41
|
+
export declare function registerJsonRenderResource(server: McpServer, options: RegisterJsonRenderResourceOptions): {
|
|
42
|
+
uri: string;
|
|
43
|
+
remove(): void;
|
|
44
|
+
};
|
|
45
|
+
export declare function registerJsonRenderTool(server: McpServer, options: RegisterJsonRenderToolOptions): {
|
|
46
|
+
name: string;
|
|
47
|
+
remove(): void;
|
|
48
|
+
};
|
|
49
|
+
export declare function createJsonRenderMcpApp(options: CreateJsonRenderMcpAppOptions): RunningMcpAppServer;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { type LanguageModel } from "ai";
|
|
2
|
+
import { type Catalog, type Spec, type SpecValidationIssues } from "@json-render/core";
|
|
3
|
+
export { compileTextStreamToSpecs } from "./spec-stream.js";
|
|
4
|
+
export interface StreamSpecOptions {
|
|
5
|
+
/** The catalog the spec must conform to (drives the system prompt). */
|
|
6
|
+
catalog: Catalog;
|
|
7
|
+
/** Any AI SDK model — `ollama(...)`, `google(...)`, `groq(...)`, etc. */
|
|
8
|
+
model: LanguageModel;
|
|
9
|
+
/** The natural-language UI request. */
|
|
10
|
+
prompt: string;
|
|
11
|
+
/** Optional runtime state to ground the generation. */
|
|
12
|
+
state?: Record<string, unknown>;
|
|
13
|
+
/** Sampling temperature. Default 0.2 — low for consistent JSONL output. */
|
|
14
|
+
temperature?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface SpecResult {
|
|
17
|
+
/** The compiled, repaired spec. */
|
|
18
|
+
spec: Spec;
|
|
19
|
+
/** Raw model output (JSONL patches). */
|
|
20
|
+
raw: string;
|
|
21
|
+
/** Repairs applied by `autoFixSpec`: props-vs-element fields, and dangling child references. */
|
|
22
|
+
fixes: string[];
|
|
23
|
+
/** Validation issues against the catalog. */
|
|
24
|
+
issues: SpecValidationIssues;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The handle {@link streamSpec} returns — one object, two ways to consume it
|
|
28
|
+
* (mirrors the AI SDK's `streamText` result):
|
|
29
|
+
*
|
|
30
|
+
* - **iterate** `partialSpecStream` to watch the UI build itself, element by
|
|
31
|
+
* element, as the model emits patches;
|
|
32
|
+
* - **await** `spec` (or `result` for everything) for the final, repaired spec
|
|
33
|
+
* — no need to touch the stream.
|
|
34
|
+
*
|
|
35
|
+
* The model request starts immediately; the promises resolve when it completes,
|
|
36
|
+
* whether or not you iterate the stream.
|
|
37
|
+
*/
|
|
38
|
+
export interface SpecStream {
|
|
39
|
+
/** Live: each value is the progressively-built spec (the UI assembling itself). */
|
|
40
|
+
partialSpecStream: AsyncIterable<Spec>;
|
|
41
|
+
/** The final repaired + validated result. */
|
|
42
|
+
result: Promise<SpecResult>;
|
|
43
|
+
/** Convenience: the final repaired spec only. */
|
|
44
|
+
spec: Promise<Spec>;
|
|
45
|
+
/** Convenience: the raw JSONL the model emitted. */
|
|
46
|
+
raw: Promise<string>;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Generate a catalog-constrained json-render spec from any AI SDK model — the
|
|
50
|
+
* one entry point for turning a prompt into UI.
|
|
51
|
+
*
|
|
52
|
+
* Uses `streamText` + json-render's stream compiler (no JSON-mode or
|
|
53
|
+
* tool-calling, so a small local model can drive it). The returned
|
|
54
|
+
* {@link SpecStream} is both **awaitable** for the final spec and **iterable**
|
|
55
|
+
* for the live build:
|
|
56
|
+
*
|
|
57
|
+
* ```ts
|
|
58
|
+
* import { streamSpec } from "mountly-mcp/json-render/server";
|
|
59
|
+
* import { ollama } from "ai-sdk-ollama";
|
|
60
|
+
*
|
|
61
|
+
* // Blocking (e.g. an MCP tool returning structuredContent):
|
|
62
|
+
* const { spec } = await streamSpec({ catalog, model: ollama("granite4.1:3b"), prompt }).result;
|
|
63
|
+
*
|
|
64
|
+
* // Live (watch it build):
|
|
65
|
+
* const ui = streamSpec({ catalog, model, prompt });
|
|
66
|
+
* for await (const partial of ui.partialSpecStream) render(partial);
|
|
67
|
+
* const { spec, issues } = await ui.result;
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
70
|
+
* The promise rejects if the model never produces a spec with a resolvable root.
|
|
71
|
+
*/
|
|
72
|
+
export declare function streamSpec(options: StreamSpecOptions): SpecStream;
|