mountly-mcp 4.1.0 → 4.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.
- package/GLOSSARY.md +1 -0
- package/README.md +123 -12
- package/dist/bridge/iframe-entry.js +7 -7
- package/dist/build/emit-meta.d.ts +3 -0
- package/dist/build/index.d.ts +3 -0
- package/dist/build/index.js +1 -1
- package/dist/chunk-4SZHJ4MK.js +9 -0
- package/dist/chunk-4SZHJ4MK.js.map +1 -0
- package/dist/{chunk-KWVGW5Q7.js → chunk-GN2IQYV3.js} +1 -1
- package/dist/chunk-GN2IQYV3.js.map +1 -0
- package/dist/{chunk-SXF23BZD.js → chunk-HIAIQVK5.js} +4 -7
- package/dist/chunk-HIAIQVK5.js.map +1 -0
- package/dist/{chunk-MTJDRWGD.js → chunk-IDGTP2NI.js} +4 -2
- package/dist/chunk-IDGTP2NI.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/compose/index.d.ts +48 -0
- package/dist/compose/index.js +141 -0
- package/dist/compose/index.js.map +1 -0
- package/dist/dev/host-entry.js +13 -6
- package/dist/dev/index.js +1 -1
- package/dist/{doctor-B54H6CRN.js → doctor-4MTC6Y4X.js} +38 -3
- package/dist/doctor-4MTC6Y4X.js.map +1 -0
- package/dist/index.js +3 -3
- package/dist/json-render/index.js +6 -5
- package/dist/json-render/index.js.map +1 -1
- package/dist/openai/server.d.ts +16 -0
- package/dist/openai/server.js +20 -0
- package/dist/openai/server.js.map +1 -0
- package/dist/react/index.js +4 -2
- package/dist/react/openai-extensions.d.ts +6 -0
- package/dist/react/openai-extensions.js +25 -0
- package/dist/react/openai-extensions.js.map +1 -0
- package/dist/server/index.js +11 -6
- package/dist/server/index.js.map +1 -1
- package/dist/types.d.ts +3 -0
- package/dist/vite/index.js +1 -1
- package/package.json +25 -3
- package/dist/chunk-KWVGW5Q7.js.map +0 -1
- package/dist/chunk-MTJDRWGD.js.map +0 -1
- package/dist/chunk-SXF23BZD.js.map +0 -1
- package/dist/doctor-B54H6CRN.js.map +0 -1
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// src/compose/index.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import {
|
|
4
|
+
RESOURCE_MIME_TYPE,
|
|
5
|
+
registerAppResource,
|
|
6
|
+
registerAppTool
|
|
7
|
+
} from "@modelcontextprotocol/ext-apps/server";
|
|
8
|
+
var DEFAULT_RESOURCE_URI = "ui://mountly/compose.html";
|
|
9
|
+
var DEFAULT_TOOL_NAME = "show_page";
|
|
10
|
+
function composeViewHtml(options) {
|
|
11
|
+
const importMap = JSON.stringify({ imports: options.imports }).replace(/</g, "\\u003c");
|
|
12
|
+
const styles = (options.styles ?? "").replace(/<\/style/gi, "<\\/style");
|
|
13
|
+
const title = (options.title ?? "Page").replace(/[<&]/g, "");
|
|
14
|
+
return `<!doctype html>
|
|
15
|
+
<html lang="en">
|
|
16
|
+
<head>
|
|
17
|
+
<meta charset="utf-8" />
|
|
18
|
+
<title>${title}</title>
|
|
19
|
+
<script type="importmap">${importMap}</script>
|
|
20
|
+
<style>${styles}</style>
|
|
21
|
+
</head>
|
|
22
|
+
<body>
|
|
23
|
+
<main id="page"></main>
|
|
24
|
+
<script type="module">
|
|
25
|
+
import { App } from "@modelcontextprotocol/ext-apps";
|
|
26
|
+
import { connectView } from "mountly-compose";
|
|
27
|
+
|
|
28
|
+
const app = new App({ name: "mountly-compose", version: "1.0.0" });
|
|
29
|
+
connectView(app, document.querySelector("#page"), {
|
|
30
|
+
request: "Show the updated page with ${DEFAULT_TOOL_NAME}.",
|
|
31
|
+
});
|
|
32
|
+
await app.connect();
|
|
33
|
+
</script>
|
|
34
|
+
</body>
|
|
35
|
+
</html>
|
|
36
|
+
`;
|
|
37
|
+
}
|
|
38
|
+
function originsOf(options) {
|
|
39
|
+
const urls = [
|
|
40
|
+
...Object.values(options.imports),
|
|
41
|
+
...options.catalog.elements.flatMap((el) => el.embed ? [el.embed] : [])
|
|
42
|
+
];
|
|
43
|
+
const origins = /* @__PURE__ */ new Set();
|
|
44
|
+
for (const url of urls) {
|
|
45
|
+
try {
|
|
46
|
+
origins.add(new URL(url).origin);
|
|
47
|
+
} catch {
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return [...origins];
|
|
51
|
+
}
|
|
52
|
+
function tagsOf(node, into = /* @__PURE__ */ new Set()) {
|
|
53
|
+
into.add(node.tag);
|
|
54
|
+
for (const child of node.children ?? []) tagsOf(child, into);
|
|
55
|
+
return into;
|
|
56
|
+
}
|
|
57
|
+
function viewPayload(catalog, page) {
|
|
58
|
+
return { page, elements: catalog.elements, actions: catalog.actions };
|
|
59
|
+
}
|
|
60
|
+
function registerComposeApp(server, options) {
|
|
61
|
+
const { catalog } = options;
|
|
62
|
+
const name = options.name ?? DEFAULT_TOOL_NAME;
|
|
63
|
+
const resourceUri = options.resourceUri ?? DEFAULT_RESOURCE_URI;
|
|
64
|
+
if (!resourceUri.startsWith("ui://")) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
`mountly-mcp/compose: resourceUri must use 'ui://' (received '${resourceUri}')`
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
const origins = originsOf(options);
|
|
70
|
+
const csp = { connectDomains: origins, resourceDomains: origins, frameDomains: [] };
|
|
71
|
+
const html = composeViewHtml(options);
|
|
72
|
+
registerAppResource(
|
|
73
|
+
server,
|
|
74
|
+
"compose_view",
|
|
75
|
+
resourceUri,
|
|
76
|
+
{
|
|
77
|
+
mimeType: RESOURCE_MIME_TYPE,
|
|
78
|
+
description: "A page composed from teams' custom elements.",
|
|
79
|
+
_meta: { ui: { prefersBorder: false, csp } }
|
|
80
|
+
},
|
|
81
|
+
async () => ({
|
|
82
|
+
contents: [
|
|
83
|
+
{ uri: resourceUri, mimeType: RESOURCE_MIME_TYPE, text: html, _meta: { ui: { csp } } }
|
|
84
|
+
]
|
|
85
|
+
})
|
|
86
|
+
);
|
|
87
|
+
const description = [
|
|
88
|
+
`Show the user a page built from the components below. Call it with { "page": <tree> }.`,
|
|
89
|
+
`To change the page, call it again with the whole updated page.`,
|
|
90
|
+
options.instructions ?? "",
|
|
91
|
+
"",
|
|
92
|
+
catalog.prompt()
|
|
93
|
+
].filter((line, index) => line || index > 2).join("\n");
|
|
94
|
+
registerAppTool(
|
|
95
|
+
server,
|
|
96
|
+
name,
|
|
97
|
+
{
|
|
98
|
+
title: "Show page",
|
|
99
|
+
description,
|
|
100
|
+
inputSchema: { page: z.unknown().describe("The page as a tree: { tag, attrs, children }.") },
|
|
101
|
+
_meta: { ui: { resourceUri, visibility: ["model", "app"] } }
|
|
102
|
+
},
|
|
103
|
+
(async (args) => {
|
|
104
|
+
const errors = catalog.validate(args.page);
|
|
105
|
+
let page = args.page;
|
|
106
|
+
let note = "";
|
|
107
|
+
if (errors.length) {
|
|
108
|
+
const { tree, dropped } = catalog.repair(args.page);
|
|
109
|
+
if (!tree || catalog.validate(tree).length) {
|
|
110
|
+
return {
|
|
111
|
+
isError: true,
|
|
112
|
+
content: [
|
|
113
|
+
{
|
|
114
|
+
type: "text",
|
|
115
|
+
text: `The page cannot be shown:
|
|
116
|
+
${errors.join("\n")}
|
|
117
|
+
Fix these and call ${name} again.`
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
page = tree;
|
|
123
|
+
note = ` Removed what the catalog does not allow: ${dropped.join("; ")}.`;
|
|
124
|
+
}
|
|
125
|
+
const hostTags = new Set(
|
|
126
|
+
catalog.elements.filter((el) => el.team === "host").map((el) => el.tag)
|
|
127
|
+
);
|
|
128
|
+
const tags = [...tagsOf(page)].filter((tag) => !hostTags.has(tag));
|
|
129
|
+
return {
|
|
130
|
+
content: [{ type: "text", text: `Showing ${tags.join(", ") || "the page"}.${note}` }],
|
|
131
|
+
structuredContent: viewPayload(catalog, page)
|
|
132
|
+
};
|
|
133
|
+
})
|
|
134
|
+
);
|
|
135
|
+
return { tool: name, resourceUri };
|
|
136
|
+
}
|
|
137
|
+
export {
|
|
138
|
+
composeViewHtml,
|
|
139
|
+
registerComposeApp
|
|
140
|
+
};
|
|
141
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/compose/index.ts"],"sourcesContent":["/**\n * Show a page composed from many teams' custom elements inside an MCP host.\n *\n * The agent is the composer: `show_page` carries the catalog's prompt as its\n * description, the agent calls it with a tree, the server validates (or\n * repairs) it, and the `ui://` view renders it with `mountly-compose` — each\n * team's code loading on first use. When the user acts in a widget, the view\n * sends the agent its next turn, with the current page, so it edits rather than\n * starts over.\n */\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport {\n RESOURCE_MIME_TYPE,\n registerAppResource,\n registerAppTool,\n} from \"@modelcontextprotocol/ext-apps/server\";\nimport type { Catalog, Tree } from \"mountly-compose\";\n\nconst DEFAULT_RESOURCE_URI = \"ui://mountly/compose.html\";\nconst DEFAULT_TOOL_NAME = \"show_page\";\n\nexport interface ComposeViewOptions {\n /**\n * The view's import map. Must map `mountly-compose` and\n * `@modelcontextprotocol/ext-apps` (its `app-with-deps` build), plus\n * whatever the teams' peer embeds import: `react`, `react/jsx-runtime`,\n * `react-dom/client`, `mountly-react`, `mountly/embed`.\n */\n imports: Record<string, string>;\n /** The page's own CSS: host layout (`ui-stack`, `ui-grid`, `ui-note`) and design tokens. */\n styles?: string;\n /** Document title. */\n title?: string;\n}\n\nexport interface RegisterComposeAppOptions extends ComposeViewOptions {\n catalog: Catalog;\n /** MCP tool name. Default `show_page`. */\n name?: string;\n /** `ui://` resource for the view. */\n resourceUri?: string;\n /** Appended to the tool description: what the agent may fill ids from, house rules. */\n instructions?: string;\n}\n\n/** The view HTML: an import map, the host's CSS, and a module that renders tool results. */\nexport function composeViewHtml(options: ComposeViewOptions): string {\n const importMap = JSON.stringify({ imports: options.imports }).replace(/</g, \"\\\\u003c\");\n const styles = (options.styles ?? \"\").replace(/<\\/style/gi, \"<\\\\/style\");\n const title = (options.title ?? \"Page\").replace(/[<&]/g, \"\");\n return `<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <title>${title}</title>\n <script type=\"importmap\">${importMap}</script>\n <style>${styles}</style>\n </head>\n <body>\n <main id=\"page\"></main>\n <script type=\"module\">\n import { App } from \"@modelcontextprotocol/ext-apps\";\n import { connectView } from \"mountly-compose\";\n\n const app = new App({ name: \"mountly-compose\", version: \"1.0.0\" });\n connectView(app, document.querySelector(\"#page\"), {\n request: \"Show the updated page with ${DEFAULT_TOOL_NAME}.\",\n });\n await app.connect();\n </script>\n </body>\n</html>\n`;\n}\n\n/** Every origin the view loads code or data from, for its content security policy. */\nfunction originsOf(options: RegisterComposeAppOptions): string[] {\n const urls = [\n ...Object.values(options.imports),\n ...options.catalog.elements.flatMap((el) => (el.embed ? [el.embed] : [])),\n ];\n const origins = new Set<string>();\n for (const url of urls) {\n try {\n origins.add(new URL(url).origin);\n } catch {\n // A relative URL is same-origin with the view and needs no entry.\n }\n }\n return [...origins];\n}\n\nfunction tagsOf(node: Tree, into = new Set<string>()): Set<string> {\n into.add(node.tag);\n for (const child of node.children ?? []) tagsOf(child, into);\n return into;\n}\n\n/**\n * What the view renders with: the page, and the catalog's elements and actions.\n * All the elements, not just the page's: an action names the widgets the next\n * page must show, and the view hands that to the agent on the next turn.\n */\nfunction viewPayload(catalog: Catalog, page: Tree) {\n return { page, elements: catalog.elements, actions: catalog.actions };\n}\n\n/**\n * Register the `show_page` tool and its `ui://` view on an MCP server.\n *\n * The input is `{ page }`, typed loosely on purpose: a strict schema would make\n * the SDK reject a near-miss before the handler could repair it. The handler\n * validates against the catalog, strips small mistakes, and otherwise returns\n * the reasons as a tool error the agent can act on.\n */\nexport function registerComposeApp(\n server: McpServer,\n options: RegisterComposeAppOptions,\n): { tool: string; resourceUri: string } {\n const { catalog } = options;\n const name = options.name ?? DEFAULT_TOOL_NAME;\n const resourceUri = options.resourceUri ?? DEFAULT_RESOURCE_URI;\n if (!resourceUri.startsWith(\"ui://\")) {\n throw new Error(\n `mountly-mcp/compose: resourceUri must use 'ui://' (received '${resourceUri}')`,\n );\n }\n const origins = originsOf(options);\n const csp = { connectDomains: origins, resourceDomains: origins, frameDomains: [] };\n const html = composeViewHtml(options);\n\n registerAppResource(\n server,\n \"compose_view\",\n resourceUri,\n {\n mimeType: RESOURCE_MIME_TYPE,\n description: \"A page composed from teams' custom elements.\",\n _meta: { ui: { prefersBorder: false, csp } },\n },\n async () => ({\n contents: [\n { uri: resourceUri, mimeType: RESOURCE_MIME_TYPE, text: html, _meta: { ui: { csp } } },\n ],\n }),\n );\n\n const description = [\n `Show the user a page built from the components below. Call it with { \"page\": <tree> }.`,\n `To change the page, call it again with the whole updated page.`,\n options.instructions ?? \"\",\n \"\",\n catalog.prompt(),\n ]\n .filter((line, index) => line || index > 2)\n .join(\"\\n\");\n\n registerAppTool(\n server,\n name,\n {\n title: \"Show page\",\n description,\n inputSchema: { page: z.unknown().describe(\"The page as a tree: { tag, attrs, children }.\") },\n _meta: { ui: { resourceUri, visibility: [\"model\", \"app\"] } },\n } as never,\n (async (args: { page?: unknown }) => {\n const errors = catalog.validate(args.page);\n let page = args.page as Tree;\n let note = \"\";\n if (errors.length) {\n const { tree, dropped } = catalog.repair(args.page);\n if (!tree || catalog.validate(tree).length) {\n return {\n isError: true,\n content: [\n {\n type: \"text\",\n text: `The page cannot be shown:\\n${errors.join(\"\\n\")}\\nFix these and call ${name} again.`,\n },\n ],\n };\n }\n page = tree;\n note = ` Removed what the catalog does not allow: ${dropped.join(\"; \")}.`;\n }\n const hostTags = new Set(\n catalog.elements.filter((el) => el.team === \"host\").map((el) => el.tag),\n );\n const tags = [...tagsOf(page)].filter((tag) => !hostTags.has(tag));\n return {\n content: [{ type: \"text\", text: `Showing ${tags.join(\", \") || \"the page\"}.${note}` }],\n structuredContent: viewPayload(catalog, page),\n };\n }) as never,\n );\n\n return { tool: name, resourceUri };\n}\n"],"mappings":"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","names":[]}
|
package/dist/dev/host-entry.js
CHANGED
|
@@ -15186,7 +15186,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
15186
15186
|
}
|
|
15187
15187
|
});
|
|
15188
15188
|
|
|
15189
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.
|
|
15189
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.0_@cfworker+json-schema@4.1.1_zod@4.4.3/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
|
|
15190
15190
|
init_v4();
|
|
15191
15191
|
var RELATED_TASK_META_KEY = "io.modelcontextprotocol/related-task";
|
|
15192
15192
|
var JSONRPC_VERSION = "2.0";
|
|
@@ -16707,7 +16707,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
16707
16707
|
// ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/mini/parse.js
|
|
16708
16708
|
init_core2();
|
|
16709
16709
|
|
|
16710
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.
|
|
16710
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.0_@cfworker+json-schema@4.1.1_zod@4.4.3/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js
|
|
16711
16711
|
function isZ4Schema(s2) {
|
|
16712
16712
|
const schema = s2;
|
|
16713
16713
|
return !!schema._zod;
|
|
@@ -16770,7 +16770,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
16770
16770
|
return void 0;
|
|
16771
16771
|
}
|
|
16772
16772
|
|
|
16773
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.
|
|
16773
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.0_@cfworker+json-schema@4.1.1_zod@4.4.3/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/interfaces.js
|
|
16774
16774
|
function isTerminal(status) {
|
|
16775
16775
|
return status === "completed" || status === "failed" || status === "cancelled";
|
|
16776
16776
|
}
|
|
@@ -16778,7 +16778,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
16778
16778
|
// ../../node_modules/.pnpm/zod-to-json-schema@3.25.2_zod@4.4.3/node_modules/zod-to-json-schema/dist/esm/parsers/string.js
|
|
16779
16779
|
var ALPHA_NUMERIC = new Set("ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvxyz0123456789");
|
|
16780
16780
|
|
|
16781
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.
|
|
16781
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.0_@cfworker+json-schema@4.1.1_zod@4.4.3/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-json-schema-compat.js
|
|
16782
16782
|
function getMethodLiteral(schema) {
|
|
16783
16783
|
const shape = getObjectShape(schema);
|
|
16784
16784
|
const methodSchema = shape?.method;
|
|
@@ -16799,7 +16799,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
16799
16799
|
return result.data;
|
|
16800
16800
|
}
|
|
16801
16801
|
|
|
16802
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.
|
|
16802
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.0_@cfworker+json-schema@4.1.1_zod@4.4.3/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js
|
|
16803
16803
|
var DEFAULT_REQUEST_TIMEOUT_MSEC = 6e4;
|
|
16804
16804
|
var Protocol = class {
|
|
16805
16805
|
constructor(_options) {
|
|
@@ -17734,7 +17734,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
17734
17734
|
}
|
|
17735
17735
|
};
|
|
17736
17736
|
|
|
17737
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+ext-apps@1.7.5_@modelcontextprotocol+sdk@1.30.
|
|
17737
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+ext-apps@1.7.5_@modelcontextprotocol+sdk@1.30.0_@cfworker+json-schema@4_zach7odob275zkkz2vkisyu32i/node_modules/@modelcontextprotocol/ext-apps/dist/src/app-bridge.js
|
|
17738
17738
|
init_v4();
|
|
17739
17739
|
var ZQ = ((X) => typeof __require < "u" ? __require : typeof Proxy < "u" ? new Proxy(X, { get: (Y, Z) => (typeof __require < "u" ? __require : Y)[Z] }) : X)(function(X) {
|
|
17740
17740
|
if (typeof __require < "u") return __require.apply(this, arguments);
|
|
@@ -18213,6 +18213,8 @@ container holding the app. Specify either width or maxWidth, and either height o
|
|
|
18213
18213
|
var capabilities = {
|
|
18214
18214
|
openLinks: {},
|
|
18215
18215
|
logging: {},
|
|
18216
|
+
// A view's `sendMessage` asks the host to post the user's next turn to the agent.
|
|
18217
|
+
message: { text: {} },
|
|
18216
18218
|
...config2.hasServer ? { serverTools: {} } : {}
|
|
18217
18219
|
};
|
|
18218
18220
|
var bridge = new DX(null, { name: "mountly-mcp-dev", version: "1.0.0" }, capabilities, {
|
|
@@ -18225,6 +18227,11 @@ container holding the app. Specify either width or maxWidth, and either height o
|
|
|
18225
18227
|
}
|
|
18226
18228
|
});
|
|
18227
18229
|
bridge.onloggingmessage = (params) => log("in", `notifications/message ${params.level}`);
|
|
18230
|
+
bridge.onmessage = async ({ content }) => {
|
|
18231
|
+
const text = content.map((block) => "text" in block ? block.text : `[${block.type}]`).join(" ");
|
|
18232
|
+
log("in", `ui/message ${text}`);
|
|
18233
|
+
return {};
|
|
18234
|
+
};
|
|
18228
18235
|
bridge.onopenlink = async ({ url: url2 }) => {
|
|
18229
18236
|
window.open(url2, "_blank", "noopener,noreferrer");
|
|
18230
18237
|
return {};
|
package/dist/dev/index.js
CHANGED
|
@@ -4,9 +4,9 @@ import {
|
|
|
4
4
|
} from "./chunk-EOWAWZH2.js";
|
|
5
5
|
|
|
6
6
|
// src/doctor.ts
|
|
7
|
-
import { existsSync, readFileSync } from "fs";
|
|
7
|
+
import { existsSync, readFileSync, readdirSync } from "fs";
|
|
8
8
|
import { createRequire } from "module";
|
|
9
|
-
import { resolve } from "path";
|
|
9
|
+
import { join, resolve } from "path";
|
|
10
10
|
function nodeMajor() {
|
|
11
11
|
return Number(process.versions.node.split(".")[0] ?? 0);
|
|
12
12
|
}
|
|
@@ -18,6 +18,33 @@ function tryResolve(specifier, fromDir) {
|
|
|
18
18
|
return null;
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
+
var OPENAI_USAGE = /openai\/ui|useOpenAIExtensions|mountly-mcp\/openai|mountly-mcp\/react\/openai|@openai\/mcp-extensions|openaiUi\b|openaiUiToolMeta|enableOpenAiExtensions/;
|
|
22
|
+
function projectSourcesMentionOpenAi(cwd, viteConfig) {
|
|
23
|
+
const candidates = [];
|
|
24
|
+
if (viteConfig) candidates.push(viteConfig);
|
|
25
|
+
for (const name of ["server.ts", "server.mjs", "server.js", "src/server.ts", "src/view.tsx"]) {
|
|
26
|
+
const path = resolve(cwd, name);
|
|
27
|
+
if (existsSync(path)) candidates.push(path);
|
|
28
|
+
}
|
|
29
|
+
const srcDir = resolve(cwd, "src");
|
|
30
|
+
if (existsSync(srcDir)) {
|
|
31
|
+
try {
|
|
32
|
+
for (const entry of readdirSync(srcDir, { withFileTypes: true })) {
|
|
33
|
+
if (entry.isFile() && /\.(tsx?|jsx?|mjs|cjs)$/.test(entry.name)) {
|
|
34
|
+
candidates.push(join(srcDir, entry.name));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
} catch {
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
for (const path of candidates) {
|
|
41
|
+
try {
|
|
42
|
+
if (OPENAI_USAGE.test(readFileSync(path, "utf8"))) return true;
|
|
43
|
+
} catch {
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
21
48
|
function runDoctor(cwd = process.cwd()) {
|
|
22
49
|
const checks = [];
|
|
23
50
|
const major = nodeMajor();
|
|
@@ -88,6 +115,14 @@ function runDoctor(cwd = process.cwd()) {
|
|
|
88
115
|
}
|
|
89
116
|
}
|
|
90
117
|
}
|
|
118
|
+
if (projectSourcesMentionOpenAi(cwd, viteConfig)) {
|
|
119
|
+
const openai = tryResolve("@openai/mcp-extensions/package.json", cwd);
|
|
120
|
+
checks.push({
|
|
121
|
+
id: "openai-extensions",
|
|
122
|
+
ok: Boolean(openai),
|
|
123
|
+
detail: openai ? `@openai/mcp-extensions resolvable (${openai})` : "Project references OpenAI MCP extensions but @openai/mcp-extensions is not installed. Run: pnpm add @openai/mcp-extensions"
|
|
124
|
+
});
|
|
125
|
+
}
|
|
91
126
|
const hard = checks.filter((c) => c.id !== "manifest" && c.id !== "playwright");
|
|
92
127
|
const ok = hard.every((c) => c.ok);
|
|
93
128
|
return { ok, checks };
|
|
@@ -119,4 +154,4 @@ export {
|
|
|
119
154
|
formatDoctorReport,
|
|
120
155
|
runDoctor
|
|
121
156
|
};
|
|
122
|
-
//# sourceMappingURL=doctor-
|
|
157
|
+
//# sourceMappingURL=doctor-4MTC6Y4X.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/doctor.ts"],"sourcesContent":["import { existsSync, readFileSync, readdirSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { join, resolve } from \"node:path\";\nimport { CLI_ERROR_CODES, cliError } from \"./errors.js\";\n\nexport interface DoctorCheck {\n id: string;\n ok: boolean;\n detail: string;\n}\n\nexport interface DoctorReport {\n ok: boolean;\n checks: DoctorCheck[];\n}\n\nfunction nodeMajor(): number {\n return Number(process.versions.node.split(\".\")[0] ?? 0);\n}\n\nfunction tryResolve(specifier: string, fromDir: string): string | null {\n try {\n const require = createRequire(resolve(fromDir, \"package.json\"));\n return require.resolve(specifier);\n } catch {\n return null;\n }\n}\n\nconst OPENAI_USAGE =\n /openai\\/ui|useOpenAIExtensions|mountly-mcp\\/openai|mountly-mcp\\/react\\/openai|@openai\\/mcp-extensions|openaiUi\\b|openaiUiToolMeta|enableOpenAiExtensions/;\n\nfunction projectSourcesMentionOpenAi(cwd: string, viteConfig?: string): boolean {\n const candidates: string[] = [];\n if (viteConfig) candidates.push(viteConfig);\n for (const name of [\"server.ts\", \"server.mjs\", \"server.js\", \"src/server.ts\", \"src/view.tsx\"]) {\n const path = resolve(cwd, name);\n if (existsSync(path)) candidates.push(path);\n }\n const srcDir = resolve(cwd, \"src\");\n if (existsSync(srcDir)) {\n try {\n for (const entry of readdirSync(srcDir, { withFileTypes: true })) {\n if (entry.isFile() && /\\.(tsx?|jsx?|mjs|cjs)$/.test(entry.name)) {\n candidates.push(join(srcDir, entry.name));\n }\n }\n } catch {\n // ignore unreadable src\n }\n }\n for (const path of candidates) {\n try {\n if (OPENAI_USAGE.test(readFileSync(path, \"utf8\"))) return true;\n } catch {\n // skip\n }\n }\n return false;\n}\n\n/**\n * Check the local project for Mountly MCP readiness. Exits nonzero via the\n * CLI when `ok` is false.\n */\nexport function runDoctor(cwd = process.cwd()): DoctorReport {\n const checks: DoctorCheck[] = [];\n\n const major = nodeMajor();\n checks.push({\n id: \"node\",\n ok: major >= 20,\n detail:\n major >= 20\n ? `Node ${process.versions.node} (ok; 20+ required, 22+ recommended)`\n : `Node ${process.versions.node} is below 20. Upgrade Node, then re-run mountly-mcp doctor.`,\n });\n\n const viteConfigCandidates = [\n \"vite.config.ts\",\n \"vite.config.mts\",\n \"vite.config.js\",\n \"vite.config.mjs\",\n ].map((name) => resolve(cwd, name));\n const viteConfig = viteConfigCandidates.find((path) => existsSync(path));\n checks.push({\n id: \"vite-config\",\n ok: Boolean(viteConfig),\n detail: viteConfig\n ? `Found ${viteConfig}`\n : \"No vite.config.* in this directory. Run from the View project, or: npx mountly-mcp create my-app --framework react\",\n });\n\n if (viteConfig) {\n const source = readFileSync(viteConfig, \"utf8\");\n const hasPlugin = /mountlyMcpViews\\s*\\(/.test(source);\n checks.push({\n id: \"vite-plugin\",\n ok: hasPlugin,\n detail: hasPlugin\n ? \"vite config imports mountlyMcpViews()\"\n : `Add mountlyMcpViews() from \"mountly-mcp/vite\" to ${viteConfig}`,\n });\n }\n\n const manifest = resolve(cwd, \"dist/mountly-mcp.manifest.json\");\n checks.push({\n id: \"manifest\",\n ok: existsSync(manifest),\n detail: existsSync(manifest)\n ? `Found ${manifest}`\n : \"No dist/mountly-mcp.manifest.json yet. Run: npx mountly-mcp build\",\n });\n\n const playwright = tryResolve(\"playwright\", cwd) ?? tryResolve(\"@playwright/test\", cwd);\n checks.push({\n id: \"playwright\",\n ok: Boolean(playwright),\n detail: playwright\n ? `Playwright resolvable for verify --render (${playwright})`\n : \"Playwright not installed. For CI render checks: pnpm add -D playwright && npx playwright install chromium\",\n });\n\n const pkgPath = resolve(cwd, \"package.json\");\n if (existsSync(pkgPath)) {\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf8\")) as {\n dependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n if (deps.react) {\n const reactPath = tryResolve(\"react/package.json\", cwd);\n if (reactPath) {\n const reactPkg = JSON.parse(readFileSync(reactPath, \"utf8\")) as { version?: string };\n const reactMajor = Number((reactPkg.version ?? \"0\").split(\".\")[0]);\n checks.push({\n id: \"react\",\n ok: reactMajor >= 19,\n detail:\n reactMajor >= 19\n ? `React ${reactPkg.version} (ok)`\n : `React ${reactPkg.version} is below 19. mountly-mcp/react and mountly-react require React 19.`,\n });\n }\n }\n if (deps.vite) {\n const vitePath = tryResolve(\"vite/package.json\", cwd);\n if (vitePath) {\n const vitePkg = JSON.parse(readFileSync(vitePath, \"utf8\")) as { version?: string };\n const viteMajor = Number((vitePkg.version ?? \"0\").split(\".\")[0]);\n checks.push({\n id: \"vite\",\n ok: viteMajor >= 8,\n detail:\n viteMajor >= 8\n ? `Vite ${vitePkg.version} (ok)`\n : `Vite ${vitePkg.version} is below 8. mountly-mcp/vite is built and tested against Vite 8.`,\n });\n }\n }\n }\n\n if (projectSourcesMentionOpenAi(cwd, viteConfig)) {\n const openai = tryResolve(\"@openai/mcp-extensions/package.json\", cwd);\n checks.push({\n id: \"openai-extensions\",\n ok: Boolean(openai),\n detail: openai\n ? `@openai/mcp-extensions resolvable (${openai})`\n : 'Project references OpenAI MCP extensions but @openai/mcp-extensions is not installed. Run: pnpm add @openai/mcp-extensions',\n });\n }\n\n // Manifest missing is advisory for a brand-new scaffold before first build.\n const hard = checks.filter((c) => c.id !== \"manifest\" && c.id !== \"playwright\");\n const ok = hard.every((c) => c.ok);\n\n return { ok, checks };\n}\n\nexport function formatDoctorReport(report: DoctorReport): string {\n const lines = [\"mountly-mcp doctor\", \"\"];\n for (const check of report.checks) {\n lines.push(`${check.ok ? \"ok\" : \"FAIL\"} ${check.id.padEnd(14)} ${check.detail}`);\n }\n lines.push(\"\");\n lines.push(report.ok ? \"Ready for mountly-mcp build / dev / verify.\" : \"Fix FAIL items above.\");\n lines.push(\"\");\n return `${lines.join(\"\\n\")}\\n`;\n}\n\nexport function doctorCommand(cwd = process.cwd()): void {\n const report = runDoctor(cwd);\n process.stdout.write(formatDoctorReport(report));\n if (!report.ok) {\n throw cliError(\n CLI_ERROR_CODES.DOCTOR_FAILED,\n \"one or more doctor checks failed\",\n \"Fix the FAIL lines above, then re-run: mountly-mcp doctor\",\n );\n }\n}\n"],"mappings":"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","names":["require"]}
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
sandboxProxyHtml
|
|
3
|
-
} from "./chunk-6QHKKFO3.js";
|
|
4
1
|
import {
|
|
5
2
|
MCP_VIEW_GLOBAL_KEY,
|
|
6
3
|
getPublishedMcpView,
|
|
7
4
|
publishMcpView
|
|
8
5
|
} from "./chunk-5L3QHYWK.js";
|
|
6
|
+
import {
|
|
7
|
+
sandboxProxyHtml
|
|
8
|
+
} from "./chunk-6QHKKFO3.js";
|
|
9
9
|
import {
|
|
10
10
|
App,
|
|
11
11
|
PostMessageTransport,
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildAppHtml,
|
|
3
|
+
useJsonRenderApp
|
|
4
|
+
} from "../chunk-33DMFKKD.js";
|
|
1
5
|
import {
|
|
2
6
|
createJsonRenderMcpApp,
|
|
3
7
|
registerJsonRenderResource,
|
|
@@ -15,12 +19,9 @@ import {
|
|
|
15
19
|
createMcpView,
|
|
16
20
|
useMcpApp,
|
|
17
21
|
useToolResult
|
|
18
|
-
} from "../chunk-
|
|
22
|
+
} from "../chunk-HIAIQVK5.js";
|
|
23
|
+
import "../chunk-4SZHJ4MK.js";
|
|
19
24
|
import "../chunk-5L3QHYWK.js";
|
|
20
|
-
import {
|
|
21
|
-
buildAppHtml,
|
|
22
|
-
useJsonRenderApp
|
|
23
|
-
} from "../chunk-33DMFKKD.js";
|
|
24
25
|
import "../chunk-YJA4H6IB.js";
|
|
25
26
|
|
|
26
27
|
// src/json-render/generative-view.tsx
|
|
@@ -1 +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"]}
|
|
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,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ChatGPT helpers that wrap `@openai/mcp-extensions/server`.
|
|
3
|
+
*/
|
|
4
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { OpenAIExtensions, type OpenAIUiEntrypoint, type OpenAIUiResourceMetadata, type OpenAIUiToolMetadata } from "@openai/mcp-extensions/server";
|
|
6
|
+
/** Return the official OpenAI extensions surface for this MCP server. */
|
|
7
|
+
export declare function enableOpenAiExtensions(server: McpServer): OpenAIExtensions;
|
|
8
|
+
/** Build a `_meta` fragment with typed `"openai/ui"` tool metadata. */
|
|
9
|
+
export declare function openaiUiToolMeta(meta: OpenAIUiToolMetadata): {
|
|
10
|
+
"openai/ui": OpenAIUiToolMetadata;
|
|
11
|
+
};
|
|
12
|
+
/** Build a `_meta` fragment with typed `"openai/ui"` resource metadata. */
|
|
13
|
+
export declare function openaiUiResourceMeta(meta: OpenAIUiResourceMetadata): {
|
|
14
|
+
"openai/ui": OpenAIUiResourceMetadata;
|
|
15
|
+
};
|
|
16
|
+
export { OpenAIExtensions, type OpenAIUiEntrypoint, type OpenAIUiResourceMetadata, type OpenAIUiToolMetadata, };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// src/openai/server.ts
|
|
2
|
+
import {
|
|
3
|
+
OpenAIExtensions
|
|
4
|
+
} from "@openai/mcp-extensions/server";
|
|
5
|
+
function enableOpenAiExtensions(server) {
|
|
6
|
+
return new OpenAIExtensions(server);
|
|
7
|
+
}
|
|
8
|
+
function openaiUiToolMeta(meta) {
|
|
9
|
+
return { "openai/ui": meta };
|
|
10
|
+
}
|
|
11
|
+
function openaiUiResourceMeta(meta) {
|
|
12
|
+
return { "openai/ui": meta };
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
OpenAIExtensions,
|
|
16
|
+
enableOpenAiExtensions,
|
|
17
|
+
openaiUiResourceMeta,
|
|
18
|
+
openaiUiToolMeta
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/openai/server.ts"],"sourcesContent":["/**\n * ChatGPT helpers that wrap `@openai/mcp-extensions/server`.\n */\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport {\n OpenAIExtensions,\n type OpenAIUiEntrypoint,\n type OpenAIUiResourceMetadata,\n type OpenAIUiToolMetadata,\n} from \"@openai/mcp-extensions/server\";\n\n/** Return the official OpenAI extensions surface for this MCP server. */\nexport function enableOpenAiExtensions(server: McpServer): OpenAIExtensions {\n return new OpenAIExtensions(server);\n}\n\n/** Build a `_meta` fragment with typed `\"openai/ui\"` tool metadata. */\nexport function openaiUiToolMeta(\n meta: OpenAIUiToolMetadata,\n): { \"openai/ui\": OpenAIUiToolMetadata } {\n return { \"openai/ui\": meta };\n}\n\n/** Build a `_meta` fragment with typed `\"openai/ui\"` resource metadata. */\nexport function openaiUiResourceMeta(\n meta: OpenAIUiResourceMetadata,\n): { \"openai/ui\": OpenAIUiResourceMetadata } {\n return { \"openai/ui\": meta };\n}\n\nexport {\n OpenAIExtensions,\n type OpenAIUiEntrypoint,\n type OpenAIUiResourceMetadata,\n type OpenAIUiToolMetadata,\n};\n"],"mappings":";AAIA;AAAA,EACE;AAAA,OAIK;AAGA,SAAS,uBAAuB,QAAqC;AAC1E,SAAO,IAAI,iBAAiB,MAAM;AACpC;AAGO,SAAS,iBACd,MACuC;AACvC,SAAO,EAAE,aAAa,KAAK;AAC7B;AAGO,SAAS,qBACd,MAC2C;AAC3C,SAAO,EAAE,aAAa,KAAK;AAC7B;","names":[]}
|
package/dist/react/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {
|
|
2
|
-
McpContext,
|
|
3
2
|
createMcpView,
|
|
4
3
|
useAutoResize,
|
|
5
4
|
useDisplayMode,
|
|
@@ -14,7 +13,10 @@ import {
|
|
|
14
13
|
useToolInputPartial,
|
|
15
14
|
useToolResult,
|
|
16
15
|
useUpdateModelContext
|
|
17
|
-
} from "../chunk-
|
|
16
|
+
} from "../chunk-HIAIQVK5.js";
|
|
17
|
+
import {
|
|
18
|
+
McpContext
|
|
19
|
+
} from "../chunk-4SZHJ4MK.js";
|
|
18
20
|
import "../chunk-5L3QHYWK.js";
|
|
19
21
|
export {
|
|
20
22
|
McpContext,
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { OpenAIExtensions } from "@openai/mcp-extensions/app";
|
|
2
|
+
/**
|
|
3
|
+
* Official ChatGPT extension surface for this View.
|
|
4
|
+
* One `OpenAIExtensions` per App handle. Call `message`, `files`, `deepLink`, and the rest on the returned instance.
|
|
5
|
+
*/
|
|
6
|
+
export declare function useOpenAIExtensions(): OpenAIExtensions;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
McpContext
|
|
3
|
+
} from "../chunk-4SZHJ4MK.js";
|
|
4
|
+
|
|
5
|
+
// src/react/openai-extensions.ts
|
|
6
|
+
import { useContext, useRef } from "react";
|
|
7
|
+
import { OpenAIExtensions } from "@openai/mcp-extensions/app";
|
|
8
|
+
function useOpenAIExtensions() {
|
|
9
|
+
const ctx = useContext(McpContext);
|
|
10
|
+
if (!ctx) {
|
|
11
|
+
throw new Error(
|
|
12
|
+
"mountly-mcp/react: useOpenAIExtensions must be used inside a View wrapped with createMcpView()."
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
const app = ctx.app;
|
|
16
|
+
const ref = useRef(null);
|
|
17
|
+
if (ref.current?.app !== app) {
|
|
18
|
+
ref.current = { app, extensions: new OpenAIExtensions(app) };
|
|
19
|
+
}
|
|
20
|
+
return ref.current.extensions;
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
useOpenAIExtensions
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=openai-extensions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/react/openai-extensions.ts"],"sourcesContent":["/**\n * ChatGPT extension hook backed by `@openai/mcp-extensions/app`.\n * Separate entry (`mountly-mcp/react/openai`) keeps the peer out of ordinary Views.\n */\nimport { useContext, useRef } from \"react\";\nimport type { App } from \"@modelcontextprotocol/ext-apps\";\nimport { OpenAIExtensions } from \"@openai/mcp-extensions/app\";\nimport { McpContext } from \"./context.js\";\n\n/**\n * Official ChatGPT extension surface for this View.\n * One `OpenAIExtensions` per App handle. Call `message`, `files`, `deepLink`, and the rest on the returned instance.\n */\nexport function useOpenAIExtensions(): OpenAIExtensions {\n const ctx = useContext(McpContext);\n if (!ctx) {\n throw new Error(\n \"mountly-mcp/react: useOpenAIExtensions must be used inside a View wrapped with createMcpView().\",\n );\n }\n const app = ctx.app;\n const ref = useRef<{ app: App; extensions: OpenAIExtensions } | null>(null);\n if (ref.current?.app !== app) {\n ref.current = { app, extensions: new OpenAIExtensions(app) };\n }\n return ref.current.extensions;\n}\n"],"mappings":";;;;;AAIA,SAAS,YAAY,cAAc;AAEnC,SAAS,wBAAwB;AAO1B,SAAS,sBAAwC;AACtD,QAAM,MAAM,WAAW,UAAU;AACjC,MAAI,CAAC,KAAK;AACR,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,QAAM,MAAM,IAAI;AAChB,QAAM,MAAM,OAA0D,IAAI;AAC1E,MAAI,IAAI,SAAS,QAAQ,KAAK;AAC5B,QAAI,UAAU,EAAE,KAAK,YAAY,IAAI,iBAAiB,GAAG,EAAE;AAAA,EAC7D;AACA,SAAO,IAAI,QAAQ;AACrB;","names":[]}
|
package/dist/server/index.js
CHANGED
|
@@ -116,15 +116,20 @@ async function registerMcpApps(server, options) {
|
|
|
116
116
|
server.server.registerCapabilities({
|
|
117
117
|
extensions: { [EXTENSION_ID]: { mimeTypes: [RESOURCE_MIME_TYPE] } }
|
|
118
118
|
});
|
|
119
|
-
const resources = views.map(
|
|
120
|
-
|
|
119
|
+
const resources = views.map(({ artifact, html }) => {
|
|
120
|
+
const resourceMeta = {
|
|
121
|
+
ui: artifact.declaration._meta.ui
|
|
122
|
+
};
|
|
123
|
+
const openaiUi = artifact.declaration._meta["openai/ui"];
|
|
124
|
+
if (openaiUi !== void 0) resourceMeta["openai/ui"] = openaiUi;
|
|
125
|
+
return registerAppResource(
|
|
121
126
|
server,
|
|
122
127
|
artifact.name,
|
|
123
128
|
artifact.uri,
|
|
124
129
|
{
|
|
125
130
|
mimeType: artifact.declaration.mimeType,
|
|
126
131
|
description: artifact.declaration.description,
|
|
127
|
-
_meta:
|
|
132
|
+
_meta: resourceMeta
|
|
128
133
|
},
|
|
129
134
|
async () => ({
|
|
130
135
|
contents: [
|
|
@@ -132,12 +137,12 @@ async function registerMcpApps(server, options) {
|
|
|
132
137
|
uri: artifact.uri,
|
|
133
138
|
mimeType: artifact.declaration.mimeType,
|
|
134
139
|
text: html,
|
|
135
|
-
_meta:
|
|
140
|
+
_meta: resourceMeta
|
|
136
141
|
}
|
|
137
142
|
]
|
|
138
143
|
})
|
|
139
|
-
)
|
|
140
|
-
);
|
|
144
|
+
);
|
|
145
|
+
});
|
|
141
146
|
const tools = (options.tools ?? []).map((registration) => {
|
|
142
147
|
const { meta, withoutUi, visibility } = mergedToolMetadata(registration);
|
|
143
148
|
const config = registration.config ?? {};
|