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.
- package/GLOSSARY.md +37 -0
- package/README.md +103 -190
- package/dist/add-DAFMA4F3.js +263 -0
- package/dist/add-DAFMA4F3.js.map +1 -0
- package/dist/add.d.ts +13 -0
- package/dist/chunk-EOWAWZH2.js +34 -0
- package/dist/chunk-EOWAWZH2.js.map +1 -0
- package/dist/{chunk-KWVGW5Q7.js → chunk-GN2IQYV3.js} +1 -1
- package/dist/chunk-GN2IQYV3.js.map +1 -0
- package/dist/{chunk-UECZA34Q.js → chunk-OWAXBNZA.js} +10 -5
- package/dist/chunk-OWAXBNZA.js.map +1 -0
- package/dist/cli.js +97 -25
- package/dist/cli.js.map +1 -1
- package/dist/compose/index.d.ts +48 -0
- package/dist/compose/index.js +141 -0
- package/dist/compose/index.js.map +1 -0
- package/dist/connect-server-P2UZ62YC.js +7 -0
- package/dist/create.js +43 -15
- package/dist/create.js.map +1 -1
- package/dist/dev/host-entry.js +7 -0
- package/dist/dev/index.js +2 -2
- 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/json-render/index.js +4 -4
- package/package.json +17 -5
- 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-KWVGW5Q7.js.map +0 -1
- package/dist/chunk-UECZA34Q.js.map +0 -1
- package/dist/connect-server-7L4HGKKL.js +0 -7
- /package/dist/{connect-server-7L4HGKKL.js.map → connect-server-P2UZ62YC.js.map} +0 -0
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":";;;;;;AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,SAAS,MAAM,eAAe;AACvC,SAAS,qBAAqB;AAG9B,IAAM,YAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AAExD,IAAM,eAAe,QAAQ,WAAW,IAAI;AAC5C,IAAM,YAAY,QAAQ,cAAc,WAAW;AAUnD,SAAS,aAAqB;AAC5B,QAAM,MAAM,KAAK,MAAM,aAAa,KAAK,cAAc,cAAc,GAAG,MAAM,CAAC;AAG/E,MAAI,CAAC,IAAI,QAAS,OAAM,IAAI,MAAM,wDAAwD;AAC1F,SAAO,IAAI;AACb;AAEA,IAAM,YAAY,CAAC,SAAS,OAAO,UAAU,SAAS;AAS/C,SAAS,gBAAgB,MAAyC;AACvE,QAAM,OAAO,KAAK,CAAC;AACnB,MAAI,CAAC,QAAQ,KAAK,WAAW,GAAG,GAAG;AACjC,UAAM;AAAA,MACJ,gBAAgB;AAAA,MAChB;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,MAAI,YAAuB;AAC3B,MAAI,MAAM,KAAK,IAAI;AAEnB,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,GAAG;AACvC,UAAM,MAAM,KAAK,CAAC;AAClB,QAAI,QAAQ,iBAAiB,QAAQ,MAAM;AACzC,YAAM,QAAQ,KAAK,EAAE,CAAC;AACtB,UAAI,UAAU,QAAW;AACvB,cAAM;AAAA,UACJ,gBAAgB;AAAA,UAChB,GAAG,GAAG;AAAA,UACN,cAAc,UAAU,KAAK,IAAI,CAAC;AAAA,QACpC;AAAA,MACF;AACA,UAAI,CAAC,UAAU,SAAS,KAAkB,GAAG;AAC3C,cAAM;AAAA,UACJ,gBAAgB;AAAA,UAChB,cAAc,KAAK;AAAA,UACnB,cAAc,UAAU,KAAK,IAAI,CAAC;AAAA,QACpC;AAAA,MACF;AACA,kBAAY;AAAA,IACd,WAAW,QAAQ,SAAS;AAC1B,YAAM,QAAQ,KAAK,EAAE,CAAC;AACtB,UAAI,UAAU,QAAW;AACvB,cAAM;AAAA,UACJ,gBAAgB;AAAA,UAChB;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,YAAM;AAAA,IACR,OAAO;AACL,YAAM;AAAA,QACJ,gBAAgB;AAAA,QAChB,0BAA0B,GAAG;AAAA,QAC7B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,MAAM,WAAW,IAAI;AAChC;AAEA,SAAS,QAAQ,MAAsB;AACrC,SAAO,KACJ,KAAK,EACL,YAAY,EACZ,QAAQ,eAAe,GAAG,EAC1B,QAAQ,YAAY,EAAE;AAC3B;AAEA,SAAS,gBAAgB,KAAa,KAAmC;AACvE,aAAW,SAAS,YAAY,GAAG,GAAG;AACpC,UAAM,OAAO,KAAK,KAAK,KAAK;AAC5B,QAAI,SAAS,IAAI,EAAE,YAAY,GAAG;AAChC,sBAAgB,MAAM,GAAG;AACzB;AAAA,IACF;AACA,QAAI,CAAC,MAAM,SAAS,OAAO,EAAG;AAC9B,QAAI,UAAU,aAAa,MAAM,MAAM;AACvC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC9C,gBAAU,QAAQ,MAAM,KAAK,GAAG,IAAI,EAAE,KAAK,KAAK;AAAA,IAClD;AACA,kBAAc,KAAK,QAAQ,WAAW,EAAE,GAAG,OAAO;AAClD,eAAW,IAAI;AAAA,EACjB;AACF;AAEA,eAAsB,cAAc,MAAiC;AACnE,QAAM,SAAS,QAAQ,KAAK,GAAG;AAC/B,MAAI,WAAW,MAAM,GAAG;AACtB,UAAM;AAAA,MACJ,gBAAgB;AAAA,MAChB,oCAAoC,MAAM;AAAA,MAC1C;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,KAAK,WAAW,KAAK,SAAS;AAC7C,MAAI,CAAC,WAAW,MAAM,GAAG;AACvB,UAAM;AAAA,MACJ,gBAAgB;AAAA,MAChB,2BAA2B,KAAK,SAAS,mBAAmB,MAAM;AAAA,MAClE,cAAc,UAAU,KAAK,IAAI,CAAC;AAAA,IACpC;AAAA,EACF;AAEA,YAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;AACrC,SAAO,QAAQ,QAAQ,EAAE,WAAW,KAAK,CAAC;AAE1C,QAAM,OAAO,QAAQ,KAAK,IAAI,KAAK;AACnC,kBAAgB,QAAQ;AAAA,IACtB,MAAM,KAAK;AAAA,IACX;AAAA,IACA,KAAK,QAAQ,IAAI;AAAA,IACjB,WAAW,KAAK;AAAA,IAChB,YAAY,WAAW;AAAA,EACzB,CAAC;AAED,UAAQ,OAAO;AAAA,IACb;AAAA,MACE;AAAA,MACA,0BAAqB,KAAK,IAAI,KAAK,KAAK,SAAS,QAAQ,MAAM;AAAA,MAC/D;AAAA,MACA;AAAA,MACA,QAAQ,KAAK,GAAG;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AACF;","names":[]}
|
package/dist/dev/host-entry.js
CHANGED
|
@@ -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-
|
|
4
|
+
} from "../chunk-GN2IQYV3.js";
|
|
5
5
|
import {
|
|
6
6
|
connectMcpServer
|
|
7
|
-
} from "../chunk-
|
|
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"]}
|
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;
|
|
@@ -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
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
@@ -1,14 +1,37 @@
|
|
|
1
1
|
# {{name}}
|
|
2
2
|
|
|
3
|
-
MCP App scaffolded with `mountly-mcp create
|
|
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
|
-
|
|
12
|
-
- Server: `server.mjs` (`registerMcpApps`)
|
|
33
|
+
## Add another View
|
|
13
34
|
|
|
14
|
-
|
|
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": {
|
|
@@ -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 })),
|
|
@@ -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
|
|
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}
|