mountly-mcp 4.0.1 → 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.
- package/GLOSSARY.md +37 -0
- package/README.md +75 -197
- package/dist/add-DAFMA4F3.js +263 -0
- package/dist/add-DAFMA4F3.js.map +1 -0
- package/dist/add.d.ts +13 -0
- package/dist/bridge/iframe-entry.js +3 -1
- package/dist/bridge/index.js +1 -1
- package/dist/{chunk-JVQZGKBL.js → chunk-2HNXL5A4.js} +4 -2
- package/dist/chunk-2HNXL5A4.js.map +1 -0
- package/dist/{chunk-SADNMGP6.js → chunk-5L3QHYWK.js} +1 -1
- package/dist/{chunk-SADNMGP6.js.map → chunk-5L3QHYWK.js.map} +1 -1
- package/dist/chunk-EOWAWZH2.js +34 -0
- package/dist/chunk-EOWAWZH2.js.map +1 -0
- package/dist/{chunk-UECZA34Q.js → chunk-OWAXBNZA.js} +10 -5
- package/dist/chunk-OWAXBNZA.js.map +1 -0
- package/dist/{chunk-AEVQKFXX.js → chunk-SXF23BZD.js} +2 -2
- package/dist/cli.js +96 -24
- package/dist/cli.js.map +1 -1
- package/dist/connect-server-P2UZ62YC.js +7 -0
- package/dist/create.js +43 -15
- package/dist/create.js.map +1 -1
- package/dist/dev/index.js +1 -1
- package/dist/doctor-B54H6CRN.js +122 -0
- package/dist/doctor-B54H6CRN.js.map +1 -0
- package/dist/doctor.d.ts +16 -0
- package/dist/errors-4ERW7HZB.js +11 -0
- package/dist/errors-4ERW7HZB.js.map +1 -0
- package/dist/errors.d.ts +25 -0
- package/dist/index.js +2 -2
- package/dist/json-render/index.js +2 -2
- package/dist/react/index.js +2 -2
- package/dist/svelte/index.js +1 -1
- package/dist/vue/index.js +1 -1
- package/package.json +14 -11
- package/templates/react/README.md.tmpl +83 -6
- package/templates/react/package.json.tmpl +2 -0
- package/templates/react/serve-stdio.mjs.tmpl +9 -0
- package/templates/react/server.mjs.tmpl +6 -1
- package/templates/react/src/view.tsx.tmpl +1 -1
- package/templates/svelte/README.md.tmpl +27 -4
- package/templates/svelte/package.json.tmpl +2 -0
- package/templates/svelte/serve-stdio.mjs.tmpl +5 -0
- package/templates/svelte/server.mjs.tmpl +6 -1
- package/templates/svelte/src/Dashboard.svelte.tmpl +1 -1
- package/templates/vanilla/README.md.tmpl +27 -11
- package/templates/vanilla/package.json.tmpl +2 -0
- package/templates/vanilla/serve-stdio.mjs.tmpl +5 -0
- package/templates/vanilla/server.mjs.tmpl +6 -1
- package/templates/vanilla/src/view.ts.tmpl +1 -1
- package/templates/vue/README.md.tmpl +27 -4
- package/templates/vue/package.json.tmpl +2 -0
- package/templates/vue/serve-stdio.mjs.tmpl +5 -0
- package/templates/vue/server.mjs.tmpl +6 -1
- package/templates/vue/src/Dashboard.vue.tmpl +1 -1
- package/dist/chunk-JVQZGKBL.js.map +0 -1
- package/dist/chunk-UECZA34Q.js.map +0 -1
- package/dist/connect-server-7L4HGKKL.js +0 -7
- /package/dist/{chunk-AEVQKFXX.js.map → chunk-SXF23BZD.js.map} +0 -0
- /package/dist/{connect-server-7L4HGKKL.js.map → connect-server-P2UZ62YC.js.map} +0 -0
package/dist/create.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CLI_ERROR_CODES,
|
|
3
|
+
cliError
|
|
4
|
+
} from "./chunk-EOWAWZH2.js";
|
|
5
|
+
|
|
1
6
|
// src/create.ts
|
|
2
7
|
import {
|
|
3
8
|
cpSync,
|
|
@@ -23,8 +28,10 @@ var SUPPORTED = ["react", "vue", "svelte", "vanilla"];
|
|
|
23
28
|
function parseCreateArgs(argv) {
|
|
24
29
|
const name = argv[0];
|
|
25
30
|
if (!name || name.startsWith("-")) {
|
|
26
|
-
throw
|
|
27
|
-
|
|
31
|
+
throw cliError(
|
|
32
|
+
CLI_ERROR_CODES.UNKNOWN_OPTION,
|
|
33
|
+
"create requires a project name",
|
|
34
|
+
"Example: mountly-mcp create my-app --framework react"
|
|
28
35
|
);
|
|
29
36
|
}
|
|
30
37
|
let framework = "react";
|
|
@@ -33,19 +40,37 @@ function parseCreateArgs(argv) {
|
|
|
33
40
|
const arg = argv[i];
|
|
34
41
|
if (arg === "--framework" || arg === "-f") {
|
|
35
42
|
const value = argv[++i];
|
|
36
|
-
if (value === void 0)
|
|
43
|
+
if (value === void 0) {
|
|
44
|
+
throw cliError(
|
|
45
|
+
CLI_ERROR_CODES.UNKNOWN_OPTION,
|
|
46
|
+
`${arg} needs a value`,
|
|
47
|
+
`Available: ${SUPPORTED.join(", ")}`
|
|
48
|
+
);
|
|
49
|
+
}
|
|
37
50
|
if (!SUPPORTED.includes(value)) {
|
|
38
|
-
throw
|
|
39
|
-
|
|
51
|
+
throw cliError(
|
|
52
|
+
CLI_ERROR_CODES.UNKNOWN_OPTION,
|
|
53
|
+
`framework "${value}" not supported`,
|
|
54
|
+
`Available: ${SUPPORTED.join(", ")}`
|
|
40
55
|
);
|
|
41
56
|
}
|
|
42
57
|
framework = value;
|
|
43
58
|
} else if (arg === "--dir") {
|
|
44
59
|
const value = argv[++i];
|
|
45
|
-
if (value === void 0)
|
|
60
|
+
if (value === void 0) {
|
|
61
|
+
throw cliError(
|
|
62
|
+
CLI_ERROR_CODES.UNKNOWN_OPTION,
|
|
63
|
+
"--dir needs a value",
|
|
64
|
+
"Example: --dir ./apps/my-app"
|
|
65
|
+
);
|
|
66
|
+
}
|
|
46
67
|
dir = value;
|
|
47
68
|
} else {
|
|
48
|
-
throw
|
|
69
|
+
throw cliError(
|
|
70
|
+
CLI_ERROR_CODES.UNKNOWN_OPTION,
|
|
71
|
+
`unknown create option '${arg}'`,
|
|
72
|
+
"Options: --framework | --dir"
|
|
73
|
+
);
|
|
49
74
|
}
|
|
50
75
|
}
|
|
51
76
|
return { name, framework, dir };
|
|
@@ -72,12 +97,18 @@ function renderTemplates(dir, ctx) {
|
|
|
72
97
|
async function createProject(args) {
|
|
73
98
|
const target = resolve(args.dir);
|
|
74
99
|
if (existsSync(target)) {
|
|
75
|
-
throw
|
|
100
|
+
throw cliError(
|
|
101
|
+
CLI_ERROR_CODES.TARGET_EXISTS,
|
|
102
|
+
`target directory already exists: ${target}`,
|
|
103
|
+
"Choose another --dir, or remove the existing folder"
|
|
104
|
+
);
|
|
76
105
|
}
|
|
77
106
|
const tplDir = join(TEMPLATES, args.framework);
|
|
78
107
|
if (!existsSync(tplDir)) {
|
|
79
|
-
throw
|
|
80
|
-
|
|
108
|
+
throw cliError(
|
|
109
|
+
CLI_ERROR_CODES.MISSING_TEMPLATE,
|
|
110
|
+
`template for framework "${args.framework}" is missing at ${tplDir}`,
|
|
111
|
+
`Available: ${SUPPORTED.join(", ")}`
|
|
81
112
|
);
|
|
82
113
|
}
|
|
83
114
|
mkdirSync(target, { recursive: true });
|
|
@@ -95,13 +126,10 @@ async function createProject(args) {
|
|
|
95
126
|
"",
|
|
96
127
|
`\u2713 Created MCP App ${args.name} (${args.framework}) at ${target}`,
|
|
97
128
|
"",
|
|
98
|
-
"Next
|
|
129
|
+
"Next:",
|
|
99
130
|
` cd ${args.dir}`,
|
|
100
131
|
" pnpm install",
|
|
101
|
-
" pnpm dev
|
|
102
|
-
" pnpm verify # conformance check",
|
|
103
|
-
"",
|
|
104
|
-
"Do not clone the Mountly monorepo for greenfield apps \u2014 this scaffold is the canonical path.",
|
|
132
|
+
" pnpm dev",
|
|
105
133
|
""
|
|
106
134
|
].join("\n")
|
|
107
135
|
);
|
package/dist/create.js.map
CHANGED
|
@@ -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
|
|
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":[]}
|
package/dist/dev/index.js
CHANGED
|
@@ -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"]}
|
package/dist/doctor.d.ts
ADDED
|
@@ -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 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/errors.d.ts
ADDED
|
@@ -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/dist/index.js
CHANGED
|
@@ -5,12 +5,12 @@ import {
|
|
|
5
5
|
MCP_VIEW_GLOBAL_KEY,
|
|
6
6
|
getPublishedMcpView,
|
|
7
7
|
publishMcpView
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-5L3QHYWK.js";
|
|
9
9
|
import {
|
|
10
10
|
App,
|
|
11
11
|
PostMessageTransport,
|
|
12
12
|
runBridge
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-2HNXL5A4.js";
|
|
14
14
|
import {
|
|
15
15
|
EXTENSION_ID,
|
|
16
16
|
LATEST_PROTOCOL_VERSION,
|
package/dist/react/index.js
CHANGED
|
@@ -14,8 +14,8 @@ import {
|
|
|
14
14
|
useToolInputPartial,
|
|
15
15
|
useToolResult,
|
|
16
16
|
useUpdateModelContext
|
|
17
|
-
} from "../chunk-
|
|
18
|
-
import "../chunk-
|
|
17
|
+
} from "../chunk-SXF23BZD.js";
|
|
18
|
+
import "../chunk-5L3QHYWK.js";
|
|
19
19
|
export {
|
|
20
20
|
McpContext,
|
|
21
21
|
createMcpView,
|
package/dist/svelte/index.js
CHANGED
package/dist/vue/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mountly-mcp",
|
|
3
|
-
"version": "4.0
|
|
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",
|
|
12
|
+
"mcp-view",
|
|
11
13
|
"model-context-protocol",
|
|
12
14
|
"react",
|
|
13
15
|
"sep-1865",
|
|
14
16
|
"svelte",
|
|
17
|
+
"ui-resource",
|
|
15
18
|
"vite-plugin",
|
|
16
|
-
"vue"
|
|
17
|
-
"mcp-view"
|
|
19
|
+
"vue"
|
|
18
20
|
],
|
|
19
21
|
"license": "Apache-2.0",
|
|
20
22
|
"repository": {
|
|
@@ -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,8 +110,8 @@
|
|
|
107
110
|
"dependencies": {
|
|
108
111
|
"@modelcontextprotocol/ext-apps": "^1.7.5",
|
|
109
112
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
110
|
-
"mountly": "^0.
|
|
111
|
-
"mountly-react": "^2.0
|
|
113
|
+
"mountly": "^1.0.1",
|
|
114
|
+
"mountly-react": "^2.1.0",
|
|
112
115
|
"zod": "^4.4.3"
|
|
113
116
|
},
|
|
114
117
|
"devDependencies": {
|
|
@@ -125,20 +128,20 @@
|
|
|
125
128
|
"tsup": "^8.5.1",
|
|
126
129
|
"typescript": "^7.0.2",
|
|
127
130
|
"vite": "^8.1.5",
|
|
128
|
-
"mountly-
|
|
129
|
-
"mountly-
|
|
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",
|
|
133
136
|
"@json-render/react": "^0.20.0",
|
|
134
137
|
"ai": "^7.0.65",
|
|
135
138
|
"axe-core": ">=4.10.0",
|
|
136
|
-
"mountly-svelte": "^2.0
|
|
137
|
-
"mountly-vue": "^2.0
|
|
139
|
+
"mountly-svelte": "^2.1.0",
|
|
140
|
+
"mountly-vue": "^2.1.0",
|
|
138
141
|
"playwright": ">=1.62.1",
|
|
139
142
|
"react": "^19",
|
|
140
143
|
"react-dom": "^19",
|
|
141
|
-
"vite": "^8
|
|
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
|
|
8
|
-
pnpm verify
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
|
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
|