@mangtre/mcp 0.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/LICENSE +26 -0
- package/dist/index.js +196 -0
- package/package.json +29 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
Măng — Proprietary License
|
|
2
|
+
|
|
3
|
+
Copyright © 2026 RumitX. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This software and its source code (the "Software"), including the Măng shell,
|
|
6
|
+
the @mangtre/* packages, and the bundled mini-apps in this repository, are the
|
|
7
|
+
confidential and proprietary property of RumitX.
|
|
8
|
+
|
|
9
|
+
No license, right, or permission is granted to any person to use, copy, modify,
|
|
10
|
+
merge, publish, distribute, sublicense, sell, or create derivative works of the
|
|
11
|
+
Software, in whole or in part, without the prior written consent of RumitX.
|
|
12
|
+
|
|
13
|
+
Unauthorized copying, distribution, or use of the Software, via any medium, is
|
|
14
|
+
strictly prohibited.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
18
|
+
FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL RUMITX BE LIABLE
|
|
19
|
+
FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY ARISING FROM, OUT OF, OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
21
|
+
|
|
22
|
+
Note: this proprietary notice protects the codebase during the early (NOW)
|
|
23
|
+
horizon. When Măng opens to third-party creators, a separate license may be
|
|
24
|
+
issued for the fork-able starter kit.
|
|
25
|
+
|
|
26
|
+
For licensing inquiries: RumitX — https://rumitx.com
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
|
|
8
|
+
// src/tools.ts
|
|
9
|
+
import { existsSync } from "fs";
|
|
10
|
+
import { readFile } from "fs/promises";
|
|
11
|
+
import { resolve } from "path";
|
|
12
|
+
import {
|
|
13
|
+
ApiError,
|
|
14
|
+
apiFetch,
|
|
15
|
+
checkBundle,
|
|
16
|
+
extractManifestComment,
|
|
17
|
+
loadAuth,
|
|
18
|
+
scaffoldApp
|
|
19
|
+
} from "@mangtre/cli/lib";
|
|
20
|
+
var DEFAULT_BUNDLE = "dist/app.js";
|
|
21
|
+
function getStandard() {
|
|
22
|
+
return [
|
|
23
|
+
"# chu\u1EA9n M\u0103ng \u2014 what a mini-app MUST satisfy",
|
|
24
|
+
"",
|
|
25
|
+
"Contract: export `{ manifest, mount }` from ONE ESM file. `mount(root, sdk) => unmount`.",
|
|
26
|
+
"Reach the outside world ONLY via `sdk.*` (storage/theme/data/\u2026) \u2014 never raw fetch/storage/eval.",
|
|
27
|
+
"",
|
|
28
|
+
"Manifest (Zod-validated): id (lowercase slug 3\u201340), name, icon (emoji), version (semver),",
|
|
29
|
+
"permissions[] (storage|theme|ai|identity|context|data), optional commands[], surfaces[], flow[].",
|
|
30
|
+
"Declare a `flow` (lu\u1ED3ng ch\xEDnh): each step's `checkpoint` must match a `data-mang-checkpoint` el.",
|
|
31
|
+
"",
|
|
32
|
+
"Hard limits (FAIL): bundle \u2264 2 MB \xB7 no eval / new Function / remote import() / WebSocket.",
|
|
33
|
+
"Warnings: direct fetch / localStorage / document.write (route through sdk.* instead).",
|
|
34
|
+
"Design: desktop-responsive (verify 1440px + 390px), use @mangtre/ui for auto light/dark.",
|
|
35
|
+
"",
|
|
36
|
+
"Build: `mang build` (Vite lib \u2192 dist/app.js + the // mang-manifest: line). Preflight: `mang check`.",
|
|
37
|
+
"Publish: `mang login` then `mang publish`. These mirror the server gate exactly."
|
|
38
|
+
].join("\n");
|
|
39
|
+
}
|
|
40
|
+
function formatReport(r) {
|
|
41
|
+
const lines = [];
|
|
42
|
+
if (!r.manifestFound) lines.push("\u26A0\uFE0F no manifest comment found \u2014 run `mang build` first.");
|
|
43
|
+
for (const f of r.findings)
|
|
44
|
+
lines.push(`${f.severity === "fail" ? "\u2716" : "\u26A0"} [${f.check}] ${f.message}`);
|
|
45
|
+
lines.push(
|
|
46
|
+
r.passed ? `\u2705 PASS \u2014 ${(r.bytes / 1024).toFixed(0)} KB. Ready to publish.` : `\u274C FAIL \u2014 ${r.findings.filter((f) => f.severity === "fail").length} error(s).`
|
|
47
|
+
);
|
|
48
|
+
return lines.join("\n");
|
|
49
|
+
}
|
|
50
|
+
async function runCheck(args) {
|
|
51
|
+
let source = args.source;
|
|
52
|
+
if (!source) {
|
|
53
|
+
const path = args.bundlePath ?? DEFAULT_BUNDLE;
|
|
54
|
+
const abs = resolve(process.cwd(), path);
|
|
55
|
+
if (!existsSync(abs)) return `\u274C Bundle not found: ${path}. Run \`mang build\` first.`;
|
|
56
|
+
source = await readFile(abs, "utf8");
|
|
57
|
+
}
|
|
58
|
+
return formatReport(checkBundle({ source, appId: args.appId }));
|
|
59
|
+
}
|
|
60
|
+
async function runScaffold(args) {
|
|
61
|
+
const targetDir = resolve(process.cwd(), args.dir ?? args.slug);
|
|
62
|
+
const written = await scaffoldApp({
|
|
63
|
+
slug: args.slug,
|
|
64
|
+
name: args.name ?? args.slug,
|
|
65
|
+
icon: args.icon ?? "\u{1F331}",
|
|
66
|
+
targetDir
|
|
67
|
+
});
|
|
68
|
+
return `\u2705 Scaffolded "${args.slug}" (${written.length} files) at ${args.dir ?? args.slug}.
|
|
69
|
+
Next: pnpm install \u2192 mang build \u2192 mang publish.`;
|
|
70
|
+
}
|
|
71
|
+
function asManifest(v) {
|
|
72
|
+
if (v && typeof v === "object" && !Array.isArray(v)) {
|
|
73
|
+
const m = v;
|
|
74
|
+
if (["id", "name", "icon", "version"].every((k) => typeof m[k] === "string")) {
|
|
75
|
+
return m;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
async function runWhoami() {
|
|
81
|
+
const auth = loadAuth();
|
|
82
|
+
if (!auth) return "Not logged in. Run `mang login` in a terminal first.";
|
|
83
|
+
try {
|
|
84
|
+
const me = await apiFetch("/v1/me", {
|
|
85
|
+
base: auth.api,
|
|
86
|
+
token: auth.token
|
|
87
|
+
});
|
|
88
|
+
return `Logged in as @${me.handle} (${me.roles.join(", ")}) on ${auth.api}.`;
|
|
89
|
+
} catch (err) {
|
|
90
|
+
return `Auth token invalid (${err.message}). Run \`mang login\` again.`;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async function runStatus() {
|
|
94
|
+
const auth = loadAuth();
|
|
95
|
+
if (!auth) return "Not logged in. Run `mang login` first.";
|
|
96
|
+
const data = await apiFetch("/v1/apps/mine", { base: auth.api, token: auth.token });
|
|
97
|
+
if (data.apps.length === 0) return "No apps yet. Use scaffold \u2192 mang build \u2192 publish.";
|
|
98
|
+
return data.apps.map((a) => {
|
|
99
|
+
const v = a.versions[0];
|
|
100
|
+
return `\u2022 ${a.nameVi} (${a.id}) \u2014 ${a.status}${v ? ` \xB7 v${v.version}: ${v.status}` : ""}`;
|
|
101
|
+
}).join("\n");
|
|
102
|
+
}
|
|
103
|
+
async function runPublish(args) {
|
|
104
|
+
const auth = loadAuth();
|
|
105
|
+
if (!auth) return "Not logged in. Run `mang login` first.";
|
|
106
|
+
const path = args.bundlePath ?? DEFAULT_BUNDLE;
|
|
107
|
+
const abs = resolve(process.cwd(), path);
|
|
108
|
+
if (!existsSync(abs)) return `\u274C Bundle not found: ${path}. Run \`mang build\` first.`;
|
|
109
|
+
const source = await readFile(abs, "utf8");
|
|
110
|
+
const manifest = asManifest(extractManifestComment(source));
|
|
111
|
+
if (!manifest) return "\u274C Bundle missing a valid manifest comment. Run `mang build`.";
|
|
112
|
+
const report = checkBundle({ source, manifest });
|
|
113
|
+
if (!report.passed) return `\u274C Preflight failed \u2014 fix these first:
|
|
114
|
+
${formatReport(report)}`;
|
|
115
|
+
try {
|
|
116
|
+
await apiFetch("/v1/apps", {
|
|
117
|
+
base: auth.api,
|
|
118
|
+
token: auth.token,
|
|
119
|
+
body: { id: manifest.id, nameVi: manifest.name, icon: manifest.icon }
|
|
120
|
+
});
|
|
121
|
+
} catch (err) {
|
|
122
|
+
if (!(err instanceof ApiError) || err.status !== 409) {
|
|
123
|
+
return `\u274C Could not create app: ${err.message}`;
|
|
124
|
+
}
|
|
125
|
+
const mine = await apiFetch("/v1/apps/mine", {
|
|
126
|
+
base: auth.api,
|
|
127
|
+
token: auth.token
|
|
128
|
+
}).catch(() => ({ apps: [] }));
|
|
129
|
+
if (!mine.apps.some((a) => a.id === manifest.id)) {
|
|
130
|
+
return `\u274C Slug "${manifest.id}" belongs to another creator.`;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
const form = new FormData();
|
|
134
|
+
form.set("bundle", new Blob([source], { type: "text/javascript" }), "app.js");
|
|
135
|
+
form.set("version", manifest.version);
|
|
136
|
+
form.set("manifest", JSON.stringify(manifest));
|
|
137
|
+
const res = await apiFetch(
|
|
138
|
+
`/v1/apps/${manifest.id}/versions`,
|
|
139
|
+
{ base: auth.api, token: auth.token, body: form }
|
|
140
|
+
);
|
|
141
|
+
return `\u{1F680} Published v${manifest.version} (${res.status}). Version: ${res.versionId}. Track with the status tool.`;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// src/index.ts
|
|
145
|
+
var text = (s) => ({ content: [{ type: "text", text: s }] });
|
|
146
|
+
var guard = (fn) => async (a) => {
|
|
147
|
+
try {
|
|
148
|
+
return text(await fn(a));
|
|
149
|
+
} catch (err) {
|
|
150
|
+
return text(`\u274C ${err instanceof Error ? err.message : String(err)}`);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
var server = new McpServer({ name: "mang-moc", version: "0.0.0" });
|
|
154
|
+
server.tool(
|
|
155
|
+
"mang_get_standard",
|
|
156
|
+
"Return the 'chu\u1EA9n M\u0103ng' standard a mini-app must satisfy (contract, manifest, limits, design).",
|
|
157
|
+
guard(() => getStandard())
|
|
158
|
+
);
|
|
159
|
+
server.tool(
|
|
160
|
+
"mang_check",
|
|
161
|
+
"Offline preflight a built mini-app bundle against the exact server gate. Returns fail/warn findings.",
|
|
162
|
+
{
|
|
163
|
+
bundlePath: z.string().optional().describe("Path to the built bundle (default dist/app.js)."),
|
|
164
|
+
source: z.string().optional().describe("Bundle source text (use instead of bundlePath)."),
|
|
165
|
+
appId: z.string().optional().describe("Claimed app id (defaults to the manifest id).")
|
|
166
|
+
},
|
|
167
|
+
guard(runCheck)
|
|
168
|
+
);
|
|
169
|
+
server.tool(
|
|
170
|
+
"mang_scaffold",
|
|
171
|
+
"Create a new standard-compliant mini-app (React + @mangtre/ui, declared flow). Returns files written.",
|
|
172
|
+
{
|
|
173
|
+
slug: z.string().describe("App id / folder slug (lowercase, 3\u201340 chars)."),
|
|
174
|
+
name: z.string().optional().describe("Display name."),
|
|
175
|
+
icon: z.string().optional().describe("Emoji icon."),
|
|
176
|
+
dir: z.string().optional().describe("Target directory (default ./<slug>).")
|
|
177
|
+
},
|
|
178
|
+
guard(runScaffold)
|
|
179
|
+
);
|
|
180
|
+
server.tool(
|
|
181
|
+
"mang_whoami",
|
|
182
|
+
"Show the logged-in creator (reads the token `mang login` stored), or a hint to log in.",
|
|
183
|
+
guard(() => runWhoami())
|
|
184
|
+
);
|
|
185
|
+
server.tool(
|
|
186
|
+
"mang_status",
|
|
187
|
+
"List my published apps + each one's latest review state. Requires `mang login`.",
|
|
188
|
+
guard(() => runStatus())
|
|
189
|
+
);
|
|
190
|
+
server.tool(
|
|
191
|
+
"mang_publish",
|
|
192
|
+
"Preflight + publish a built bundle to M\u0103ng (creates the app on first publish). Requires `mang login`.",
|
|
193
|
+
{ bundlePath: z.string().optional().describe("Path to the built bundle (default dist/app.js).") },
|
|
194
|
+
guard(runPublish)
|
|
195
|
+
);
|
|
196
|
+
await server.connect(new StdioServerTransport());
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mangtre/mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"bin": {
|
|
9
|
+
"mang-mcp": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
16
|
+
"zod": "^3.24.1",
|
|
17
|
+
"@mangtre/cli": "0.1.0"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/node": "^20.17.6",
|
|
21
|
+
"tsup": "^8.3.5",
|
|
22
|
+
"vitest": "^2.1.8"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsup",
|
|
26
|
+
"typecheck": "tsc --noEmit",
|
|
27
|
+
"test": "vitest run"
|
|
28
|
+
}
|
|
29
|
+
}
|