mountly-mcp 4.0.2 → 4.2.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.
Files changed (53) hide show
  1. package/GLOSSARY.md +37 -0
  2. package/README.md +103 -190
  3. package/dist/add-DAFMA4F3.js +263 -0
  4. package/dist/add-DAFMA4F3.js.map +1 -0
  5. package/dist/add.d.ts +13 -0
  6. package/dist/chunk-EOWAWZH2.js +34 -0
  7. package/dist/chunk-EOWAWZH2.js.map +1 -0
  8. package/dist/{chunk-KWVGW5Q7.js → chunk-GN2IQYV3.js} +1 -1
  9. package/dist/chunk-GN2IQYV3.js.map +1 -0
  10. package/dist/{chunk-UECZA34Q.js → chunk-OWAXBNZA.js} +10 -5
  11. package/dist/chunk-OWAXBNZA.js.map +1 -0
  12. package/dist/cli.js +97 -25
  13. package/dist/cli.js.map +1 -1
  14. package/dist/compose/index.d.ts +48 -0
  15. package/dist/compose/index.js +141 -0
  16. package/dist/compose/index.js.map +1 -0
  17. package/dist/connect-server-P2UZ62YC.js +7 -0
  18. package/dist/create.js +43 -15
  19. package/dist/create.js.map +1 -1
  20. package/dist/dev/host-entry.js +7 -0
  21. package/dist/dev/index.js +2 -2
  22. package/dist/doctor-B54H6CRN.js +122 -0
  23. package/dist/doctor-B54H6CRN.js.map +1 -0
  24. package/dist/doctor.d.ts +16 -0
  25. package/dist/errors-4ERW7HZB.js +11 -0
  26. package/dist/errors-4ERW7HZB.js.map +1 -0
  27. package/dist/errors.d.ts +25 -0
  28. package/dist/json-render/index.js +4 -4
  29. package/package.json +17 -5
  30. package/templates/react/README.md.tmpl +83 -6
  31. package/templates/react/package.json.tmpl +2 -0
  32. package/templates/react/serve-stdio.mjs.tmpl +9 -0
  33. package/templates/react/server.mjs.tmpl +6 -1
  34. package/templates/react/src/view.tsx.tmpl +1 -1
  35. package/templates/svelte/README.md.tmpl +27 -4
  36. package/templates/svelte/package.json.tmpl +2 -0
  37. package/templates/svelte/serve-stdio.mjs.tmpl +5 -0
  38. package/templates/svelte/server.mjs.tmpl +6 -1
  39. package/templates/svelte/src/Dashboard.svelte.tmpl +1 -1
  40. package/templates/vanilla/README.md.tmpl +27 -11
  41. package/templates/vanilla/package.json.tmpl +2 -0
  42. package/templates/vanilla/serve-stdio.mjs.tmpl +5 -0
  43. package/templates/vanilla/server.mjs.tmpl +6 -1
  44. package/templates/vanilla/src/view.ts.tmpl +1 -1
  45. package/templates/vue/README.md.tmpl +27 -4
  46. package/templates/vue/package.json.tmpl +2 -0
  47. package/templates/vue/serve-stdio.mjs.tmpl +5 -0
  48. package/templates/vue/server.mjs.tmpl +6 -1
  49. package/templates/vue/src/Dashboard.vue.tmpl +1 -1
  50. package/dist/chunk-KWVGW5Q7.js.map +0 -1
  51. package/dist/chunk-UECZA34Q.js.map +0 -1
  52. package/dist/connect-server-7L4HGKKL.js +0 -7
  53. /package/dist/{connect-server-7L4HGKKL.js.map → connect-server-P2UZ62YC.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/create.ts"],"sourcesContent":["import {\n cpSync,\n existsSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n/** Package root: dist/cli.js → .. ; src/cli.ts during tests → .. when run via dist. */\nconst PACKAGE_ROOT = resolve(__dirname, \"..\");\nconst TEMPLATES = resolve(PACKAGE_ROOT, \"templates\");\n\n/**\n * The version of mountly-mcp doing the scaffolding, so the generated\n * package.json pins the API this CLI actually ships.\n *\n * Hardcoding the pin in the templates meant a major release left them behind:\n * `^3.1.0` cannot resolve to 4.0.0, so every scaffolded app installed a\n * package without the exports its own vite.config imported.\n */\nfunction ownVersion(): string {\n const pkg = JSON.parse(readFileSync(join(PACKAGE_ROOT, \"package.json\"), \"utf8\")) as {\n version?: string;\n };\n if (!pkg.version) throw new Error(\"mountly-mcp: cannot read own version from package.json\");\n return pkg.version;\n}\n\nconst SUPPORTED = [\"react\", \"vue\", \"svelte\", \"vanilla\"] as const;\ntype Framework = (typeof SUPPORTED)[number];\n\nexport interface CreateArgs {\n name: string;\n framework: Framework;\n dir: string;\n}\n\nexport function parseCreateArgs(argv: ReadonlyArray<string>): CreateArgs {\n const name = argv[0];\n if (!name || name.startsWith(\"-\")) {\n throw new Error(\n \"mountly-mcp create requires a project name. e.g. mountly-mcp create my-app --framework react\",\n );\n }\n\n let framework: Framework = \"react\";\n let dir = `./${name}`;\n\n for (let i = 1; i < argv.length; i += 1) {\n const arg = argv[i];\n if (arg === \"--framework\" || arg === \"-f\") {\n const value = argv[++i];\n if (value === undefined) throw new Error(`mountly-mcp: ${arg} needs a value`);\n if (!SUPPORTED.includes(value as Framework)) {\n throw new Error(\n `mountly-mcp: framework \"${value}\" not supported. Available: ${SUPPORTED.join(\", \")}`,\n );\n }\n framework = value as Framework;\n } else if (arg === \"--dir\") {\n const value = argv[++i];\n if (value === undefined) throw new Error(\"mountly-mcp: --dir needs a value\");\n dir = value;\n } else {\n throw new Error(`mountly-mcp: unknown create option '${arg}'`);\n }\n }\n\n return { name, framework, dir };\n}\n\nfunction slugify(name: string): string {\n return name\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n}\n\nfunction renderTemplates(dir: string, ctx: Record<string, string>): void {\n for (const entry of readdirSync(dir)) {\n const full = join(dir, entry);\n if (statSync(full).isDirectory()) {\n renderTemplates(full, ctx);\n continue;\n }\n if (!entry.endsWith(\".tmpl\")) continue;\n let content = readFileSync(full, \"utf8\");\n for (const [key, value] of Object.entries(ctx)) {\n content = content.split(`{{${key}}}`).join(value);\n }\n writeFileSync(full.replace(/\\.tmpl$/, \"\"), content);\n unlinkSync(full);\n }\n}\n\nexport async function createProject(args: CreateArgs): Promise<void> {\n const target = resolve(args.dir);\n if (existsSync(target)) {\n throw new Error(`mountly-mcp: target directory already exists: ${target}`);\n }\n\n const tplDir = join(TEMPLATES, args.framework);\n if (!existsSync(tplDir)) {\n throw new Error(\n `mountly-mcp: template for framework \"${args.framework}\" is missing at ${tplDir}`,\n );\n }\n\n mkdirSync(target, { recursive: true });\n cpSync(tplDir, target, { recursive: true });\n\n const slug = slugify(args.name) || \"app\";\n renderTemplates(target, {\n name: args.name,\n slug,\n uri: `ui://${slug}/dashboard`,\n framework: args.framework,\n mcpVersion: ownVersion(),\n });\n\n process.stdout.write(\n [\n \"\",\n `✓ Created MCP App ${args.name} (${args.framework}) at ${target}`,\n \"\",\n \"Next steps:\",\n ` cd ${args.dir}`,\n \" pnpm install\",\n \" pnpm dev # sandboxed host + live reload\",\n \" pnpm verify # conformance check\",\n \"\",\n \"Do not clone the Mountly monorepo for greenfield apps — this scaffold is the canonical path.\",\n \"\",\n ].join(\"\\n\"),\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/create.ts"],"sourcesContent":["import {\n cpSync,\n existsSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { CLI_ERROR_CODES, cliError } from \"./errors.js\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n/** Package root: dist/cli.js → .. ; src/cli.ts during tests → .. when run via dist. */\nconst PACKAGE_ROOT = resolve(__dirname, \"..\");\nconst TEMPLATES = resolve(PACKAGE_ROOT, \"templates\");\n\n/**\n * The version of mountly-mcp doing the scaffolding, so the generated\n * package.json pins the API this CLI actually ships.\n *\n * Hardcoding the pin in the templates meant a major release left them behind:\n * `^3.1.0` cannot resolve to 4.0.0, so every scaffolded app installed a\n * package without the exports its own vite.config imported.\n */\nfunction ownVersion(): string {\n const pkg = JSON.parse(readFileSync(join(PACKAGE_ROOT, \"package.json\"), \"utf8\")) as {\n version?: string;\n };\n if (!pkg.version) throw new Error(\"mountly-mcp: cannot read own version from package.json\");\n return pkg.version;\n}\n\nconst SUPPORTED = [\"react\", \"vue\", \"svelte\", \"vanilla\"] as const;\ntype Framework = (typeof SUPPORTED)[number];\n\nexport interface CreateArgs {\n name: string;\n framework: Framework;\n dir: string;\n}\n\nexport function parseCreateArgs(argv: ReadonlyArray<string>): CreateArgs {\n const name = argv[0];\n if (!name || name.startsWith(\"-\")) {\n throw cliError(\n CLI_ERROR_CODES.UNKNOWN_OPTION,\n \"create requires a project name\",\n \"Example: mountly-mcp create my-app --framework react\",\n );\n }\n\n let framework: Framework = \"react\";\n let dir = `./${name}`;\n\n for (let i = 1; i < argv.length; i += 1) {\n const arg = argv[i];\n if (arg === \"--framework\" || arg === \"-f\") {\n const value = argv[++i];\n if (value === undefined) {\n throw cliError(\n CLI_ERROR_CODES.UNKNOWN_OPTION,\n `${arg} needs a value`,\n `Available: ${SUPPORTED.join(\", \")}`,\n );\n }\n if (!SUPPORTED.includes(value as Framework)) {\n throw cliError(\n CLI_ERROR_CODES.UNKNOWN_OPTION,\n `framework \"${value}\" not supported`,\n `Available: ${SUPPORTED.join(\", \")}`,\n );\n }\n framework = value as Framework;\n } else if (arg === \"--dir\") {\n const value = argv[++i];\n if (value === undefined) {\n throw cliError(\n CLI_ERROR_CODES.UNKNOWN_OPTION,\n \"--dir needs a value\",\n \"Example: --dir ./apps/my-app\",\n );\n }\n dir = value;\n } else {\n throw cliError(\n CLI_ERROR_CODES.UNKNOWN_OPTION,\n `unknown create option '${arg}'`,\n \"Options: --framework | --dir\",\n );\n }\n }\n\n return { name, framework, dir };\n}\n\nfunction slugify(name: string): string {\n return name\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n}\n\nfunction renderTemplates(dir: string, ctx: Record<string, string>): void {\n for (const entry of readdirSync(dir)) {\n const full = join(dir, entry);\n if (statSync(full).isDirectory()) {\n renderTemplates(full, ctx);\n continue;\n }\n if (!entry.endsWith(\".tmpl\")) continue;\n let content = readFileSync(full, \"utf8\");\n for (const [key, value] of Object.entries(ctx)) {\n content = content.split(`{{${key}}}`).join(value);\n }\n writeFileSync(full.replace(/\\.tmpl$/, \"\"), content);\n unlinkSync(full);\n }\n}\n\nexport async function createProject(args: CreateArgs): Promise<void> {\n const target = resolve(args.dir);\n if (existsSync(target)) {\n throw cliError(\n CLI_ERROR_CODES.TARGET_EXISTS,\n `target directory already exists: ${target}`,\n \"Choose another --dir, or remove the existing folder\",\n );\n }\n\n const tplDir = join(TEMPLATES, args.framework);\n if (!existsSync(tplDir)) {\n throw cliError(\n CLI_ERROR_CODES.MISSING_TEMPLATE,\n `template for framework \"${args.framework}\" is missing at ${tplDir}`,\n `Available: ${SUPPORTED.join(\", \")}`,\n );\n }\n\n mkdirSync(target, { recursive: true });\n cpSync(tplDir, target, { recursive: true });\n\n const slug = slugify(args.name) || \"app\";\n renderTemplates(target, {\n name: args.name,\n slug,\n uri: `ui://${slug}/dashboard`,\n framework: args.framework,\n mcpVersion: ownVersion(),\n });\n\n process.stdout.write(\n [\n \"\",\n `✓ Created MCP App ${args.name} (${args.framework}) at ${target}`,\n \"\",\n \"Next:\",\n ` cd ${args.dir}`,\n \" pnpm install\",\n \" pnpm dev\",\n \"\",\n ].join(\"\\n\"),\n );\n}\n"],"mappings":"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","names":[]}
@@ -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
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  sandboxProxyHtml,
3
3
  startDevHost
4
- } from "../chunk-KWVGW5Q7.js";
4
+ } from "../chunk-GN2IQYV3.js";
5
5
  import {
6
6
  connectMcpServer
7
- } from "../chunk-UECZA34Q.js";
7
+ } from "../chunk-OWAXBNZA.js";
8
8
  import "../chunk-YJA4H6IB.js";
9
9
  export {
10
10
  connectMcpServer,
@@ -0,0 +1,122 @@
1
+ import {
2
+ CLI_ERROR_CODES,
3
+ cliError
4
+ } from "./chunk-EOWAWZH2.js";
5
+
6
+ // src/doctor.ts
7
+ import { existsSync, readFileSync } from "fs";
8
+ import { createRequire } from "module";
9
+ import { resolve } from "path";
10
+ function nodeMajor() {
11
+ return Number(process.versions.node.split(".")[0] ?? 0);
12
+ }
13
+ function tryResolve(specifier, fromDir) {
14
+ try {
15
+ const require2 = createRequire(resolve(fromDir, "package.json"));
16
+ return require2.resolve(specifier);
17
+ } catch {
18
+ return null;
19
+ }
20
+ }
21
+ function runDoctor(cwd = process.cwd()) {
22
+ const checks = [];
23
+ const major = nodeMajor();
24
+ checks.push({
25
+ id: "node",
26
+ ok: major >= 20,
27
+ detail: major >= 20 ? `Node ${process.versions.node} (ok; 20+ required, 22+ recommended)` : `Node ${process.versions.node} is below 20. Upgrade Node, then re-run mountly-mcp doctor.`
28
+ });
29
+ const viteConfigCandidates = [
30
+ "vite.config.ts",
31
+ "vite.config.mts",
32
+ "vite.config.js",
33
+ "vite.config.mjs"
34
+ ].map((name) => resolve(cwd, name));
35
+ const viteConfig = viteConfigCandidates.find((path) => existsSync(path));
36
+ checks.push({
37
+ id: "vite-config",
38
+ ok: Boolean(viteConfig),
39
+ detail: viteConfig ? `Found ${viteConfig}` : "No vite.config.* in this directory. Run from the View project, or: npx mountly-mcp create my-app --framework react"
40
+ });
41
+ if (viteConfig) {
42
+ const source = readFileSync(viteConfig, "utf8");
43
+ const hasPlugin = /mountlyMcpViews\s*\(/.test(source);
44
+ checks.push({
45
+ id: "vite-plugin",
46
+ ok: hasPlugin,
47
+ detail: hasPlugin ? "vite config imports mountlyMcpViews()" : `Add mountlyMcpViews() from "mountly-mcp/vite" to ${viteConfig}`
48
+ });
49
+ }
50
+ const manifest = resolve(cwd, "dist/mountly-mcp.manifest.json");
51
+ checks.push({
52
+ id: "manifest",
53
+ ok: existsSync(manifest),
54
+ detail: existsSync(manifest) ? `Found ${manifest}` : "No dist/mountly-mcp.manifest.json yet. Run: npx mountly-mcp build"
55
+ });
56
+ const playwright = tryResolve("playwright", cwd) ?? tryResolve("@playwright/test", cwd);
57
+ checks.push({
58
+ id: "playwright",
59
+ ok: Boolean(playwright),
60
+ detail: playwright ? `Playwright resolvable for verify --render (${playwright})` : "Playwright not installed. For CI render checks: pnpm add -D playwright && npx playwright install chromium"
61
+ });
62
+ const pkgPath = resolve(cwd, "package.json");
63
+ if (existsSync(pkgPath)) {
64
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
65
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
66
+ if (deps.react) {
67
+ const reactPath = tryResolve("react/package.json", cwd);
68
+ if (reactPath) {
69
+ const reactPkg = JSON.parse(readFileSync(reactPath, "utf8"));
70
+ const reactMajor = Number((reactPkg.version ?? "0").split(".")[0]);
71
+ checks.push({
72
+ id: "react",
73
+ ok: reactMajor >= 19,
74
+ detail: reactMajor >= 19 ? `React ${reactPkg.version} (ok)` : `React ${reactPkg.version} is below 19. mountly-mcp/react and mountly-react require React 19.`
75
+ });
76
+ }
77
+ }
78
+ if (deps.vite) {
79
+ const vitePath = tryResolve("vite/package.json", cwd);
80
+ if (vitePath) {
81
+ const vitePkg = JSON.parse(readFileSync(vitePath, "utf8"));
82
+ const viteMajor = Number((vitePkg.version ?? "0").split(".")[0]);
83
+ checks.push({
84
+ id: "vite",
85
+ ok: viteMajor >= 8,
86
+ detail: viteMajor >= 8 ? `Vite ${vitePkg.version} (ok)` : `Vite ${vitePkg.version} is below 8. mountly-mcp/vite is built and tested against Vite 8.`
87
+ });
88
+ }
89
+ }
90
+ }
91
+ const hard = checks.filter((c) => c.id !== "manifest" && c.id !== "playwright");
92
+ const ok = hard.every((c) => c.ok);
93
+ return { ok, checks };
94
+ }
95
+ function formatDoctorReport(report) {
96
+ const lines = ["mountly-mcp doctor", ""];
97
+ for (const check of report.checks) {
98
+ lines.push(`${check.ok ? "ok" : "FAIL"} ${check.id.padEnd(14)} ${check.detail}`);
99
+ }
100
+ lines.push("");
101
+ lines.push(report.ok ? "Ready for mountly-mcp build / dev / verify." : "Fix FAIL items above.");
102
+ lines.push("");
103
+ return `${lines.join("\n")}
104
+ `;
105
+ }
106
+ function doctorCommand(cwd = process.cwd()) {
107
+ const report = runDoctor(cwd);
108
+ process.stdout.write(formatDoctorReport(report));
109
+ if (!report.ok) {
110
+ throw cliError(
111
+ CLI_ERROR_CODES.DOCTOR_FAILED,
112
+ "one or more doctor checks failed",
113
+ "Fix the FAIL lines above, then re-run: mountly-mcp doctor"
114
+ );
115
+ }
116
+ }
117
+ export {
118
+ doctorCommand,
119
+ formatDoctorReport,
120
+ runDoctor
121
+ };
122
+ //# sourceMappingURL=doctor-B54H6CRN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/doctor.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { 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\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 // 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"]}
@@ -0,0 +1,16 @@
1
+ export interface DoctorCheck {
2
+ id: string;
3
+ ok: boolean;
4
+ detail: string;
5
+ }
6
+ export interface DoctorReport {
7
+ ok: boolean;
8
+ checks: DoctorCheck[];
9
+ }
10
+ /**
11
+ * Check the local project for Mountly MCP readiness. Exits nonzero via the
12
+ * CLI when `ok` is false.
13
+ */
14
+ export declare function runDoctor(cwd?: string): DoctorReport;
15
+ export declare function formatDoctorReport(report: DoctorReport): string;
16
+ export declare function doctorCommand(cwd?: string): void;
@@ -0,0 +1,11 @@
1
+ import {
2
+ CLI_ERROR_CODES,
3
+ MountlyMcpCliError,
4
+ cliError
5
+ } from "./chunk-EOWAWZH2.js";
6
+ export {
7
+ CLI_ERROR_CODES,
8
+ MountlyMcpCliError,
9
+ cliError
10
+ };
11
+ //# sourceMappingURL=errors-4ERW7HZB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * LLM-shaped CLI errors: a stable code plus the next command or file to open.
3
+ * Skills and agents should key off the `mountly-mcp/…` code prefix.
4
+ */
5
+ export declare const CLI_ERROR_CODES: {
6
+ readonly MISSING_VITE_PLUGIN: "mountly-mcp/missing-vite-plugin";
7
+ readonly NO_VITE_CONFIG: "mountly-mcp/no-vite-config";
8
+ readonly UNKNOWN_VIEW: "mountly-mcp/unknown-view";
9
+ readonly MULTI_VIEW_NEEDS_APP: "mountly-mcp/multi-view-needs-app";
10
+ readonly INVALID_UI_URI: "mountly-mcp/invalid-ui-uri";
11
+ readonly BAD_SERVER_EXPORT: "mountly-mcp/bad-server-export";
12
+ readonly NO_TOOL_FOR_VIEW: "mountly-mcp/no-tool-for-view";
13
+ readonly UNKNOWN_OPTION: "mountly-mcp/unknown-option";
14
+ readonly UNKNOWN_COMMAND: "mountly-mcp/unknown-command";
15
+ readonly TARGET_EXISTS: "mountly-mcp/target-exists";
16
+ readonly MISSING_TEMPLATE: "mountly-mcp/missing-template";
17
+ readonly DOCTOR_FAILED: "mountly-mcp/doctor-failed";
18
+ };
19
+ export type CliErrorCode = (typeof CLI_ERROR_CODES)[keyof typeof CLI_ERROR_CODES];
20
+ export declare class MountlyMcpCliError extends Error {
21
+ readonly code: CliErrorCode;
22
+ readonly next: string;
23
+ constructor(code: CliErrorCode, message: string, next: string);
24
+ }
25
+ export declare function cliError(code: CliErrorCode, message: string, next: string): MountlyMcpCliError;
@@ -1,3 +1,7 @@
1
+ import {
2
+ buildAppHtml,
3
+ useJsonRenderApp
4
+ } from "../chunk-33DMFKKD.js";
1
5
  import {
2
6
  createJsonRenderMcpApp,
3
7
  registerJsonRenderResource,
@@ -17,10 +21,6 @@ import {
17
21
  useToolResult
18
22
  } from "../chunk-SXF23BZD.js";
19
23
  import "../chunk-5L3QHYWK.js";
20
- import {
21
- buildAppHtml,
22
- useJsonRenderApp
23
- } from "../chunk-33DMFKKD.js";
24
24
  import "../chunk-YJA4H6IB.js";
25
25
 
26
26
  // src/json-render/generative-view.tsx
package/package.json CHANGED
@@ -1,18 +1,20 @@
1
1
  {
2
2
  "name": "mountly-mcp",
3
- "version": "4.0.2",
3
+ "version": "4.2.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",
7
7
  "claude",
8
8
  "mcp",
9
9
  "mcp-apps",
10
+ "mcp-apps-view",
10
11
  "mcp-ui",
11
12
  "mcp-view",
12
13
  "model-context-protocol",
13
14
  "react",
14
15
  "sep-1865",
15
16
  "svelte",
17
+ "ui-resource",
16
18
  "vite-plugin",
17
19
  "vue"
18
20
  ],
@@ -27,7 +29,8 @@
27
29
  },
28
30
  "files": [
29
31
  "dist",
30
- "templates"
32
+ "templates",
33
+ "GLOSSARY.md"
31
34
  ],
32
35
  "type": "module",
33
36
  "main": "./dist/index.js",
@@ -66,6 +69,10 @@
66
69
  "types": "./dist/json-render/server.d.ts",
67
70
  "import": "./dist/json-render/server.js"
68
71
  },
72
+ "./compose": {
73
+ "types": "./dist/compose/index.d.ts",
74
+ "import": "./dist/compose/index.js"
75
+ },
69
76
  "./json-render/app": {
70
77
  "types": "./dist/json-render/app.d.ts",
71
78
  "import": "./dist/json-render/app.js"
@@ -107,7 +114,7 @@
107
114
  "dependencies": {
108
115
  "@modelcontextprotocol/ext-apps": "^1.7.5",
109
116
  "@modelcontextprotocol/sdk": "^1.30.0",
110
- "mountly": "^1.0.0",
117
+ "mountly": "^1.3.0",
111
118
  "mountly-react": "^2.1.0",
112
119
  "zod": "^4.4.3"
113
120
  },
@@ -125,7 +132,8 @@
125
132
  "tsup": "^8.5.1",
126
133
  "typescript": "^7.0.2",
127
134
  "vite": "^8.1.5",
128
- "mountly-svelte": "^2.1.0",
135
+ "mountly-svelte": "^2.1.1",
136
+ "mountly-compose": "0.1.0",
129
137
  "mountly-vue": "^2.1.0"
130
138
  },
131
139
  "peerDependencies": {
@@ -133,12 +141,13 @@
133
141
  "@json-render/react": "^0.20.0",
134
142
  "ai": "^7.0.65",
135
143
  "axe-core": ">=4.10.0",
144
+ "mountly-compose": "^0.1.0",
136
145
  "mountly-svelte": "^2.1.0",
137
146
  "mountly-vue": "^2.1.0",
138
147
  "playwright": ">=1.62.1",
139
148
  "react": "^19",
140
149
  "react-dom": "^19",
141
- "vite": "^8.2.1"
150
+ "vite": "^8"
142
151
  },
143
152
  "peerDependenciesMeta": {
144
153
  "@json-render/core": {
@@ -170,6 +179,9 @@
170
179
  },
171
180
  "axe-core": {
172
181
  "optional": true
182
+ },
183
+ "mountly-compose": {
184
+ "optional": true
173
185
  }
174
186
  },
175
187
  "scripts": {
@@ -2,14 +2,91 @@
2
2
 
3
3
  MCP App scaffolded with `mountly-mcp create`.
4
4
 
5
+ ## Runbook
6
+
5
7
  ```bash
6
8
  pnpm install
7
- pnpm dev # sandboxed host on :5179
8
- pnpm verify # conformance
9
+ pnpm dev # sandboxed AppBridge host on :5179 (uses --server ./server.mjs)
10
+ pnpm verify # static conformance
11
+ pnpm verify:render # + Chromium mount check (needs Playwright)
12
+ ```
13
+
14
+ | File | Role |
15
+ | --- | --- |
16
+ | `src/view.tsx` | `createMcpView`: View entry; reads tool data via `useToolResult` |
17
+ | `server.mjs` | `registerMcpApps`: factory for `mountly-mcp dev --server` |
18
+ | `serve-stdio.mjs` | Stdio entry for Claude Desktop / VS Code / ChatGPT connectors |
19
+ | `mcp.fixtures.json` | Tool **arguments** when using `--server` |
20
+ | `vite.config.ts` | `mountlyMcpViews({ apps: [...] })` |
21
+ | `dist/mountly-mcp.manifest.json` | Build artifact (after `pnpm build` / first `dev`) |
22
+
23
+ Do not clone the Mountly monorepo for greenfield apps: this project is the canonical path.
24
+
25
+ ## Open in a real host
26
+
27
+ `serve-stdio.mjs` is included. Build first (`pnpm build` or run `pnpm dev` once), then point the host at that entry.
28
+
29
+ Never write logs to **stdout** in a stdio server.
30
+
31
+ ### Claude Desktop
32
+
33
+ `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS):
34
+
35
+ ```json
36
+ {
37
+ "mcpServers": {
38
+ "{{slug}}": {
39
+ "command": "node",
40
+ "args": ["/ABSOLUTE/PATH/TO/{{name}}/serve-stdio.mjs"]
41
+ }
42
+ }
43
+ }
44
+ ```
45
+
46
+ ### VS Code
47
+
48
+ `.vscode/mcp.json`:
49
+
50
+ ```json
51
+ {
52
+ "servers": {
53
+ "{{slug}}": {
54
+ "type": "stdio",
55
+ "command": "node",
56
+ "args": ["${workspaceFolder}/serve-stdio.mjs"]
57
+ }
58
+ }
59
+ }
9
60
  ```
10
61
 
11
- - View: `src/view.tsx` (`createMcpView`)
12
- - Server: `server.mjs` (`registerMcpApps`)
13
- - Fixtures: `mcp.fixtures.json` (tool args when using `--server`)
62
+ ### ChatGPT
63
+
64
+ Use a connector / custom MCP that runs the same `serve-stdio.mjs` (or an HTTP transport your deployment owns). Mountly does not own OAuth or hosting.
65
+
66
+ ## CI
67
+
68
+ ```yaml
69
+ # .github/workflows/mcp-verify.yml
70
+ name: mcp-verify
71
+ on: [push, pull_request]
72
+ jobs:
73
+ verify:
74
+ runs-on: ubuntu-latest
75
+ steps:
76
+ - uses: actions/checkout@v4
77
+ - uses: pnpm/action-setup@v4
78
+ - uses: actions/setup-node@v4
79
+ with: { node-version: 22, cache: pnpm }
80
+ - run: pnpm install
81
+ - run: pnpm exec mountly-mcp build
82
+ - run: pnpm exec playwright install chromium
83
+ - run: pnpm exec mountly-mcp verify --strict --render
84
+ ```
85
+
86
+ ## Add another View
87
+
88
+ ```bash
89
+ pnpm exec mountly-mcp add settings --framework react
90
+ ```
14
91
 
15
- Do not clone the Mountly monorepo for greenfield apps — this project is the canonical path.
92
+ Then register a tool with matching `resourceUri` in `server.mjs` via `registerMcpApps`.
@@ -8,6 +8,8 @@
8
8
  "dev": "mountly-mcp dev --server ./server.mjs",
9
9
  "verify": "mountly-mcp verify",
10
10
  "verify:strict": "mountly-mcp verify --strict",
11
+ "verify:render": "mountly-mcp verify --strict --render",
12
+ "doctor": "mountly-mcp doctor",
11
13
  "typecheck": "tsc --noEmit"
12
14
  },
13
15
  "dependencies": {
@@ -0,0 +1,9 @@
1
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
2
+ import createServer from "./server.mjs";
3
+
4
+ /**
5
+ * Stdio entry for Claude Desktop / VS Code / other MCP hosts.
6
+ * Never write logs to stdout: stdout is the JSON-RPC channel.
7
+ */
8
+ const server = await createServer();
9
+ await server.connect(new StdioServerTransport());
@@ -1,3 +1,4 @@
1
+ import { fileURLToPath } from "node:url";
1
2
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
3
  import { readMcpAppManifest } from "mountly-mcp/artifact";
3
4
  import { registerMcpApps } from "mountly-mcp/server";
@@ -5,6 +6,10 @@ import { z } from "zod";
5
6
 
6
7
  const URI = "{{uri}}";
7
8
 
9
+ // Resolved from this file, not the cwd: an MCP host spawns the process with a
10
+ // working directory of its own choosing.
11
+ const MANIFEST = fileURLToPath(new URL("./dist/mountly-mcp.manifest.json", import.meta.url));
12
+
8
13
  function sampleCards() {
9
14
  return [
10
15
  { label: "Requests", value: Math.floor(1200 + Math.random() * 200) },
@@ -20,7 +25,7 @@ export default async function createServer() {
20
25
  { capabilities: { tools: {}, resources: {} } },
21
26
  );
22
27
 
23
- const { artifacts } = await readMcpAppManifest("dist/mountly-mcp.manifest.json");
28
+ const { artifacts } = await readMcpAppManifest(MANIFEST);
24
29
 
25
30
  await registerMcpApps(server, {
26
31
  views: artifacts.map((artifact) => ({ artifact })),
@@ -130,7 +130,7 @@ function Dashboard() {
130
130
  <p className="eyebrow">MCP App · Mountly</p>
131
131
  <h1>{title}</h1>
132
132
  <p className="subtitle">
133
- Built with <code>mountly-mcp</code> — try Refresh to call an app-only tool.
133
+ Built with <code>mountly-mcp</code>. Try Refresh to call an app-only tool.
134
134
  </p>
135
135
  <div className="grid">
136
136
  {cards.length === 0
@@ -1,14 +1,37 @@
1
1
  # {{name}}
2
2
 
3
- MCP App scaffolded with `mountly-mcp create --framework svelte`.
3
+ MCP App scaffolded with `mountly-mcp create` (Svelte).
4
+
5
+ ## Runbook
4
6
 
5
7
  ```bash
6
8
  pnpm install
7
9
  pnpm dev
8
10
  pnpm verify
11
+ pnpm verify:render
12
+ ```
13
+
14
+ | File | Role |
15
+ | --- | --- |
16
+ | `src/view.ts` | `createMcpView` entry |
17
+ | `src/Dashboard.svelte` | View UI: `toolResult` prop |
18
+ | `server.mjs` | `registerMcpApps` factory |
19
+ | `mcp.fixtures.json` | Tool args for `dev --server` |
20
+
21
+ ## Open in a real host
22
+
23
+ `serve-stdio.mjs` is included. Point Claude Desktop or VS Code at that entry (stdio). ChatGPT: use your connector against the same process.
24
+
25
+ ## CI
26
+
27
+ ```bash
28
+ pnpm exec mountly-mcp build
29
+ pnpm exec playwright install chromium
30
+ pnpm exec mountly-mcp verify --strict --render
9
31
  ```
10
32
 
11
- - View: `src/view.ts` + `src/Dashboard.svelte`
12
- - Server: `server.mjs` (`registerMcpApps`)
33
+ ## Add another View
13
34
 
14
- Do not clone the Mountly monorepo for greenfield apps — this project is the canonical path.
35
+ ```bash
36
+ pnpm exec mountly-mcp add settings --framework svelte
37
+ ```
@@ -8,6 +8,8 @@
8
8
  "dev": "mountly-mcp dev --server ./server.mjs",
9
9
  "verify": "mountly-mcp verify",
10
10
  "verify:strict": "mountly-mcp verify --strict",
11
+ "verify:render": "mountly-mcp verify --strict --render",
12
+ "doctor": "mountly-mcp doctor",
11
13
  "typecheck": "svelte-check --tsconfig ./tsconfig.json"
12
14
  },
13
15
  "dependencies": {
@@ -0,0 +1,5 @@
1
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
2
+ import createServer from "./server.mjs";
3
+
4
+ const server = await createServer();
5
+ await server.connect(new StdioServerTransport());
@@ -1,3 +1,4 @@
1
+ import { fileURLToPath } from "node:url";
1
2
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
3
  import { readMcpAppManifest } from "mountly-mcp/artifact";
3
4
  import { registerMcpApps } from "mountly-mcp/server";
@@ -5,6 +6,10 @@ import { z } from "zod";
5
6
 
6
7
  const URI = "{{uri}}";
7
8
 
9
+ // Resolved from this file, not the cwd: an MCP host spawns the process with a
10
+ // working directory of its own choosing.
11
+ const MANIFEST = fileURLToPath(new URL("./dist/mountly-mcp.manifest.json", import.meta.url));
12
+
8
13
  function sampleCards() {
9
14
  return [
10
15
  { label: "Requests", value: Math.floor(1200 + Math.random() * 200) },
@@ -20,7 +25,7 @@ export default async function createServer() {
20
25
  { capabilities: { tools: {}, resources: {} } },
21
26
  );
22
27
 
23
- const { artifacts } = await readMcpAppManifest("dist/mountly-mcp.manifest.json");
28
+ const { artifacts } = await readMcpAppManifest(MANIFEST);
24
29
 
25
30
  await registerMcpApps(server, {
26
31
  views: artifacts.map((artifact) => ({ artifact })),
@@ -61,7 +61,7 @@
61
61
  <p class="eyebrow">MCP App · Mountly</p>
62
62
  <h1>{title}</h1>
63
63
  <p class="subtitle">
64
- Built with <code>mountly-mcp</code> — try Refresh to call an app-only tool.
64
+ Built with <code>mountly-mcp</code>. Try Refresh to call an app-only tool.
65
65
  </p>
66
66
  <div class="grid">
67
67
  {#if cards.length === 0}