mountly-mcp 4.3.0 → 4.5.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/README.md +89 -0
- package/dist/artifact/declaration.d.ts +61 -0
- package/dist/artifact/index.d.ts +2 -42
- package/dist/artifact/index.js +9 -5
- package/dist/chunk-6T5EIQGE.js +104 -0
- package/dist/chunk-6T5EIQGE.js.map +1 -0
- package/dist/chunk-BLT2MK32.js +35 -0
- package/dist/chunk-BLT2MK32.js.map +1 -0
- package/dist/{chunk-HIAIQVK5.js → chunk-QIA76O6M.js} +9 -1
- package/dist/chunk-QIA76O6M.js.map +1 -0
- package/dist/{chunk-DKK26TRS.js → chunk-RLDSMU5M.js} +9 -70
- package/dist/chunk-RLDSMU5M.js.map +1 -0
- package/dist/chunk-UMQ5OULD.js +243 -0
- package/dist/chunk-UMQ5OULD.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/dev/host-entry.js +23 -0
- package/dist/{doctor-4MTC6Y4X.js → doctor-OTOROLPI.js} +118 -9
- package/dist/doctor-OTOROLPI.js.map +1 -0
- package/dist/doctor.d.ts +4 -0
- package/dist/download.d.ts +17 -0
- package/dist/events/index.d.ts +97 -0
- package/dist/events/index.js +215 -0
- package/dist/events/index.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +7 -3
- package/dist/json-render/index.js +2 -1
- package/dist/json-render/index.js.map +1 -1
- package/dist/react/hooks.d.ts +7 -0
- package/dist/react/index.js +4 -1
- package/dist/server/core.d.ts +84 -0
- package/dist/server/index.d.ts +2 -72
- package/dist/server/index.js +19 -219
- package/dist/server/index.js.map +1 -1
- package/dist/server/workers.d.ts +7 -0
- package/dist/server/workers.js +14 -0
- package/dist/server/workers.js.map +1 -0
- package/dist/testing/index.js +5 -3
- package/dist/testing/index.js.map +1 -1
- package/dist/vite/index.d.ts +15 -1
- package/dist/vite/index.js +133 -11
- package/dist/vite/index.js.map +1 -1
- package/dist/vue/index.d.ts +6 -0
- package/dist/vue/index.js +8 -0
- package/dist/vue/index.js.map +1 -1
- package/package.json +18 -6
- package/templates/react/README.md.tmpl +3 -0
- package/templates/react/package.json.tmpl +6 -3
- package/templates/svelte/README.md.tmpl +2 -0
- package/templates/svelte/package.json.tmpl +5 -3
- package/templates/svelte/src/env.d.ts.tmpl +10 -0
- package/templates/vanilla/README.md.tmpl +2 -0
- package/templates/vanilla/package.json.tmpl +5 -2
- package/templates/vue/README.md.tmpl +2 -0
- package/templates/vue/package.json.tmpl +6 -4
- package/templates/vue/src/env.d.ts.tmpl +10 -0
- package/dist/chunk-DKK26TRS.js.map +0 -1
- package/dist/chunk-HIAIQVK5.js.map +0 -1
- package/dist/doctor-4MTC6Y4X.js.map +0 -1
package/dist/vite/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
|
-
MCP_APP_MANIFEST_FILE,
|
|
3
2
|
writeMcpAppManifest
|
|
4
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-RLDSMU5M.js";
|
|
4
|
+
import {
|
|
5
|
+
MCP_APP_MANIFEST_FILE
|
|
6
|
+
} from "../chunk-6T5EIQGE.js";
|
|
5
7
|
import {
|
|
6
8
|
buildMcpResourceFromSource
|
|
7
9
|
} from "../chunk-IDGTP2NI.js";
|
|
@@ -9,8 +11,37 @@ import "../chunk-M4WFJR3C.js";
|
|
|
9
11
|
import "../chunk-YJA4H6IB.js";
|
|
10
12
|
|
|
11
13
|
// src/vite/index.ts
|
|
12
|
-
import { rm } from "fs/promises";
|
|
14
|
+
import { readFile, rm, writeFile } from "fs/promises";
|
|
13
15
|
import { basename, isAbsolute, join, resolve } from "path";
|
|
16
|
+
import { parseAst } from "vite";
|
|
17
|
+
var MCP_APP_VIEWS_MODULE_FILE = "mountly-mcp.views.js";
|
|
18
|
+
async function writeViewsModule(path, artifacts) {
|
|
19
|
+
const views = await Promise.all(
|
|
20
|
+
artifacts.map(async ({ name, uri, declaration, htmlPath }) => ({
|
|
21
|
+
name,
|
|
22
|
+
uri,
|
|
23
|
+
declaration,
|
|
24
|
+
html: await readFile(htmlPath, "utf8")
|
|
25
|
+
}))
|
|
26
|
+
);
|
|
27
|
+
await writeFile(
|
|
28
|
+
path,
|
|
29
|
+
`// Generated by mountly-mcp. Do not edit.
|
|
30
|
+
export default ${JSON.stringify(views, null, 2)};
|
|
31
|
+
`,
|
|
32
|
+
"utf8"
|
|
33
|
+
);
|
|
34
|
+
await writeFile(
|
|
35
|
+
// `views.mjs` pairs with `views.d.mts`, which is where TypeScript looks.
|
|
36
|
+
path.replace(/\.(m?)js$/, ".d.$1ts"),
|
|
37
|
+
`// Generated by mountly-mcp. Do not edit.
|
|
38
|
+
import type { McpAppSource } from "mountly-mcp/artifact";
|
|
39
|
+
declare const views: ReadonlyArray<McpAppSource>;
|
|
40
|
+
export default views;
|
|
41
|
+
`,
|
|
42
|
+
"utf8"
|
|
43
|
+
);
|
|
44
|
+
}
|
|
14
45
|
function isCollection(options) {
|
|
15
46
|
return "apps" in options;
|
|
16
47
|
}
|
|
@@ -22,11 +53,83 @@ function outputPath(root, outDir, app) {
|
|
|
22
53
|
if (!app.output) return join(outDir, `${basename(app.name)}.html`);
|
|
23
54
|
return isAbsolute(app.output) ? app.output : resolve(root, app.output);
|
|
24
55
|
}
|
|
56
|
+
function isImportMetaUrl(node) {
|
|
57
|
+
return node?.type === "MemberExpression" && node.object?.type === "MetaProperty" && node.object.meta?.name === "import" && node.object.property?.name === "meta" && node.property?.name === "url";
|
|
58
|
+
}
|
|
59
|
+
function stringValue(node) {
|
|
60
|
+
if (node?.type === "Literal" && typeof node.value === "string") return node.value;
|
|
61
|
+
if (node?.type === "TemplateLiteral" && node.expressions.length === 0) {
|
|
62
|
+
return node.quasis[0]?.value?.cooked;
|
|
63
|
+
}
|
|
64
|
+
return void 0;
|
|
65
|
+
}
|
|
66
|
+
function workerEdits(script, lang, offset, imports, count) {
|
|
67
|
+
const edits = [];
|
|
68
|
+
const walk = (node) => {
|
|
69
|
+
if (Array.isArray(node)) return node.forEach(walk);
|
|
70
|
+
if (!node || typeof node !== "object") return;
|
|
71
|
+
const n = node;
|
|
72
|
+
if (n.type === "NewExpression" && (n.callee?.name === "Worker" || n.callee?.name === "SharedWorker")) {
|
|
73
|
+
const [url, options] = n.arguments ?? [];
|
|
74
|
+
const path = url?.type === "NewExpression" && url.callee?.name === "URL" ? stringValue(url.arguments?.[0]) : void 0;
|
|
75
|
+
if (path !== void 0 && isImportMetaUrl(url.arguments?.[1])) {
|
|
76
|
+
const id = `__mountlyMcpWorker${count.n++}`;
|
|
77
|
+
const query = n.callee.name === "SharedWorker" ? "sharedworker" : "worker";
|
|
78
|
+
imports.push(`import ${id} from ${JSON.stringify(`${path}?${query}&inline`)};`);
|
|
79
|
+
const end = options ? options.start : n.end;
|
|
80
|
+
const text = options ? `new ${id}(` : `new ${id}()`;
|
|
81
|
+
const breaks = script.slice(n.start, end).split("\n").length - 1;
|
|
82
|
+
edits.push([offset + n.start, offset + end, text + "\n".repeat(breaks)]);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
for (const key in n) walk(n[key]);
|
|
86
|
+
};
|
|
87
|
+
walk(parseAst(script, { lang }));
|
|
88
|
+
return edits;
|
|
89
|
+
}
|
|
90
|
+
function langOf(file, attributes = "") {
|
|
91
|
+
const lang = /\blang\s*=\s*["']?(tsx|ts|jsx|js)\b/.exec(attributes)?.[1] ?? /\.([cm]?[jt]sx?)$/.exec(file)?.[1];
|
|
92
|
+
if (lang === "tsx" || lang === "jsx") return lang;
|
|
93
|
+
return lang && /ts$/.test(lang) ? "ts" : "js";
|
|
94
|
+
}
|
|
95
|
+
function inlineWorkers(code, file = "view.ts") {
|
|
96
|
+
if (!code.includes("import.meta")) return null;
|
|
97
|
+
const edits = [];
|
|
98
|
+
const count = { n: 0 };
|
|
99
|
+
try {
|
|
100
|
+
if (/\.(vue|svelte)$/.test(file)) {
|
|
101
|
+
for (const block of code.matchAll(/(<script\b([^>]*)>)([\s\S]*?)<\/script>/g)) {
|
|
102
|
+
const start = (block.index ?? 0) + (block[1]?.length ?? 0);
|
|
103
|
+
const imports = [];
|
|
104
|
+
edits.push(...workerEdits(block[3] ?? "", langOf(file, block[2]), start, imports, count));
|
|
105
|
+
if (imports.length) edits.push([start, start, imports.join("")]);
|
|
106
|
+
}
|
|
107
|
+
} else {
|
|
108
|
+
const imports = [];
|
|
109
|
+
edits.push(...workerEdits(code, langOf(file), 0, imports, count));
|
|
110
|
+
if (imports.length) edits.push([0, 0, imports.join("")]);
|
|
111
|
+
}
|
|
112
|
+
} catch {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
if (!edits.length) return null;
|
|
116
|
+
let out = code;
|
|
117
|
+
for (const [start, end, text] of edits.sort((a, b) => b[0] - a[0] || b[1] - a[1])) {
|
|
118
|
+
out = out.slice(0, start) + text + out.slice(end);
|
|
119
|
+
}
|
|
120
|
+
return out;
|
|
121
|
+
}
|
|
25
122
|
function mountlyMcpViews(options) {
|
|
26
123
|
const configuredApps = isCollection(options) ? [...options.apps] : [options];
|
|
27
124
|
const selectedForDev = process.env.MOUNTLY_MCP_SELECTED_APP;
|
|
28
125
|
const apps = selectedForDev ? configuredApps.filter((app) => app.name === selectedForDev) : configuredApps;
|
|
29
126
|
const manifestOption = isCollection(options) ? options.manifest : void 0;
|
|
127
|
+
const moduleOption = isCollection(options) ? options.module : void 0;
|
|
128
|
+
if (typeof moduleOption === "string" && !/\.m?js$/.test(moduleOption)) {
|
|
129
|
+
throw new Error(
|
|
130
|
+
`mountly-mcp: module must name a .js or .mjs file (received '${moduleOption}')`
|
|
131
|
+
);
|
|
132
|
+
}
|
|
30
133
|
if (apps.length === 0) throw new Error("mountly-mcp: apps must contain at least one View");
|
|
31
134
|
const names = /* @__PURE__ */ new Set();
|
|
32
135
|
const uris = /* @__PURE__ */ new Set();
|
|
@@ -69,10 +172,22 @@ function mountlyMcpViews(options) {
|
|
|
69
172
|
enforce: "post",
|
|
70
173
|
// Only meaningful during `vite build`; a dev server has no bundle to emit.
|
|
71
174
|
apply: "build",
|
|
72
|
-
|
|
175
|
+
// Before TypeScript is stripped and before Vite's own worker plugin claims
|
|
176
|
+
// the `new URL(…)` and emits a separate file.
|
|
177
|
+
transform: {
|
|
178
|
+
order: "pre",
|
|
179
|
+
handler(code, id) {
|
|
180
|
+
if (id.includes("/node_modules/") || id.includes("?")) return null;
|
|
181
|
+
const out = inlineWorkers(code, id);
|
|
182
|
+
return out === null ? null : { code: out, map: null };
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
config(config, env) {
|
|
73
186
|
const first = environments[0];
|
|
74
187
|
if (!first) throw new Error("mountly-mcp: configure at least one app");
|
|
75
188
|
return {
|
|
189
|
+
// An inline worker is one blob, so its own bundle must be one file too.
|
|
190
|
+
...config.worker?.format ? {} : { worker: { format: "iife" } },
|
|
76
191
|
// Vite's lib mode leaves `process.env.NODE_ENV` for a consuming bundler
|
|
77
192
|
// to replace. There isn't one — the bundle is inlined into HTML and run
|
|
78
193
|
// in a sandboxed iframe, where `process` is undefined and React and Vue
|
|
@@ -192,20 +307,27 @@ function mountlyMcpViews(options) {
|
|
|
192
307
|
if (source.cssFile) await rm(join(outDir, source.cssFile), { force: true });
|
|
193
308
|
}
|
|
194
309
|
this.info?.(`mountly-mcp: ${environment.app.uri} \u2192 ${result.htmlPath}`);
|
|
195
|
-
if (
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
);
|
|
310
|
+
if (manifestWritten || artifacts.size !== environments.length) return;
|
|
311
|
+
manifestWritten = true;
|
|
312
|
+
const all = environments.map((item) => artifacts.get(item.name));
|
|
313
|
+
const at = (path) => isAbsolute(path) ? path : resolve(root, path);
|
|
314
|
+
if (manifestOption !== false) {
|
|
315
|
+
const path = manifestOption ? at(manifestOption) : join(outDir, MCP_APP_MANIFEST_FILE);
|
|
316
|
+
await writeMcpAppManifest(path, all);
|
|
202
317
|
this.info?.(`mountly-mcp: manifest \u2192 ${path}`);
|
|
203
318
|
}
|
|
319
|
+
if (moduleOption) {
|
|
320
|
+
const path = typeof moduleOption === "string" ? at(moduleOption) : join(outDir, MCP_APP_VIEWS_MODULE_FILE);
|
|
321
|
+
await writeViewsModule(path, all);
|
|
322
|
+
this.info?.(`mountly-mcp: views module \u2192 ${path}`);
|
|
323
|
+
}
|
|
204
324
|
}
|
|
205
325
|
};
|
|
206
326
|
return plugin;
|
|
207
327
|
}
|
|
208
328
|
export {
|
|
329
|
+
MCP_APP_VIEWS_MODULE_FILE,
|
|
330
|
+
inlineWorkers,
|
|
209
331
|
mountlyMcpViews
|
|
210
332
|
};
|
|
211
333
|
//# sourceMappingURL=index.js.map
|
package/dist/vite/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/vite/index.ts"],"sourcesContent":["import { rm } from \"node:fs/promises\";\nimport { basename, isAbsolute, join, resolve } from \"node:path\";\nimport type { BuildEnvironment, Plugin, UserConfig } from \"vite\";\nimport { MCP_APP_MANIFEST_FILE, writeMcpAppManifest } from \"../artifact/index.js\";\nimport type { McpAppArtifact } from \"../artifact/index.js\";\nimport { buildMcpResourceFromSource } from \"../build/index.js\";\nimport type { BuildSelfContainedOptions } from \"../build/index.js\";\n\nexport interface MountlyMcpViewOptions extends Omit<\n BuildSelfContainedOptions,\n \"entry\" | \"output\" | \"cssEntry\"\n> {\n entry: string;\n output?: string;\n cleanIntermediate?: boolean;\n}\n\nexport interface MountlyMcpViewsOptions {\n apps: ReadonlyArray<MountlyMcpViewOptions>;\n /** Defaults to `<outDir>/mountly-mcp.manifest.json`; false disables it. */\n manifest?: string | false;\n}\n\nexport type MountlyMcpViteOptions = MountlyMcpViewOptions | MountlyMcpViewsOptions;\n\nexport interface MountlyMcpViteApi {\n apps: ReadonlyArray<MountlyMcpViewOptions>;\n manifest?: string | false;\n}\n\nfunction isCollection(options: MountlyMcpViteOptions): options is MountlyMcpViewsOptions {\n return \"apps\" in options;\n}\n\nfunction safeBuildName(name: string, index: number): string {\n const safe = name.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n return `mountly_mcp_${index}_${safe || \"app\"}`;\n}\n\nfunction outputPath(root: string, outDir: string, app: MountlyMcpViewOptions): string {\n if (!app.output) return join(outDir, `${basename(app.name)}.html`);\n return isAbsolute(app.output) ? app.output : resolve(root, app.output);\n}\n\n/**\n * Build one or many independent MCP Apps Views. Each View is a Vite build\n * environment, so frameworks and CSS remain isolated while callers configure\n * the collection once.\n */\nexport function mountlyMcpViews(options: MountlyMcpViteOptions): Plugin {\n const configuredApps = isCollection(options) ? [...options.apps] : [options];\n const selectedForDev = process.env.MOUNTLY_MCP_SELECTED_APP;\n const apps = selectedForDev\n ? configuredApps.filter((app) => app.name === selectedForDev)\n : configuredApps;\n const manifestOption = isCollection(options) ? options.manifest : undefined;\n if (apps.length === 0) throw new Error(\"mountly-mcp: apps must contain at least one View\");\n\n const names = new Set<string>();\n const uris = new Set<string>();\n for (const app of apps) {\n if (!app.uri.startsWith(\"ui://\")) {\n throw new Error(\n `mountly-mcp: UI resource uri must use the 'ui://' scheme (received '${app.uri}')`,\n );\n }\n if (names.has(app.name)) throw new Error(`mountly-mcp: duplicate app name '${app.name}'`);\n if (uris.has(app.uri)) throw new Error(`mountly-mcp: duplicate app uri '${app.uri}'`);\n names.add(app.name);\n uris.add(app.uri);\n }\n\n const environments = apps.map((app, index) => ({\n app,\n name: safeBuildName(app.name, index),\n jsFile: `view-${index}-${basename(app.name)}.js`,\n cssFile: `view-${index}-${basename(app.name)}.css`,\n }));\n const byEnvironment = new Map(environments.map((environment) => [environment.name, environment]));\n const emitted = new Map<\n string,\n { js?: string; css?: string; jsFile?: string; cssFile?: string; names: string[] }\n >();\n const artifacts = new Map<string, McpAppArtifact>();\n let root = process.cwd();\n let outDir = resolve(root, \"dist\");\n let manifestWritten = false;\n\n function currentEnvironment(context: unknown) {\n const name = (context as { environment?: { name?: string } }).environment?.name;\n return (\n (name ? byEnvironment.get(name) : undefined) ??\n (environments.length === 1 ? environments[0] : undefined)\n );\n }\n\n const plugin: Plugin = {\n name: \"mountly-mcp-views\",\n api: {\n // The CLI consumes this documented plugin interface instead of scraping\n // Vite's resolved build settings.\n mountlyMcp: { apps: configuredApps, manifest: manifestOption } satisfies MountlyMcpViteApi,\n },\n // After Vite core plugins: css-post writes the stylesheet in its own\n // closeBundle, and this plugin has to see the file to inline it.\n enforce: \"post\",\n // Only meaningful during `vite build`; a dev server has no bundle to emit.\n apply: \"build\",\n\n config(_config, env): UserConfig {\n const first = environments[0];\n if (!first) throw new Error(\"mountly-mcp: configure at least one app\");\n return {\n // Vite's lib mode leaves `process.env.NODE_ENV` for a consuming bundler\n // to replace. There isn't one — the bundle is inlined into HTML and run\n // in a sandboxed iframe, where `process` is undefined and React and Vue\n // throw on their first environment check.\n define: { \"process.env.NODE_ENV\": JSON.stringify(env.mode) },\n // Legacy `vite build` builds one environment. Preserve that zero-config\n // path for single-View projects; multi-View projects use\n // `mountly-mcp build`, which drives the environments below.\n build: {\n lib: {\n entry: first.app.entry,\n // IIFE so the bundle inlines into a single <script> with no import\n // graph left to resolve inside the sandboxed iframe.\n formats: [\"iife\"] as const,\n name: \"__mountlyMcpEntry0\",\n fileName: () => first.jsFile,\n // Named explicitly: otherwise a lib build derives the stylesheet\n // name from package.json and fails outright when there isn't one.\n cssFileName: first.cssFile.replace(/\\.css$/, \"\"),\n },\n // One stylesheet to inline; per-chunk CSS would strand imports.\n cssCodeSplit: false,\n },\n builder: {\n sharedPlugins: true,\n async buildApp(builder) {\n for (const environment of environments) {\n const target = builder.environments[environment.name] as BuildEnvironment | undefined;\n if (!target)\n throw new Error(`mountly-mcp: missing Vite environment '${environment.name}'`);\n await builder.build(target);\n }\n },\n },\n environments: Object.fromEntries(\n environments.map((environment, index) => [\n environment.name,\n {\n // A custom environment defaults to a server consumer, which\n // externalizes node_modules — React and Vue would become bare\n // globals and the view would die on `vue is not defined`. A\n // `ui://` resource has no import graph at runtime, so everything\n // must be bundled in.\n consumer: \"client\" as const,\n resolve: { noExternal: true as const },\n build: {\n emptyOutDir: index === 0,\n lib: {\n entry: environment.app.entry,\n formats: [\"iife\"] as const,\n name: `__mountlyMcpEntry${index}`,\n fileName: () => environment.jsFile,\n cssFileName: environment.cssFile.replace(/\\.css$/, \"\"),\n },\n cssCodeSplit: false,\n },\n },\n ]),\n ),\n };\n },\n\n configResolved(config) {\n root = config.root;\n outDir = resolve(config.root, config.build.outDir);\n },\n\n buildStart() {\n const name = (this as { environment?: { name?: string } }).environment?.name;\n if (apps.length > 1 && !byEnvironment.has(String(name))) {\n this.error(\n \"mountly-mcp: multi-View builds require 'mountly-mcp build' (or 'vite build --app') so Vite builds every environment\",\n );\n }\n },\n\n generateBundle: {\n order: \"post\",\n handler(_outputOptions, bundle) {\n const environment = currentEnvironment(this);\n if (!environment) return;\n const chunk =\n bundle[environment.jsFile] ??\n Object.values(bundle).find((item) => item.type === \"chunk\" && item.isEntry);\n const cssAsset =\n bundle[environment.cssFile] ??\n Object.values(bundle).find(\n (item) => item.type === \"asset\" && item.fileName.endsWith(\".css\"),\n );\n emitted.set(environment.name, {\n js: chunk && \"code\" in chunk ? chunk.code : undefined,\n css: cssAsset && \"source\" in cssAsset ? cssAsset.source.toString() : undefined,\n jsFile: chunk?.fileName,\n cssFile: cssAsset?.fileName,\n names: Object.keys(bundle),\n });\n },\n },\n\n async closeBundle() {\n const environment = currentEnvironment(this);\n if (!environment || artifacts.has(environment.name)) return;\n const source = emitted.get(environment.name);\n if (source?.js === undefined) {\n this.error(\n `mountly-mcp: the build emitted no ${environment.jsFile} for '${environment.app.entry}'. Emitted: ${source?.names.join(\", \") || \"nothing\"}`,\n );\n return;\n }\n const {\n entry: _entry,\n output: _output,\n cleanIntermediate = true,\n ...resourceOptions\n } = environment.app;\n const result = await buildMcpResourceFromSource({\n ...resourceOptions,\n js: source.js,\n css: source.css,\n output: outputPath(root, outDir, environment.app),\n });\n artifacts.set(environment.name, result.artifact);\n if (cleanIntermediate) {\n if (source.jsFile) await rm(join(outDir, source.jsFile), { force: true });\n if (source.cssFile) await rm(join(outDir, source.cssFile), { force: true });\n }\n this.info?.(`mountly-mcp: ${environment.app.uri} → ${result.htmlPath}`);\n\n if (!manifestWritten && artifacts.size === environments.length && manifestOption !== false) {\n manifestWritten = true;\n const path = manifestOption\n ? isAbsolute(manifestOption)\n ? manifestOption\n : resolve(root, manifestOption)\n : join(outDir, MCP_APP_MANIFEST_FILE);\n await writeMcpAppManifest(\n path,\n environments.map((item) => artifacts.get(item.name) as McpAppArtifact),\n );\n this.info?.(`mountly-mcp: manifest → ${path}`);\n }\n },\n };\n\n return plugin;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/vite/index.ts"],"sourcesContent":["import { readFile, rm, writeFile } from \"node:fs/promises\";\nimport { basename, isAbsolute, join, resolve } from \"node:path\";\nimport { parseAst, type BuildEnvironment, type Plugin, type UserConfig } from \"vite\";\nimport { MCP_APP_MANIFEST_FILE, writeMcpAppManifest } from \"../artifact/index.js\";\nimport type { McpAppArtifact } from \"../artifact/index.js\";\nimport { buildMcpResourceFromSource } from \"../build/index.js\";\nimport type { BuildSelfContainedOptions } from \"../build/index.js\";\n\nexport interface MountlyMcpViewOptions extends Omit<\n BuildSelfContainedOptions,\n \"entry\" | \"output\" | \"cssEntry\"\n> {\n entry: string;\n output?: string;\n cleanIntermediate?: boolean;\n}\n\nexport interface MountlyMcpViewsOptions {\n apps: ReadonlyArray<MountlyMcpViewOptions>;\n /** Defaults to `<outDir>/mountly-mcp.manifest.json`; false disables it. */\n manifest?: string | false;\n /**\n * Also write every View, HTML included, as an ES module, for a server that\n * cannot read files — Cloudflare Workers, say: `import views from\n * \"./dist/mountly-mcp.views.js\"`, then `views.map((artifact) => ({ artifact }))`.\n * `true` writes `<outDir>/mountly-mcp.views.js`; a string names the path.\n */\n module?: string | boolean;\n}\n\nexport const MCP_APP_VIEWS_MODULE_FILE = \"mountly-mcp.views.js\";\n\n/** `mountly-mcp.views.js` and the declaration beside it. */\nasync function writeViewsModule(path: string, artifacts: ReadonlyArray<McpAppArtifact>) {\n const views = await Promise.all(\n artifacts.map(async ({ name, uri, declaration, htmlPath }) => ({\n name,\n uri,\n declaration,\n html: await readFile(htmlPath, \"utf8\"),\n })),\n );\n await writeFile(\n path,\n `// Generated by mountly-mcp. Do not edit.\\nexport default ${JSON.stringify(views, null, 2)};\\n`,\n \"utf8\",\n );\n await writeFile(\n // `views.mjs` pairs with `views.d.mts`, which is where TypeScript looks.\n path.replace(/\\.(m?)js$/, \".d.$1ts\"),\n `// Generated by mountly-mcp. Do not edit.\\nimport type { McpAppSource } from \"mountly-mcp/artifact\";\\ndeclare const views: ReadonlyArray<McpAppSource>;\\nexport default views;\\n`,\n \"utf8\",\n );\n}\n\nexport type MountlyMcpViteOptions = MountlyMcpViewOptions | MountlyMcpViewsOptions;\n\nexport interface MountlyMcpViteApi {\n apps: ReadonlyArray<MountlyMcpViewOptions>;\n manifest?: string | false;\n}\n\nfunction isCollection(options: MountlyMcpViteOptions): options is MountlyMcpViewsOptions {\n return \"apps\" in options;\n}\n\nfunction safeBuildName(name: string, index: number): string {\n const safe = name.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n return `mountly_mcp_${index}_${safe || \"app\"}`;\n}\n\nfunction outputPath(root: string, outDir: string, app: MountlyMcpViewOptions): string {\n if (!app.output) return join(outDir, `${basename(app.name)}.html`);\n return isAbsolute(app.output) ? app.output : resolve(root, app.output);\n}\n\n/**\n * `new Worker(new URL(\"./w.ts\", import.meta.url), …)` emits the worker as its own\n * file, which a `ui://` resource cannot serve: the View is one HTML document.\n * Rewrite each to Vite's `?worker&inline` import, which bundles the worker into\n * the View and starts it from a blob URL — so the host's CSP must allow\n * `worker-src blob:`. Workers built any other way are left alone; `mountly-mcp\n * doctor` points them out.\n */\ntype Node = Record<string, any>;\ntype Edit = [start: number, end: number, text: string];\n\nfunction isImportMetaUrl(node: Node | undefined): boolean {\n return (\n node?.type === \"MemberExpression\" &&\n node.object?.type === \"MetaProperty\" &&\n node.object.meta?.name === \"import\" &&\n node.object.property?.name === \"meta\" &&\n node.property?.name === \"url\"\n );\n}\n\nfunction stringValue(node: Node | undefined): string | undefined {\n if (node?.type === \"Literal\" && typeof node.value === \"string\") return node.value;\n if (node?.type === \"TemplateLiteral\" && node.expressions.length === 0) {\n return node.quasis[0]?.value?.cooked;\n }\n return undefined;\n}\n\n/**\n * The edits for every worker call in one script. Parsed, not pattern-matched:\n * the same characters in a comment or a string are not a call.\n */\nfunction workerEdits(\n script: string,\n lang: \"js\" | \"jsx\" | \"ts\" | \"tsx\",\n offset: number,\n imports: string[],\n count: { n: number },\n): Edit[] {\n const edits: Edit[] = [];\n const walk = (node: unknown): void => {\n if (Array.isArray(node)) return node.forEach(walk);\n if (!node || typeof node !== \"object\") return;\n const n = node as Node;\n if (\n n.type === \"NewExpression\" &&\n (n.callee?.name === \"Worker\" || n.callee?.name === \"SharedWorker\")\n ) {\n const [url, options] = n.arguments ?? [];\n const path =\n url?.type === \"NewExpression\" && url.callee?.name === \"URL\"\n ? stringValue(url.arguments?.[0])\n : undefined;\n if (path !== undefined && isImportMetaUrl(url.arguments?.[1])) {\n const id = `__mountlyMcpWorker${count.n++}`;\n const query = n.callee.name === \"SharedWorker\" ? \"sharedworker\" : \"worker\";\n imports.push(`import ${id} from ${JSON.stringify(`${path}?${query}&inline`)};`);\n // The wrapper takes the options object (it reads `name`) as its only\n // argument. Without one, the whole call goes, trailing comma included.\n const end = options ? options.start : n.end;\n const text = options ? `new ${id}(` : `new ${id}()`;\n // Keep the span's line breaks, so every later line keeps its number.\n const breaks = script.slice(n.start, end).split(\"\\n\").length - 1;\n edits.push([offset + n.start, offset + end, text + \"\\n\".repeat(breaks)]);\n }\n }\n for (const key in n) walk(n[key]);\n };\n walk(parseAst(script, { lang }));\n return edits;\n}\n\nfunction langOf(file: string, attributes = \"\"): \"js\" | \"jsx\" | \"ts\" | \"tsx\" {\n const lang =\n /\\blang\\s*=\\s*[\"']?(tsx|ts|jsx|js)\\b/.exec(attributes)?.[1] ??\n /\\.([cm]?[jt]sx?)$/.exec(file)?.[1];\n if (lang === \"tsx\" || lang === \"jsx\") return lang;\n return lang && /ts$/.test(lang) ? \"ts\" : \"js\";\n}\n\n/**\n * Rewrite a module's worker calls. In a `.vue` or `.svelte` file each\n * `<script>` is parsed on its own, and its imports go inside that block —\n * anything outside it is not script, and the compiler drops it.\n */\nexport function inlineWorkers(code: string, file = \"view.ts\"): string | null {\n if (!code.includes(\"import.meta\")) return null;\n const edits: Edit[] = [];\n const count = { n: 0 };\n try {\n if (/\\.(vue|svelte)$/.test(file)) {\n for (const block of code.matchAll(/(<script\\b([^>]*)>)([\\s\\S]*?)<\\/script>/g)) {\n const start = (block.index ?? 0) + (block[1]?.length ?? 0);\n const imports: string[] = [];\n edits.push(...workerEdits(block[3] ?? \"\", langOf(file, block[2]), start, imports, count));\n if (imports.length) edits.push([start, start, imports.join(\"\")]);\n }\n } else {\n const imports: string[] = [];\n edits.push(...workerEdits(code, langOf(file), 0, imports, count));\n if (imports.length) edits.push([0, 0, imports.join(\"\")]);\n }\n } catch {\n // Unparseable here means some later plugin owns this syntax; leave it to Vite.\n return null;\n }\n if (!edits.length) return null;\n let out = code;\n // Right to left, so earlier offsets stay valid.\n for (const [start, end, text] of edits.sort((a, b) => b[0] - a[0] || b[1] - a[1])) {\n out = out.slice(0, start) + text + out.slice(end);\n }\n return out;\n}\n\n/**\n * Build one or many independent MCP Apps Views. Each View is a Vite build\n * environment, so frameworks and CSS remain isolated while callers configure\n * the collection once.\n */\nexport function mountlyMcpViews(options: MountlyMcpViteOptions): Plugin {\n const configuredApps = isCollection(options) ? [...options.apps] : [options];\n const selectedForDev = process.env.MOUNTLY_MCP_SELECTED_APP;\n const apps = selectedForDev\n ? configuredApps.filter((app) => app.name === selectedForDev)\n : configuredApps;\n const manifestOption = isCollection(options) ? options.manifest : undefined;\n const moduleOption = isCollection(options) ? options.module : undefined;\n if (typeof moduleOption === \"string\" && !/\\.m?js$/.test(moduleOption)) {\n throw new Error(\n `mountly-mcp: module must name a .js or .mjs file (received '${moduleOption}')`,\n );\n }\n if (apps.length === 0) throw new Error(\"mountly-mcp: apps must contain at least one View\");\n\n const names = new Set<string>();\n const uris = new Set<string>();\n for (const app of apps) {\n if (!app.uri.startsWith(\"ui://\")) {\n throw new Error(\n `mountly-mcp: UI resource uri must use the 'ui://' scheme (received '${app.uri}')`,\n );\n }\n if (names.has(app.name)) throw new Error(`mountly-mcp: duplicate app name '${app.name}'`);\n if (uris.has(app.uri)) throw new Error(`mountly-mcp: duplicate app uri '${app.uri}'`);\n names.add(app.name);\n uris.add(app.uri);\n }\n\n const environments = apps.map((app, index) => ({\n app,\n name: safeBuildName(app.name, index),\n jsFile: `view-${index}-${basename(app.name)}.js`,\n cssFile: `view-${index}-${basename(app.name)}.css`,\n }));\n const byEnvironment = new Map(environments.map((environment) => [environment.name, environment]));\n const emitted = new Map<\n string,\n { js?: string; css?: string; jsFile?: string; cssFile?: string; names: string[] }\n >();\n const artifacts = new Map<string, McpAppArtifact>();\n let root = process.cwd();\n let outDir = resolve(root, \"dist\");\n let manifestWritten = false;\n\n function currentEnvironment(context: unknown) {\n const name = (context as { environment?: { name?: string } }).environment?.name;\n return (\n (name ? byEnvironment.get(name) : undefined) ??\n (environments.length === 1 ? environments[0] : undefined)\n );\n }\n\n const plugin: Plugin = {\n name: \"mountly-mcp-views\",\n api: {\n // The CLI consumes this documented plugin interface instead of scraping\n // Vite's resolved build settings.\n mountlyMcp: { apps: configuredApps, manifest: manifestOption } satisfies MountlyMcpViteApi,\n },\n // After Vite core plugins: css-post writes the stylesheet in its own\n // closeBundle, and this plugin has to see the file to inline it.\n enforce: \"post\",\n // Only meaningful during `vite build`; a dev server has no bundle to emit.\n apply: \"build\",\n\n // Before TypeScript is stripped and before Vite's own worker plugin claims\n // the `new URL(…)` and emits a separate file.\n transform: {\n order: \"pre\",\n handler(code, id) {\n if (id.includes(\"/node_modules/\") || id.includes(\"?\")) return null;\n const out = inlineWorkers(code, id);\n return out === null ? null : { code: out, map: null };\n },\n },\n\n config(config, env): UserConfig {\n const first = environments[0];\n if (!first) throw new Error(\"mountly-mcp: configure at least one app\");\n return {\n // An inline worker is one blob, so its own bundle must be one file too.\n ...(config.worker?.format ? {} : { worker: { format: \"iife\" as const } }),\n // Vite's lib mode leaves `process.env.NODE_ENV` for a consuming bundler\n // to replace. There isn't one — the bundle is inlined into HTML and run\n // in a sandboxed iframe, where `process` is undefined and React and Vue\n // throw on their first environment check.\n define: { \"process.env.NODE_ENV\": JSON.stringify(env.mode) },\n // Legacy `vite build` builds one environment. Preserve that zero-config\n // path for single-View projects; multi-View projects use\n // `mountly-mcp build`, which drives the environments below.\n build: {\n lib: {\n entry: first.app.entry,\n // IIFE so the bundle inlines into a single <script> with no import\n // graph left to resolve inside the sandboxed iframe.\n formats: [\"iife\"] as const,\n name: \"__mountlyMcpEntry0\",\n fileName: () => first.jsFile,\n // Named explicitly: otherwise a lib build derives the stylesheet\n // name from package.json and fails outright when there isn't one.\n cssFileName: first.cssFile.replace(/\\.css$/, \"\"),\n },\n // One stylesheet to inline; per-chunk CSS would strand imports.\n cssCodeSplit: false,\n },\n builder: {\n sharedPlugins: true,\n async buildApp(builder) {\n for (const environment of environments) {\n const target = builder.environments[environment.name] as BuildEnvironment | undefined;\n if (!target)\n throw new Error(`mountly-mcp: missing Vite environment '${environment.name}'`);\n await builder.build(target);\n }\n },\n },\n environments: Object.fromEntries(\n environments.map((environment, index) => [\n environment.name,\n {\n // A custom environment defaults to a server consumer, which\n // externalizes node_modules — React and Vue would become bare\n // globals and the view would die on `vue is not defined`. A\n // `ui://` resource has no import graph at runtime, so everything\n // must be bundled in.\n consumer: \"client\" as const,\n resolve: { noExternal: true as const },\n build: {\n emptyOutDir: index === 0,\n lib: {\n entry: environment.app.entry,\n formats: [\"iife\"] as const,\n name: `__mountlyMcpEntry${index}`,\n fileName: () => environment.jsFile,\n cssFileName: environment.cssFile.replace(/\\.css$/, \"\"),\n },\n cssCodeSplit: false,\n },\n },\n ]),\n ),\n };\n },\n\n configResolved(config) {\n root = config.root;\n outDir = resolve(config.root, config.build.outDir);\n },\n\n buildStart() {\n const name = (this as { environment?: { name?: string } }).environment?.name;\n if (apps.length > 1 && !byEnvironment.has(String(name))) {\n this.error(\n \"mountly-mcp: multi-View builds require 'mountly-mcp build' (or 'vite build --app') so Vite builds every environment\",\n );\n }\n },\n\n generateBundle: {\n order: \"post\",\n handler(_outputOptions, bundle) {\n const environment = currentEnvironment(this);\n if (!environment) return;\n const chunk =\n bundle[environment.jsFile] ??\n Object.values(bundle).find((item) => item.type === \"chunk\" && item.isEntry);\n const cssAsset =\n bundle[environment.cssFile] ??\n Object.values(bundle).find(\n (item) => item.type === \"asset\" && item.fileName.endsWith(\".css\"),\n );\n emitted.set(environment.name, {\n js: chunk && \"code\" in chunk ? chunk.code : undefined,\n css: cssAsset && \"source\" in cssAsset ? cssAsset.source.toString() : undefined,\n jsFile: chunk?.fileName,\n cssFile: cssAsset?.fileName,\n names: Object.keys(bundle),\n });\n },\n },\n\n async closeBundle() {\n const environment = currentEnvironment(this);\n if (!environment || artifacts.has(environment.name)) return;\n const source = emitted.get(environment.name);\n if (source?.js === undefined) {\n this.error(\n `mountly-mcp: the build emitted no ${environment.jsFile} for '${environment.app.entry}'. Emitted: ${source?.names.join(\", \") || \"nothing\"}`,\n );\n return;\n }\n const {\n entry: _entry,\n output: _output,\n cleanIntermediate = true,\n ...resourceOptions\n } = environment.app;\n const result = await buildMcpResourceFromSource({\n ...resourceOptions,\n js: source.js,\n css: source.css,\n output: outputPath(root, outDir, environment.app),\n });\n artifacts.set(environment.name, result.artifact);\n if (cleanIntermediate) {\n if (source.jsFile) await rm(join(outDir, source.jsFile), { force: true });\n if (source.cssFile) await rm(join(outDir, source.cssFile), { force: true });\n }\n this.info?.(`mountly-mcp: ${environment.app.uri} → ${result.htmlPath}`);\n\n if (manifestWritten || artifacts.size !== environments.length) return;\n manifestWritten = true;\n const all = environments.map((item) => artifacts.get(item.name) as McpAppArtifact);\n const at = (path: string) => (isAbsolute(path) ? path : resolve(root, path));\n if (manifestOption !== false) {\n const path = manifestOption ? at(manifestOption) : join(outDir, MCP_APP_MANIFEST_FILE);\n await writeMcpAppManifest(path, all);\n this.info?.(`mountly-mcp: manifest → ${path}`);\n }\n if (moduleOption) {\n const path =\n typeof moduleOption === \"string\"\n ? at(moduleOption)\n : join(outDir, MCP_APP_VIEWS_MODULE_FILE);\n await writeViewsModule(path, all);\n this.info?.(`mountly-mcp: views module → ${path}`);\n }\n },\n };\n\n return plugin;\n}\n"],"mappings":"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","names":[]}
|
package/dist/vue/index.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ import { type Component, type ComputedRef, type InjectionKey } from "vue";
|
|
|
16
16
|
import type { AdapterOptions } from "mountly/adapter";
|
|
17
17
|
import type { App, McpUiDisplayMode, McpUiHostContext } from "@modelcontextprotocol/ext-apps";
|
|
18
18
|
import type { McpView, McpViewProps } from "../types.js";
|
|
19
|
+
import { type DownloadableFile } from "../download.js";
|
|
19
20
|
/** What {@link createMcpView} provides to descendants. */
|
|
20
21
|
export interface McpVueContext {
|
|
21
22
|
app: App;
|
|
@@ -29,6 +30,11 @@ export declare const McpInjectionKey: InjectionKey<ComputedRef<McpVueContext>>;
|
|
|
29
30
|
export declare function createMcpView<P extends object>(Component: Component<P>, options?: AdapterOptions): McpView;
|
|
30
31
|
/** The view-side ext-apps App: call server tools, send messages, open links. */
|
|
31
32
|
export declare function useMcpApp(): App;
|
|
33
|
+
/**
|
|
34
|
+
* Return a function that hands the user a file: through the host's
|
|
35
|
+
* `ui/download-file` where it has one, else an ordinary `<a download>`.
|
|
36
|
+
*/
|
|
37
|
+
export declare function useDownload(): (file: DownloadableFile) => Promise<boolean>;
|
|
32
38
|
/** Complete notification params; read the tool arguments from `.arguments`. */
|
|
33
39
|
export declare function useToolInput<T = unknown>(): ComputedRef<T | undefined>;
|
|
34
40
|
/**
|
package/dist/vue/index.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
downloadFile
|
|
3
|
+
} from "../chunk-BLT2MK32.js";
|
|
1
4
|
import {
|
|
2
5
|
publishMcpView
|
|
3
6
|
} from "../chunk-5L3QHYWK.js";
|
|
@@ -49,6 +52,10 @@ function useEnsuredContext() {
|
|
|
49
52
|
function useMcpApp() {
|
|
50
53
|
return useEnsuredContext().value.app;
|
|
51
54
|
}
|
|
55
|
+
function useDownload() {
|
|
56
|
+
const context = useEnsuredContext();
|
|
57
|
+
return (file) => downloadFile(context.value.app, file);
|
|
58
|
+
}
|
|
52
59
|
function useToolInput() {
|
|
53
60
|
const context = useEnsuredContext();
|
|
54
61
|
return computed(() => context.value.toolInput);
|
|
@@ -83,6 +90,7 @@ export {
|
|
|
83
90
|
McpInjectionKey,
|
|
84
91
|
createMcpView,
|
|
85
92
|
useDisplayMode,
|
|
93
|
+
useDownload,
|
|
86
94
|
useHostContext,
|
|
87
95
|
useMcpApp,
|
|
88
96
|
useRequestDisplayMode,
|
package/dist/vue/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/vue/index.ts"],"sourcesContent":["/**\n * Vue entry point: turn a Vue component into an MCP App View.\n *\n * ```ts\n * import { createMcpView } from \"mountly-mcp/vue\";\n * import Dashboard from \"./Dashboard.vue\";\n *\n * createMcpView(Dashboard);\n * ```\n *\n * The component receives the bridge's props (`mcp`, `toolInput`, `toolResult`,\n * `hostContext`) and can also reach them from any depth with the composables\n * below, which mirror `mountly-mcp/react`'s hooks.\n */\nimport {\n computed,\n defineComponent,\n h,\n inject,\n provide,\n type Component,\n type ComputedRef,\n type InjectionKey,\n} from \"vue\";\nimport { createWidget } from \"mountly-vue\";\nimport type { AdapterOptions } from \"mountly/adapter\";\nimport type { App, McpUiDisplayMode, McpUiHostContext } from \"@modelcontextprotocol/ext-apps\";\nimport type { McpView, McpViewProps } from \"../types.js\";\nimport { publishMcpView } from \"../publish.js\";\n\n/** What {@link createMcpView} provides to descendants. */\nexport interface McpVueContext {\n app: App;\n toolInput?: McpViewProps[\"toolInput\"];\n toolInputPartial?: McpViewProps[\"toolInputPartial\"];\n toolResult?: McpViewProps[\"toolResult\"];\n hostContext?: McpUiHostContext;\n}\n\nexport const McpInjectionKey: InjectionKey<ComputedRef<McpVueContext>> = Symbol(\"mountly-mcp\");\n\n/** Wraps a Vue component as an MCP Apps View and publishes it for the bridge. */\nexport function createMcpView<P extends object>(\n Component: Component<P>,\n options?: AdapterOptions,\n): McpView {\n const Wrapped = defineComponent({\n name: \"MountlyMcpProvider\",\n inheritAttrs: false,\n props: {\n mcp: { type: Object, required: true },\n toolInput: { type: Object, default: undefined },\n toolInputPartial: { type: Object, default: undefined },\n toolResult: { type: Object, default: undefined },\n hostContext: { type: Object, default: undefined },\n },\n setup(props, { attrs }) {\n const context = computed<McpVueContext>(() => ({\n app: props.mcp as App,\n toolInput: props.toolInput as McpVueContext[\"toolInput\"],\n toolInputPartial: props.toolInputPartial as McpVueContext[\"toolInputPartial\"],\n toolResult: props.toolResult as McpVueContext[\"toolResult\"],\n hostContext: props.hostContext as McpUiHostContext | undefined,\n }));\n provide(McpInjectionKey, context);\n return () => h(Component as Component, attrs);\n },\n });\n return publishMcpView(createWidget(Wrapped, options));\n}\n\nfunction useEnsuredContext(): ComputedRef<McpVueContext> {\n const context = inject(McpInjectionKey, null);\n if (!context) {\n throw new Error(\n \"mountly-mcp/vue: useMcpApp/useToolResult/etc must be used inside a component wrapped with createMcpView().\",\n );\n }\n return context;\n}\n\n/** The view-side ext-apps App: call server tools, send messages, open links. */\nexport function useMcpApp(): App {\n return useEnsuredContext().value.app;\n}\n\n/** Complete notification params; read the tool arguments from `.arguments`. */\nexport function useToolInput<T = unknown>(): ComputedRef<T | undefined> {\n const context = useEnsuredContext();\n return computed(() => context.value.toolInput as T | undefined);\n}\n\n/**\n * Streaming tool arguments (`ui/notifications/tool-input-partial`), present only\n * when the bridge runs with `streamToolInput`. Best-effort recovered JSON —\n * render loading states from it, never critical operations.\n */\nexport function useToolInputPartial<T = unknown>(): ComputedRef<Partial<T> | undefined> {\n const context = useEnsuredContext();\n return computed(() => context.value.toolInputPartial as Partial<T> | undefined);\n}\n\n/** Complete MCP tool result; structured data is available at `.structuredContent`. */\nexport function useToolResult<T = unknown>(): ComputedRef<T | undefined> {\n const context = useEnsuredContext();\n return computed(() => context.value.toolResult as T | undefined);\n}\n\n/** Latest host context (theme, styles, displayMode, container dimensions). */\nexport function useHostContext(): ComputedRef<McpUiHostContext | undefined> {\n const context = useEnsuredContext();\n return computed(() => context.value.hostContext);\n}\n\n/** Current display mode reported by the host. */\nexport function useDisplayMode(): ComputedRef<McpUiDisplayMode | undefined> {\n const context = useEnsuredContext();\n return computed(() => context.value.hostContext?.displayMode);\n}\n\n/**\n * Request a display mode change, resolving to the mode the host actually\n * applied. Modes the host didn't advertise are never requested — the spec\n * requires views to check `availableDisplayModes` first.\n */\nexport function useRequestDisplayMode(): (\n mode: McpUiDisplayMode,\n) => Promise<McpUiDisplayMode | undefined> {\n const context = useEnsuredContext();\n return async (mode) => {\n const { app, hostContext } = context.value;\n const available = hostContext?.availableDisplayModes;\n if (available && !available.includes(mode)) return hostContext?.displayMode;\n const result = await app.requestDisplayMode({ mode });\n return result.mode;\n };\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../src/vue/index.ts"],"sourcesContent":["/**\n * Vue entry point: turn a Vue component into an MCP App View.\n *\n * ```ts\n * import { createMcpView } from \"mountly-mcp/vue\";\n * import Dashboard from \"./Dashboard.vue\";\n *\n * createMcpView(Dashboard);\n * ```\n *\n * The component receives the bridge's props (`mcp`, `toolInput`, `toolResult`,\n * `hostContext`) and can also reach them from any depth with the composables\n * below, which mirror `mountly-mcp/react`'s hooks.\n */\nimport {\n computed,\n defineComponent,\n h,\n inject,\n provide,\n type Component,\n type ComputedRef,\n type InjectionKey,\n} from \"vue\";\nimport { createWidget } from \"mountly-vue\";\nimport type { AdapterOptions } from \"mountly/adapter\";\nimport type { App, McpUiDisplayMode, McpUiHostContext } from \"@modelcontextprotocol/ext-apps\";\nimport type { McpView, McpViewProps } from \"../types.js\";\nimport { publishMcpView } from \"../publish.js\";\nimport { downloadFile, type DownloadableFile } from \"../download.js\";\n\n/** What {@link createMcpView} provides to descendants. */\nexport interface McpVueContext {\n app: App;\n toolInput?: McpViewProps[\"toolInput\"];\n toolInputPartial?: McpViewProps[\"toolInputPartial\"];\n toolResult?: McpViewProps[\"toolResult\"];\n hostContext?: McpUiHostContext;\n}\n\nexport const McpInjectionKey: InjectionKey<ComputedRef<McpVueContext>> = Symbol(\"mountly-mcp\");\n\n/** Wraps a Vue component as an MCP Apps View and publishes it for the bridge. */\nexport function createMcpView<P extends object>(\n Component: Component<P>,\n options?: AdapterOptions,\n): McpView {\n const Wrapped = defineComponent({\n name: \"MountlyMcpProvider\",\n inheritAttrs: false,\n props: {\n mcp: { type: Object, required: true },\n toolInput: { type: Object, default: undefined },\n toolInputPartial: { type: Object, default: undefined },\n toolResult: { type: Object, default: undefined },\n hostContext: { type: Object, default: undefined },\n },\n setup(props, { attrs }) {\n const context = computed<McpVueContext>(() => ({\n app: props.mcp as App,\n toolInput: props.toolInput as McpVueContext[\"toolInput\"],\n toolInputPartial: props.toolInputPartial as McpVueContext[\"toolInputPartial\"],\n toolResult: props.toolResult as McpVueContext[\"toolResult\"],\n hostContext: props.hostContext as McpUiHostContext | undefined,\n }));\n provide(McpInjectionKey, context);\n return () => h(Component as Component, attrs);\n },\n });\n return publishMcpView(createWidget(Wrapped, options));\n}\n\nfunction useEnsuredContext(): ComputedRef<McpVueContext> {\n const context = inject(McpInjectionKey, null);\n if (!context) {\n throw new Error(\n \"mountly-mcp/vue: useMcpApp/useToolResult/etc must be used inside a component wrapped with createMcpView().\",\n );\n }\n return context;\n}\n\n/** The view-side ext-apps App: call server tools, send messages, open links. */\nexport function useMcpApp(): App {\n return useEnsuredContext().value.app;\n}\n\n/**\n * Return a function that hands the user a file: through the host's\n * `ui/download-file` where it has one, else an ordinary `<a download>`.\n */\nexport function useDownload(): (file: DownloadableFile) => Promise<boolean> {\n const context = useEnsuredContext();\n return (file) => downloadFile(context.value.app, file);\n}\n\n/** Complete notification params; read the tool arguments from `.arguments`. */\nexport function useToolInput<T = unknown>(): ComputedRef<T | undefined> {\n const context = useEnsuredContext();\n return computed(() => context.value.toolInput as T | undefined);\n}\n\n/**\n * Streaming tool arguments (`ui/notifications/tool-input-partial`), present only\n * when the bridge runs with `streamToolInput`. Best-effort recovered JSON —\n * render loading states from it, never critical operations.\n */\nexport function useToolInputPartial<T = unknown>(): ComputedRef<Partial<T> | undefined> {\n const context = useEnsuredContext();\n return computed(() => context.value.toolInputPartial as Partial<T> | undefined);\n}\n\n/** Complete MCP tool result; structured data is available at `.structuredContent`. */\nexport function useToolResult<T = unknown>(): ComputedRef<T | undefined> {\n const context = useEnsuredContext();\n return computed(() => context.value.toolResult as T | undefined);\n}\n\n/** Latest host context (theme, styles, displayMode, container dimensions). */\nexport function useHostContext(): ComputedRef<McpUiHostContext | undefined> {\n const context = useEnsuredContext();\n return computed(() => context.value.hostContext);\n}\n\n/** Current display mode reported by the host. */\nexport function useDisplayMode(): ComputedRef<McpUiDisplayMode | undefined> {\n const context = useEnsuredContext();\n return computed(() => context.value.hostContext?.displayMode);\n}\n\n/**\n * Request a display mode change, resolving to the mode the host actually\n * applied. Modes the host didn't advertise are never requested — the spec\n * requires views to check `availableDisplayModes` first.\n */\nexport function useRequestDisplayMode(): (\n mode: McpUiDisplayMode,\n) => Promise<McpUiDisplayMode | undefined> {\n const context = useEnsuredContext();\n return async (mode) => {\n const { app, hostContext } = context.value;\n const available = hostContext?.availableDisplayModes;\n if (available && !available.includes(mode)) return hostContext?.displayMode;\n const result = await app.requestDisplayMode({ mode });\n return result.mode;\n };\n}\n"],"mappings":";;;;;;;;AAcA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AACP,SAAS,oBAAoB;AAgBtB,IAAM,kBAA4D,uBAAO,aAAa;AAGtF,SAAS,cACd,WACA,SACS;AACT,QAAM,UAAU,gBAAgB;AAAA,IAC9B,MAAM;AAAA,IACN,cAAc;AAAA,IACd,OAAO;AAAA,MACL,KAAK,EAAE,MAAM,QAAQ,UAAU,KAAK;AAAA,MACpC,WAAW,EAAE,MAAM,QAAQ,SAAS,OAAU;AAAA,MAC9C,kBAAkB,EAAE,MAAM,QAAQ,SAAS,OAAU;AAAA,MACrD,YAAY,EAAE,MAAM,QAAQ,SAAS,OAAU;AAAA,MAC/C,aAAa,EAAE,MAAM,QAAQ,SAAS,OAAU;AAAA,IAClD;AAAA,IACA,MAAM,OAAO,EAAE,MAAM,GAAG;AACtB,YAAM,UAAU,SAAwB,OAAO;AAAA,QAC7C,KAAK,MAAM;AAAA,QACX,WAAW,MAAM;AAAA,QACjB,kBAAkB,MAAM;AAAA,QACxB,YAAY,MAAM;AAAA,QAClB,aAAa,MAAM;AAAA,MACrB,EAAE;AACF,cAAQ,iBAAiB,OAAO;AAChC,aAAO,MAAM,EAAE,WAAwB,KAAK;AAAA,IAC9C;AAAA,EACF,CAAC;AACD,SAAO,eAAe,aAAa,SAAS,OAAO,CAAC;AACtD;AAEA,SAAS,oBAAgD;AACvD,QAAM,UAAU,OAAO,iBAAiB,IAAI;AAC5C,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,YAAiB;AAC/B,SAAO,kBAAkB,EAAE,MAAM;AACnC;AAMO,SAAS,cAA4D;AAC1E,QAAM,UAAU,kBAAkB;AAClC,SAAO,CAAC,SAAS,aAAa,QAAQ,MAAM,KAAK,IAAI;AACvD;AAGO,SAAS,eAAwD;AACtE,QAAM,UAAU,kBAAkB;AAClC,SAAO,SAAS,MAAM,QAAQ,MAAM,SAA0B;AAChE;AAOO,SAAS,sBAAwE;AACtF,QAAM,UAAU,kBAAkB;AAClC,SAAO,SAAS,MAAM,QAAQ,MAAM,gBAA0C;AAChF;AAGO,SAAS,gBAAyD;AACvE,QAAM,UAAU,kBAAkB;AAClC,SAAO,SAAS,MAAM,QAAQ,MAAM,UAA2B;AACjE;AAGO,SAAS,iBAA4D;AAC1E,QAAM,UAAU,kBAAkB;AAClC,SAAO,SAAS,MAAM,QAAQ,MAAM,WAAW;AACjD;AAGO,SAAS,iBAA4D;AAC1E,QAAM,UAAU,kBAAkB;AAClC,SAAO,SAAS,MAAM,QAAQ,MAAM,aAAa,WAAW;AAC9D;AAOO,SAAS,wBAE2B;AACzC,QAAM,UAAU,kBAAkB;AAClC,SAAO,OAAO,SAAS;AACrB,UAAM,EAAE,KAAK,YAAY,IAAI,QAAQ;AACrC,UAAM,YAAY,aAAa;AAC/B,QAAI,aAAa,CAAC,UAAU,SAAS,IAAI,EAAG,QAAO,aAAa;AAChE,UAAM,SAAS,MAAM,IAAI,mBAAmB,EAAE,KAAK,CAAC;AACpD,WAAO,OAAO;AAAA,EAChB;AACF;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mountly-mcp",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.5.0",
|
|
4
4
|
"description": "Build MCP Apps (SEP-1865) views from React, Vue or Svelte components — new or existing. One build emits the ui:// resource, its sidecar, and the MCP server wiring.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"chatgpt",
|
|
@@ -62,6 +62,14 @@
|
|
|
62
62
|
"import": "./dist/react/openai-extensions.js"
|
|
63
63
|
},
|
|
64
64
|
"./server": {
|
|
65
|
+
"workerd": {
|
|
66
|
+
"types": "./dist/server/workers.d.ts",
|
|
67
|
+
"import": "./dist/server/workers.js"
|
|
68
|
+
},
|
|
69
|
+
"worker": {
|
|
70
|
+
"types": "./dist/server/workers.d.ts",
|
|
71
|
+
"import": "./dist/server/workers.js"
|
|
72
|
+
},
|
|
65
73
|
"types": "./dist/server/index.d.ts",
|
|
66
74
|
"import": "./dist/server/index.js"
|
|
67
75
|
},
|
|
@@ -69,6 +77,10 @@
|
|
|
69
77
|
"types": "./dist/openai/server.d.ts",
|
|
70
78
|
"import": "./dist/openai/server.js"
|
|
71
79
|
},
|
|
80
|
+
"./events": {
|
|
81
|
+
"types": "./dist/events/index.d.ts",
|
|
82
|
+
"import": "./dist/events/index.js"
|
|
83
|
+
},
|
|
72
84
|
"./json-render": {
|
|
73
85
|
"types": "./dist/json-render/index.d.ts",
|
|
74
86
|
"import": "./dist/json-render/index.js"
|
|
@@ -123,7 +135,7 @@
|
|
|
123
135
|
"@modelcontextprotocol/ext-apps": "^1.7.5",
|
|
124
136
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
125
137
|
"mountly": "^1.3.0",
|
|
126
|
-
"mountly-react": "^2.
|
|
138
|
+
"mountly-react": "^2.3.0",
|
|
127
139
|
"zod": "^4.4.3"
|
|
128
140
|
},
|
|
129
141
|
"devDependencies": {
|
|
@@ -141,9 +153,9 @@
|
|
|
141
153
|
"tsup": "^8.5.1",
|
|
142
154
|
"typescript": "^7.0.2",
|
|
143
155
|
"vite": "^8.1.5",
|
|
144
|
-
"mountly-
|
|
156
|
+
"mountly-compose": "0.1.0",
|
|
145
157
|
"mountly-vue": "^2.1.0",
|
|
146
|
-
"mountly-
|
|
158
|
+
"mountly-svelte": "^2.1.1"
|
|
147
159
|
},
|
|
148
160
|
"peerDependencies": {
|
|
149
161
|
"@json-render/core": "^0.20.0",
|
|
@@ -155,8 +167,8 @@
|
|
|
155
167
|
"mountly-svelte": "^2.1.0",
|
|
156
168
|
"mountly-vue": "^2.1.0",
|
|
157
169
|
"playwright": ">=1.62.1",
|
|
158
|
-
"react": "^19",
|
|
159
|
-
"react-dom": "^19",
|
|
170
|
+
"react": "^18 || ^19",
|
|
171
|
+
"react-dom": "^18 || ^19",
|
|
160
172
|
"vite": "^8"
|
|
161
173
|
},
|
|
162
174
|
"peerDependenciesMeta": {
|
|
@@ -9,6 +9,8 @@ pnpm install
|
|
|
9
9
|
pnpm dev # sandboxed AppBridge host on :5179 (uses --server ./server.mjs)
|
|
10
10
|
pnpm verify # static conformance
|
|
11
11
|
pnpm verify:render # + Chromium mount check (needs Playwright)
|
|
12
|
+
pnpm typecheck # TypeScript 7 (native tsc, a.k.a. tsgo)
|
|
13
|
+
pnpm lint # oxlint, type-aware via tsgolint
|
|
12
14
|
```
|
|
13
15
|
|
|
14
16
|
| File | Role |
|
|
@@ -78,6 +80,7 @@ jobs:
|
|
|
78
80
|
- uses: actions/setup-node@v4
|
|
79
81
|
with: { node-version: 22, cache: pnpm }
|
|
80
82
|
- run: pnpm install
|
|
83
|
+
- run: pnpm typecheck && pnpm lint
|
|
81
84
|
- run: pnpm exec mountly-mcp build
|
|
82
85
|
- run: pnpm exec playwright install chromium
|
|
83
86
|
- run: pnpm exec mountly-mcp verify --strict --render
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"verify:strict": "mountly-mcp verify --strict",
|
|
11
11
|
"verify:render": "mountly-mcp verify --strict --render",
|
|
12
12
|
"doctor": "mountly-mcp doctor",
|
|
13
|
-
"typecheck": "tsc --noEmit"
|
|
13
|
+
"typecheck": "tsc --noEmit",
|
|
14
|
+
"lint": "oxlint --type-aware"
|
|
14
15
|
},
|
|
15
16
|
"dependencies": {
|
|
16
17
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
@@ -22,8 +23,10 @@
|
|
|
22
23
|
"devDependencies": {
|
|
23
24
|
"@types/react": "^19.2.18",
|
|
24
25
|
"@types/react-dom": "^19.2.4",
|
|
25
|
-
"@vitejs/plugin-react": "^
|
|
26
|
-
"
|
|
26
|
+
"@vitejs/plugin-react": "^6.1.1",
|
|
27
|
+
"oxlint": "^1.86.0",
|
|
28
|
+
"oxlint-tsgolint": "^7.0.2003",
|
|
29
|
+
"typescript": "^7.0.2",
|
|
27
30
|
"vite": "^8.2.1"
|
|
28
31
|
}
|
|
29
32
|
}
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"verify:strict": "mountly-mcp verify --strict",
|
|
11
11
|
"verify:render": "mountly-mcp verify --strict --render",
|
|
12
12
|
"doctor": "mountly-mcp doctor",
|
|
13
|
-
"typecheck": "
|
|
13
|
+
"typecheck": "tsc --noEmit",
|
|
14
|
+
"lint": "oxlint --type-aware"
|
|
14
15
|
},
|
|
15
16
|
"dependencies": {
|
|
16
17
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
@@ -21,8 +22,9 @@
|
|
|
21
22
|
},
|
|
22
23
|
"devDependencies": {
|
|
23
24
|
"@sveltejs/vite-plugin-svelte": "^7.3.0",
|
|
24
|
-
"
|
|
25
|
-
"
|
|
25
|
+
"oxlint": "^1.86.0",
|
|
26
|
+
"oxlint-tsgolint": "^7.0.2003",
|
|
27
|
+
"typescript": "^7.0.2",
|
|
26
28
|
"vite": "^8.2.1"
|
|
27
29
|
}
|
|
28
30
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
2
|
+
|
|
3
|
+
// Types `.svelte` imports for `tsc --noEmit` on TypeScript 7. Switch typecheck to
|
|
4
|
+
// `svelte-check` and delete this file once svelte-check supports TypeScript 7.
|
|
5
|
+
declare module "*.svelte" {
|
|
6
|
+
import type { Component } from "svelte";
|
|
7
|
+
|
|
8
|
+
const component: Component<Record<string, unknown>>;
|
|
9
|
+
export default component;
|
|
10
|
+
}
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"verify:strict": "mountly-mcp verify --strict",
|
|
11
11
|
"verify:render": "mountly-mcp verify --strict --render",
|
|
12
12
|
"doctor": "mountly-mcp doctor",
|
|
13
|
-
"typecheck": "tsc --noEmit"
|
|
13
|
+
"typecheck": "tsc --noEmit",
|
|
14
|
+
"lint": "oxlint --type-aware"
|
|
14
15
|
},
|
|
15
16
|
"dependencies": {
|
|
16
17
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
@@ -18,7 +19,9 @@
|
|
|
18
19
|
"zod": "^4.4.3"
|
|
19
20
|
},
|
|
20
21
|
"devDependencies": {
|
|
21
|
-
"
|
|
22
|
+
"oxlint": "^1.86.0",
|
|
23
|
+
"oxlint-tsgolint": "^7.0.2003",
|
|
24
|
+
"typescript": "^7.0.2",
|
|
22
25
|
"vite": "^8.2.1"
|
|
23
26
|
}
|
|
24
27
|
}
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"verify:strict": "mountly-mcp verify --strict",
|
|
11
11
|
"verify:render": "mountly-mcp verify --strict --render",
|
|
12
12
|
"doctor": "mountly-mcp doctor",
|
|
13
|
-
"typecheck": "
|
|
13
|
+
"typecheck": "tsc --noEmit",
|
|
14
|
+
"lint": "oxlint --type-aware"
|
|
14
15
|
},
|
|
15
16
|
"dependencies": {
|
|
16
17
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
@@ -21,8 +22,9 @@
|
|
|
21
22
|
},
|
|
22
23
|
"devDependencies": {
|
|
23
24
|
"@vitejs/plugin-vue": "^6.0.8",
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
25
|
+
"oxlint": "^1.86.0",
|
|
26
|
+
"oxlint-tsgolint": "^7.0.2003",
|
|
27
|
+
"typescript": "^7.0.2",
|
|
28
|
+
"vite": "^8.2.1"
|
|
27
29
|
}
|
|
28
30
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
2
|
+
|
|
3
|
+
// Types `.vue` imports for `tsc --noEmit` on TypeScript 7. Switch typecheck to
|
|
4
|
+
// `vue-tsc --noEmit` and delete this file once vue-tsc supports TypeScript 7.
|
|
5
|
+
declare module "*.vue" {
|
|
6
|
+
import type { DefineComponent } from "vue";
|
|
7
|
+
|
|
8
|
+
const component: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
|
|
9
|
+
export default component;
|
|
10
|
+
}
|