mountly-mcp 4.0.2 → 4.1.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 (45) hide show
  1. package/GLOSSARY.md +37 -0
  2. package/README.md +75 -197
  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-UECZA34Q.js → chunk-OWAXBNZA.js} +10 -5
  9. package/dist/chunk-OWAXBNZA.js.map +1 -0
  10. package/dist/cli.js +96 -24
  11. package/dist/cli.js.map +1 -1
  12. package/dist/connect-server-P2UZ62YC.js +7 -0
  13. package/dist/create.js +43 -15
  14. package/dist/create.js.map +1 -1
  15. package/dist/dev/index.js +1 -1
  16. package/dist/doctor-B54H6CRN.js +122 -0
  17. package/dist/doctor-B54H6CRN.js.map +1 -0
  18. package/dist/doctor.d.ts +16 -0
  19. package/dist/errors-4ERW7HZB.js +11 -0
  20. package/dist/errors-4ERW7HZB.js.map +1 -0
  21. package/dist/errors.d.ts +25 -0
  22. package/package.json +9 -6
  23. package/templates/react/README.md.tmpl +83 -6
  24. package/templates/react/package.json.tmpl +2 -0
  25. package/templates/react/serve-stdio.mjs.tmpl +9 -0
  26. package/templates/react/server.mjs.tmpl +6 -1
  27. package/templates/react/src/view.tsx.tmpl +1 -1
  28. package/templates/svelte/README.md.tmpl +27 -4
  29. package/templates/svelte/package.json.tmpl +2 -0
  30. package/templates/svelte/serve-stdio.mjs.tmpl +5 -0
  31. package/templates/svelte/server.mjs.tmpl +6 -1
  32. package/templates/svelte/src/Dashboard.svelte.tmpl +1 -1
  33. package/templates/vanilla/README.md.tmpl +27 -11
  34. package/templates/vanilla/package.json.tmpl +2 -0
  35. package/templates/vanilla/serve-stdio.mjs.tmpl +5 -0
  36. package/templates/vanilla/server.mjs.tmpl +6 -1
  37. package/templates/vanilla/src/view.ts.tmpl +1 -1
  38. package/templates/vue/README.md.tmpl +27 -4
  39. package/templates/vue/package.json.tmpl +2 -0
  40. package/templates/vue/serve-stdio.mjs.tmpl +5 -0
  41. package/templates/vue/server.mjs.tmpl +6 -1
  42. package/templates/vue/src/Dashboard.vue.tmpl +1 -1
  43. package/dist/chunk-UECZA34Q.js.map +0 -1
  44. package/dist/connect-server-7L4HGKKL.js +0 -7
  45. /package/dist/{connect-server-7L4HGKKL.js.map → connect-server-P2UZ62YC.js.map} +0 -0
@@ -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":";;;;;;AAAA,SAAS,YAAY,oBAAoB;AACzC,SAAS,qBAAqB;AAC9B,SAAS,eAAe;AAcxB,SAAS,YAAoB;AAC3B,SAAO,OAAO,QAAQ,SAAS,KAAK,MAAM,GAAG,EAAE,CAAC,KAAK,CAAC;AACxD;AAEA,SAAS,WAAW,WAAmB,SAAgC;AACrE,MAAI;AACF,UAAMA,WAAU,cAAc,QAAQ,SAAS,cAAc,CAAC;AAC9D,WAAOA,SAAQ,QAAQ,SAAS;AAAA,EAClC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMO,SAAS,UAAU,MAAM,QAAQ,IAAI,GAAiB;AAC3D,QAAM,SAAwB,CAAC;AAE/B,QAAM,QAAQ,UAAU;AACxB,SAAO,KAAK;AAAA,IACV,IAAI;AAAA,IACJ,IAAI,SAAS;AAAA,IACb,QACE,SAAS,KACL,QAAQ,QAAQ,SAAS,IAAI,yCAC7B,QAAQ,QAAQ,SAAS,IAAI;AAAA,EACrC,CAAC;AAED,QAAM,uBAAuB;AAAA,IAC3B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,IAAI,CAAC,SAAS,QAAQ,KAAK,IAAI,CAAC;AAClC,QAAM,aAAa,qBAAqB,KAAK,CAAC,SAAS,WAAW,IAAI,CAAC;AACvE,SAAO,KAAK;AAAA,IACV,IAAI;AAAA,IACJ,IAAI,QAAQ,UAAU;AAAA,IACtB,QAAQ,aACJ,SAAS,UAAU,KACnB;AAAA,EACN,CAAC;AAED,MAAI,YAAY;AACd,UAAM,SAAS,aAAa,YAAY,MAAM;AAC9C,UAAM,YAAY,uBAAuB,KAAK,MAAM;AACpD,WAAO,KAAK;AAAA,MACV,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,QAAQ,YACJ,0CACA,oDAAoD,UAAU;AAAA,IACpE,CAAC;AAAA,EACH;AAEA,QAAM,WAAW,QAAQ,KAAK,gCAAgC;AAC9D,SAAO,KAAK;AAAA,IACV,IAAI;AAAA,IACJ,IAAI,WAAW,QAAQ;AAAA,IACvB,QAAQ,WAAW,QAAQ,IACvB,SAAS,QAAQ,KACjB;AAAA,EACN,CAAC;AAED,QAAM,aAAa,WAAW,cAAc,GAAG,KAAK,WAAW,oBAAoB,GAAG;AACtF,SAAO,KAAK;AAAA,IACV,IAAI;AAAA,IACJ,IAAI,QAAQ,UAAU;AAAA,IACtB,QAAQ,aACJ,8CAA8C,UAAU,MACxD;AAAA,EACN,CAAC;AAED,QAAM,UAAU,QAAQ,KAAK,cAAc;AAC3C,MAAI,WAAW,OAAO,GAAG;AACvB,UAAM,MAAM,KAAK,MAAM,aAAa,SAAS,MAAM,CAAC;AAKpD,UAAM,OAAO,EAAE,GAAG,IAAI,cAAc,GAAG,IAAI,gBAAgB;AAC3D,QAAI,KAAK,OAAO;AACd,YAAM,YAAY,WAAW,sBAAsB,GAAG;AACtD,UAAI,WAAW;AACb,cAAM,WAAW,KAAK,MAAM,aAAa,WAAW,MAAM,CAAC;AAC3D,cAAM,aAAa,QAAQ,SAAS,WAAW,KAAK,MAAM,GAAG,EAAE,CAAC,CAAC;AACjE,eAAO,KAAK;AAAA,UACV,IAAI;AAAA,UACJ,IAAI,cAAc;AAAA,UAClB,QACE,cAAc,KACV,SAAS,SAAS,OAAO,UACzB,SAAS,SAAS,OAAO;AAAA,QACjC,CAAC;AAAA,MACH;AAAA,IACF;AACA,QAAI,KAAK,MAAM;AACb,YAAM,WAAW,WAAW,qBAAqB,GAAG;AACpD,UAAI,UAAU;AACZ,cAAM,UAAU,KAAK,MAAM,aAAa,UAAU,MAAM,CAAC;AACzD,cAAM,YAAY,QAAQ,QAAQ,WAAW,KAAK,MAAM,GAAG,EAAE,CAAC,CAAC;AAC/D,eAAO,KAAK;AAAA,UACV,IAAI;AAAA,UACJ,IAAI,aAAa;AAAA,UACjB,QACE,aAAa,IACT,QAAQ,QAAQ,OAAO,UACvB,QAAQ,QAAQ,OAAO;AAAA,QAC/B,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAGA,QAAM,OAAO,OAAO,OAAO,CAAC,MAAM,EAAE,OAAO,cAAc,EAAE,OAAO,YAAY;AAC9E,QAAM,KAAK,KAAK,MAAM,CAAC,MAAM,EAAE,EAAE;AAEjC,SAAO,EAAE,IAAI,OAAO;AACtB;AAEO,SAAS,mBAAmB,QAA8B;AAC/D,QAAM,QAAQ,CAAC,sBAAsB,EAAE;AACvC,aAAW,SAAS,OAAO,QAAQ;AACjC,UAAM,KAAK,GAAG,MAAM,KAAK,OAAO,MAAM,KAAK,MAAM,GAAG,OAAO,EAAE,CAAC,IAAI,MAAM,MAAM,EAAE;AAAA,EAClF;AACA,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,OAAO,KAAK,gDAAgD,uBAAuB;AAC9F,QAAM,KAAK,EAAE;AACb,SAAO,GAAG,MAAM,KAAK,IAAI,CAAC;AAAA;AAC5B;AAEO,SAAS,cAAc,MAAM,QAAQ,IAAI,GAAS;AACvD,QAAM,SAAS,UAAU,GAAG;AAC5B,UAAQ,OAAO,MAAM,mBAAmB,MAAM,CAAC;AAC/C,MAAI,CAAC,OAAO,IAAI;AACd,UAAM;AAAA,MACJ,gBAAgB;AAAA,MAChB;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;","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;
package/package.json CHANGED
@@ -1,18 +1,20 @@
1
1
  {
2
2
  "name": "mountly-mcp",
3
- "version": "4.0.2",
3
+ "version": "4.1.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",
@@ -107,7 +110,7 @@
107
110
  "dependencies": {
108
111
  "@modelcontextprotocol/ext-apps": "^1.7.5",
109
112
  "@modelcontextprotocol/sdk": "^1.30.0",
110
- "mountly": "^1.0.0",
113
+ "mountly": "^1.0.1",
111
114
  "mountly-react": "^2.1.0",
112
115
  "zod": "^4.4.3"
113
116
  },
@@ -125,8 +128,8 @@
125
128
  "tsup": "^8.5.1",
126
129
  "typescript": "^7.0.2",
127
130
  "vite": "^8.1.5",
128
- "mountly-svelte": "^2.1.0",
129
- "mountly-vue": "^2.1.0"
131
+ "mountly-vue": "^2.1.0",
132
+ "mountly-svelte": "^2.1.0"
130
133
  },
131
134
  "peerDependencies": {
132
135
  "@json-render/core": "^0.20.0",
@@ -138,7 +141,7 @@
138
141
  "playwright": ">=1.62.1",
139
142
  "react": "^19",
140
143
  "react-dom": "^19",
141
- "vite": "^8.2.1"
144
+ "vite": "^8"
142
145
  },
143
146
  "peerDependenciesMeta": {
144
147
  "@json-render/core": {
@@ -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}
@@ -1,20 +1,36 @@
1
1
  # {{name}}
2
2
 
3
- MCP App scaffolded with `mountly-mcp create`.
3
+ MCP App scaffolded with `mountly-mcp create` (vanilla: no framework).
4
+
5
+ ## Runbook
4
6
 
5
7
  ```bash
6
8
  pnpm install
7
- pnpm dev # sandboxed host on :5179
8
- pnpm verify # conformance
9
+ pnpm dev
10
+ pnpm verify
11
+ pnpm verify:render
9
12
  ```
10
13
 
11
- - View: `src/view.ts` (`publishMcpView`)
12
- - Server: `server.mjs` (`registerMcpApps`)
13
- - Fixtures: `mcp.fixtures.json` (tool args when using `--server`)
14
+ | File | Role |
15
+ | --- | --- |
16
+ | `src/view.ts` | `publishMcpView`: `mount` / `update` / `unmount` |
17
+ | `server.mjs` | `registerMcpApps` factory |
18
+ | `mcp.fixtures.json` | Tool args for `dev --server` |
19
+
20
+ ## Open in a real host
21
+
22
+ `serve-stdio.mjs` is included. Register that command in Claude Desktop / VS Code / ChatGPT.
14
23
 
15
- No framework, no adapter: a View is just `mount` / `update` / `unmount`, so
16
- `publishMcpView` takes the object directly. The bridge drives it exactly as it
17
- drives a React, Vue or Svelte View. Add a framework later by swapping
18
- `publishMcpView(...)` for that framework's `createMcpView(Component)`.
24
+ ## CI
19
25
 
20
- Do not clone the Mountly monorepo for greenfield apps — this project is the canonical path.
26
+ ```bash
27
+ pnpm exec mountly-mcp build
28
+ pnpm exec playwright install chromium
29
+ pnpm exec mountly-mcp verify --strict --render
30
+ ```
31
+
32
+ ## Add another View
33
+
34
+ ```bash
35
+ pnpm exec mountly-mcp add settings --framework vanilla
36
+ ```
@@ -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,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 })),
@@ -2,7 +2,7 @@ import { publishMcpView, type McpViewProps } from "mountly-mcp";
2
2
 
3
3
  /**
4
4
  * No framework, no adapter. A View is just `mount` / `update` / `unmount`, so
5
- * `publishMcpView` takes this object directly — the bridge drives it exactly
5
+ * `publishMcpView` takes this object directly. The bridge drives it exactly
6
6
  * as it drives a React, Vue or Svelte View.
7
7
  */
8
8
 
@@ -1,14 +1,37 @@
1
1
  # {{name}}
2
2
 
3
- MCP App scaffolded with `mountly-mcp create --framework vue`.
3
+ MCP App scaffolded with `mountly-mcp create` (Vue).
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.vue` | View UI: `useToolResult` |
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 / VS Code at `node` + absolute path to that file (see the React scaffold README for JSON shapes). 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.vue`
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 vue
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": "vue-tsc --noEmit"
12
14
  },
13
15
  "dependencies": {