@yassinello/create-mymcp 0.2.0 → 0.3.1
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/index.mjs +188 -404
- package/package.json +29 -29
package/index.mjs
CHANGED
|
@@ -1,404 +1,188 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// create-mymcp — Interactive installer for MyMCP
|
|
4
|
-
// Usage: npx @yassinello/create-mymcp@latest
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
import { createInterface } from "node:readline";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
],
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
);
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
if (existsSync(projectDir) && isDirNonEmpty(projectDir)) {
|
|
190
|
-
log(` ${RED}✗${RESET} Directory "${projectDir}" already exists and is not empty.`);
|
|
191
|
-
rl.close();
|
|
192
|
-
process.exit(1);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
info(`Will create: ${projectDir}`);
|
|
196
|
-
|
|
197
|
-
// ── Step 2: Clone ────────────────────────────────────────────────
|
|
198
|
-
|
|
199
|
-
step("2/5", "Cloning MyMCP");
|
|
200
|
-
|
|
201
|
-
if (!hasCommand("git")) {
|
|
202
|
-
log(` ${RED}✗${RESET} git is required. Install it from https://git-scm.com`);
|
|
203
|
-
rl.close();
|
|
204
|
-
process.exit(1);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
const cloneResult = spawnSync(
|
|
208
|
-
"git",
|
|
209
|
-
["clone", "https://github.com/Yassinello/mymcp.git", projectDir],
|
|
210
|
-
{ stdio: "inherit" }
|
|
211
|
-
);
|
|
212
|
-
|
|
213
|
-
if (cloneResult.status !== 0) {
|
|
214
|
-
log(` ${RED}✗${RESET} Failed to clone repository.`);
|
|
215
|
-
rl.close();
|
|
216
|
-
process.exit(1);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// Set up upstream remote for easy updates
|
|
220
|
-
run(`git -C "${projectDir}" remote rename origin upstream`);
|
|
221
|
-
ok("Cloned and upstream remote configured");
|
|
222
|
-
info("Run `npm run update` to pull updates anytime");
|
|
223
|
-
|
|
224
|
-
// ── Step 3: Pick packs ───────────────────────────────────────────
|
|
225
|
-
|
|
226
|
-
step("3/5", "Choose your tool packs");
|
|
227
|
-
log("");
|
|
228
|
-
|
|
229
|
-
const selectedPacks = [];
|
|
230
|
-
for (const pack of PACKS) {
|
|
231
|
-
const defaultOn = pack.id === "vault" || pack.id === "google";
|
|
232
|
-
const yes = await confirm(
|
|
233
|
-
`${BOLD}${pack.name}${RESET} — ${pack.tools}?`,
|
|
234
|
-
defaultOn
|
|
235
|
-
);
|
|
236
|
-
if (yes) selectedPacks.push(pack);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
if (selectedPacks.length === 0) {
|
|
240
|
-
warn("No packs selected. You can add them later in your .env file.");
|
|
241
|
-
} else {
|
|
242
|
-
ok(`Selected: ${selectedPacks.map((p) => p.name).join(", ")}`);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// ── Step 4: Collect credentials ──────────────────────────────────
|
|
246
|
-
|
|
247
|
-
step("4/5", "Configure credentials");
|
|
248
|
-
|
|
249
|
-
const envVars = {};
|
|
250
|
-
|
|
251
|
-
// Generate MCP auth token
|
|
252
|
-
envVars.MCP_AUTH_TOKEN = randomBytes(32).toString("hex");
|
|
253
|
-
ok(`MCP_AUTH_TOKEN generated: ${envVars.MCP_AUTH_TOKEN.slice(0, 8)}...`);
|
|
254
|
-
|
|
255
|
-
// Instance settings
|
|
256
|
-
log("");
|
|
257
|
-
const tz = (await ask(` Timezone [UTC]: `)).trim() || "UTC";
|
|
258
|
-
const locale = (await ask(` Locale [en-US]: `)).trim() || "en-US";
|
|
259
|
-
const displayName = (await ask(` Display name [User]: `)).trim() || "User";
|
|
260
|
-
envVars.MYMCP_TIMEZONE = tz;
|
|
261
|
-
envVars.MYMCP_LOCALE = locale;
|
|
262
|
-
envVars.MYMCP_DISPLAY_NAME = displayName;
|
|
263
|
-
|
|
264
|
-
// Pack credentials
|
|
265
|
-
for (const pack of selectedPacks) {
|
|
266
|
-
log("");
|
|
267
|
-
log(` ${BOLD}${pack.name}${RESET}`);
|
|
268
|
-
for (const v of pack.vars) {
|
|
269
|
-
if (v.help) info(v.help);
|
|
270
|
-
if (v.optional) {
|
|
271
|
-
info("(optional — press Enter to skip)");
|
|
272
|
-
}
|
|
273
|
-
const value = (await ask(` ${v.prompt}: `)).trim();
|
|
274
|
-
if (value) {
|
|
275
|
-
envVars[v.key] = value;
|
|
276
|
-
ok(`${v.key} set`);
|
|
277
|
-
} else if (!v.optional) {
|
|
278
|
-
warn(`${v.key} skipped — ${pack.name} pack won't activate until set`);
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// ── Write .env ───────────────────────────────────────────────────
|
|
284
|
-
|
|
285
|
-
const envPath = join(projectDir, ".env");
|
|
286
|
-
const envExamplePath = join(projectDir, ".env.example");
|
|
287
|
-
|
|
288
|
-
// Read .env.example as base, then overlay collected values
|
|
289
|
-
let envContent = "# MyMCP — Generated by create-mymcp\n";
|
|
290
|
-
envContent += `# Created: ${new Date().toISOString().split("T")[0]}\n\n`;
|
|
291
|
-
|
|
292
|
-
// Track which vars we've written so we don't duplicate
|
|
293
|
-
const writtenVars = new Set();
|
|
294
|
-
|
|
295
|
-
if (existsSync(envExamplePath)) {
|
|
296
|
-
const example = readFileSync(envExamplePath, "utf-8");
|
|
297
|
-
const lines = example.split("\n");
|
|
298
|
-
for (const line of lines) {
|
|
299
|
-
const match = line.match(/^([A-Z_][A-Z0-9_]*)=(.*)$/);
|
|
300
|
-
if (match && envVars[match[1]] !== undefined) {
|
|
301
|
-
envContent += `${match[1]}=${envVars[match[1]]}\n`;
|
|
302
|
-
writtenVars.add(match[1]);
|
|
303
|
-
} else {
|
|
304
|
-
envContent += line + "\n";
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// Append any remaining vars not in .env.example
|
|
310
|
-
for (const [key, value] of Object.entries(envVars)) {
|
|
311
|
-
if (!writtenVars.has(key)) {
|
|
312
|
-
envContent += `${key}=${value}\n`;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
writeFileSync(envPath, envContent);
|
|
317
|
-
ok(".env file created");
|
|
318
|
-
|
|
319
|
-
// ── Step 5: Install & Deploy ─────────────────────────────────────
|
|
320
|
-
|
|
321
|
-
step("5/5", "Install & deploy");
|
|
322
|
-
|
|
323
|
-
// Install dependencies
|
|
324
|
-
log("");
|
|
325
|
-
info("Installing dependencies...");
|
|
326
|
-
const installResult = spawnSync("npm", ["install"], {
|
|
327
|
-
cwd: projectDir,
|
|
328
|
-
stdio: "inherit",
|
|
329
|
-
shell: true,
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
if (installResult.status !== 0) {
|
|
333
|
-
warn("npm install failed — you can run it manually later");
|
|
334
|
-
} else {
|
|
335
|
-
ok("Dependencies installed");
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// Offer Vercel deploy
|
|
339
|
-
log("");
|
|
340
|
-
const deployVercel = await confirm(
|
|
341
|
-
"Deploy to Vercel now? (requires Vercel CLI)",
|
|
342
|
-
false
|
|
343
|
-
);
|
|
344
|
-
|
|
345
|
-
if (deployVercel) {
|
|
346
|
-
if (!hasCommand("vercel")) {
|
|
347
|
-
info("Installing Vercel CLI...");
|
|
348
|
-
spawnSync("npm", ["install", "-g", "vercel"], {
|
|
349
|
-
stdio: "inherit",
|
|
350
|
-
shell: true,
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
log("");
|
|
355
|
-
info("Running vercel deploy...");
|
|
356
|
-
const vercelResult = spawnSync("vercel", ["--yes"], {
|
|
357
|
-
cwd: projectDir,
|
|
358
|
-
stdio: "inherit",
|
|
359
|
-
shell: true,
|
|
360
|
-
});
|
|
361
|
-
|
|
362
|
-
if (vercelResult.status === 0) {
|
|
363
|
-
ok("Deployed to Vercel!");
|
|
364
|
-
log("");
|
|
365
|
-
warn("Don't forget to add your env vars in the Vercel dashboard:");
|
|
366
|
-
info("Vercel → Project Settings → Environment Variables");
|
|
367
|
-
info("Or run: vercel env add MCP_AUTH_TOKEN");
|
|
368
|
-
} else {
|
|
369
|
-
warn("Deploy failed — you can run `vercel` manually in your project dir");
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
// ── Done ─────────────────────────────────────────────────────────
|
|
374
|
-
|
|
375
|
-
log("");
|
|
376
|
-
log(`${BOLD} ╔══════════════════════════════════════════╗${RESET}`);
|
|
377
|
-
log(`${BOLD} ║ ${GREEN}Setup complete!${RESET}${BOLD} ║${RESET}`);
|
|
378
|
-
log(`${BOLD} ╚══════════════════════════════════════════╝${RESET}`);
|
|
379
|
-
log("");
|
|
380
|
-
log(` ${BOLD}Next steps:${RESET}`);
|
|
381
|
-
log("");
|
|
382
|
-
log(` ${CYAN}cd ${projectName}${RESET}`);
|
|
383
|
-
if (!deployVercel) {
|
|
384
|
-
log(` ${CYAN}npm run dev${RESET} ${DIM}# Start locally${RESET}`);
|
|
385
|
-
log(` ${CYAN}vercel${RESET} ${DIM}# Deploy to Vercel${RESET}`);
|
|
386
|
-
}
|
|
387
|
-
log(` ${CYAN}open /setup${RESET} ${DIM}# Guided setup page${RESET}`);
|
|
388
|
-
log("");
|
|
389
|
-
log(` ${BOLD}Connect to Claude Desktop / Claude Code:${RESET}`);
|
|
390
|
-
log(` ${DIM}Endpoint: https://your-app.vercel.app/api/mcp${RESET}`);
|
|
391
|
-
log(` ${DIM}Token: starts with ${envVars.MCP_AUTH_TOKEN ? envVars.MCP_AUTH_TOKEN.slice(0, 8) + "..." : "(check your .env)"}${RESET}`);
|
|
392
|
-
log("");
|
|
393
|
-
log(` ${BOLD}Stay up to date:${RESET}`);
|
|
394
|
-
log(` ${CYAN}npm run update${RESET}`);
|
|
395
|
-
log("");
|
|
396
|
-
|
|
397
|
-
rl.close();
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
main().catch((err) => {
|
|
401
|
-
console.error(`\n${RED}Error:${RESET} ${err.message}`);
|
|
402
|
-
rl.close();
|
|
403
|
-
process.exit(1);
|
|
404
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// create-mymcp — Interactive installer for MyMCP
|
|
4
|
+
// Usage: npx @yassinello/create-mymcp@latest
|
|
5
|
+
|
|
6
|
+
import { spawnSync, spawn } from "node:child_process";
|
|
7
|
+
import { createInterface } from "node:readline";
|
|
8
|
+
import { existsSync, readdirSync } from "node:fs";
|
|
9
|
+
import { resolve, isAbsolute } from "node:path";
|
|
10
|
+
|
|
11
|
+
// ── Helpers ──────────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
14
|
+
const ask = (q) => new Promise((r) => rl.question(q, r));
|
|
15
|
+
|
|
16
|
+
const BOLD = "\x1b[1m";
|
|
17
|
+
const DIM = "\x1b[2m";
|
|
18
|
+
const GREEN = "\x1b[32m";
|
|
19
|
+
const CYAN = "\x1b[36m";
|
|
20
|
+
const YELLOW = "\x1b[33m";
|
|
21
|
+
const RED = "\x1b[31m";
|
|
22
|
+
const RESET = "\x1b[0m";
|
|
23
|
+
|
|
24
|
+
const log = (msg) => console.log(msg);
|
|
25
|
+
const step = (n, msg) => log(`\n${CYAN}[${n}]${RESET} ${BOLD}${msg}${RESET}`);
|
|
26
|
+
const ok = (msg) => log(` ${GREEN}✓${RESET} ${msg}`);
|
|
27
|
+
const warn = (msg) => log(` ${YELLOW}!${RESET} ${msg}`);
|
|
28
|
+
const info = (msg) => log(` ${DIM}${msg}${RESET}`);
|
|
29
|
+
|
|
30
|
+
function openBrowserUrl(url) {
|
|
31
|
+
const cmd =
|
|
32
|
+
process.platform === "win32"
|
|
33
|
+
? "start"
|
|
34
|
+
: process.platform === "darwin"
|
|
35
|
+
? "open"
|
|
36
|
+
: "xdg-open";
|
|
37
|
+
spawnSync(cmd, [url], { shell: true, stdio: "ignore" });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function cleanPath(input) {
|
|
41
|
+
return input.trim().replace(/^["']|["']$/g, "");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function isDirNonEmpty(dir) {
|
|
45
|
+
try {
|
|
46
|
+
return readdirSync(dir).length > 0;
|
|
47
|
+
} catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
// ── Main ─────────────────────────────────────────────────────────────
|
|
54
|
+
|
|
55
|
+
async function main() {
|
|
56
|
+
log("");
|
|
57
|
+
log(`${BOLD} ╔══════════════════════════════════════════╗${RESET}`);
|
|
58
|
+
log(`${BOLD} ║ ${CYAN}create-mymcp${RESET}${BOLD} ║${RESET}`);
|
|
59
|
+
log(`${BOLD} ║ Your personal AI backend in minutes ║${RESET}`);
|
|
60
|
+
log(`${BOLD} ╚══════════════════════════════════════════╝${RESET}`);
|
|
61
|
+
|
|
62
|
+
// ── Step 1: Project directory ────────────────────────────────────
|
|
63
|
+
|
|
64
|
+
step("1/3", "Project setup");
|
|
65
|
+
info("Just type a folder name, or a full path.");
|
|
66
|
+
|
|
67
|
+
const rawInput = (await ask(` Project directory [mymcp]: `)).trim();
|
|
68
|
+
const cleaned = cleanPath(rawInput) || "mymcp";
|
|
69
|
+
const projectDir = isAbsolute(cleaned) ? cleaned : resolve(cleaned);
|
|
70
|
+
const projectName = projectDir.split(/[/\\]/).pop();
|
|
71
|
+
|
|
72
|
+
if (existsSync(projectDir) && isDirNonEmpty(projectDir)) {
|
|
73
|
+
log(` ${RED}✗${RESET} Directory "${projectDir}" already exists and is not empty.`);
|
|
74
|
+
rl.close();
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
info(`Will create: ${projectDir}`);
|
|
79
|
+
|
|
80
|
+
// ── Step 2: Clone ────────────────────────────────────────────────
|
|
81
|
+
|
|
82
|
+
step("2/3", "Cloning MyMCP");
|
|
83
|
+
|
|
84
|
+
const cloneResult = spawnSync(
|
|
85
|
+
"git",
|
|
86
|
+
["clone", "https://github.com/Yassinello/mymcp.git", projectDir],
|
|
87
|
+
{ stdio: "inherit" }
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
if (cloneResult.status !== 0) {
|
|
91
|
+
log(` ${RED}✗${RESET} Clone failed. Is git installed?`);
|
|
92
|
+
rl.close();
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Set up upstream for updates
|
|
97
|
+
spawnSync("git", ["-C", projectDir, "remote", "rename", "origin", "upstream"], {
|
|
98
|
+
stdio: "pipe",
|
|
99
|
+
});
|
|
100
|
+
ok("Cloned and upstream remote configured");
|
|
101
|
+
|
|
102
|
+
// ── Step 3: Install + Launch Setup Wizard ────────────────────────
|
|
103
|
+
|
|
104
|
+
step("3/3", "Installing & launching setup wizard");
|
|
105
|
+
|
|
106
|
+
log("");
|
|
107
|
+
info("Installing dependencies (this takes ~1 minute)...");
|
|
108
|
+
const installResult = spawnSync("npm", ["install"], {
|
|
109
|
+
cwd: projectDir,
|
|
110
|
+
stdio: "inherit",
|
|
111
|
+
shell: true,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
if (installResult.status !== 0) {
|
|
115
|
+
warn("npm install failed — try running it manually:");
|
|
116
|
+
log(` ${CYAN}cd ${projectName} && npm install${RESET}`);
|
|
117
|
+
rl.close();
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
ok("Dependencies installed");
|
|
121
|
+
|
|
122
|
+
// Start dev server in background
|
|
123
|
+
log("");
|
|
124
|
+
info("Starting dev server...");
|
|
125
|
+
|
|
126
|
+
const devServer = spawn("npm", ["run", "dev"], {
|
|
127
|
+
cwd: projectDir,
|
|
128
|
+
shell: true,
|
|
129
|
+
stdio: "pipe",
|
|
130
|
+
detached: true,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Wait for the server to be ready
|
|
134
|
+
let serverReady = false;
|
|
135
|
+
const startTime = Date.now();
|
|
136
|
+
|
|
137
|
+
while (!serverReady && Date.now() - startTime < 30000) {
|
|
138
|
+
try {
|
|
139
|
+
const res = await fetch("http://localhost:3000/api/health");
|
|
140
|
+
if (res.ok) serverReady = true;
|
|
141
|
+
} catch {
|
|
142
|
+
// Not ready yet
|
|
143
|
+
}
|
|
144
|
+
if (!serverReady) await new Promise((r) => setTimeout(r, 1000));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (serverReady) {
|
|
148
|
+
ok("Dev server running at http://localhost:3000");
|
|
149
|
+
|
|
150
|
+
// Open setup wizard in browser
|
|
151
|
+
log("");
|
|
152
|
+
info("Opening setup wizard in your browser...");
|
|
153
|
+
openBrowserUrl("http://localhost:3000/setup");
|
|
154
|
+
|
|
155
|
+
log("");
|
|
156
|
+
log(`${BOLD} ╔══════════════════════════════════════════╗${RESET}`);
|
|
157
|
+
log(`${BOLD} ║ ${GREEN}Complete the setup in your browser${RESET}${BOLD} ║${RESET}`);
|
|
158
|
+
log(`${BOLD} ╚══════════════════════════════════════════╝${RESET}`);
|
|
159
|
+
log("");
|
|
160
|
+
log(` ${BOLD}Setup wizard:${RESET} ${CYAN}http://localhost:3000/setup${RESET}`);
|
|
161
|
+
log("");
|
|
162
|
+
log(` ${DIM}The wizard will help you:${RESET}`);
|
|
163
|
+
log(` ${DIM} 1. Choose your tool packs${RESET}`);
|
|
164
|
+
log(` ${DIM} 2. Enter credentials (with live testing)${RESET}`);
|
|
165
|
+
log(` ${DIM} 3. Configure your instance${RESET}`);
|
|
166
|
+
log(` ${DIM} 4. Save your .env file${RESET}`);
|
|
167
|
+
log("");
|
|
168
|
+
log(` ${DIM}Press Ctrl+C to stop the dev server when done.${RESET}`);
|
|
169
|
+
log(` ${DIM}Run ${CYAN}npm run update${RESET}${DIM} anytime to pull updates.${RESET}`);
|
|
170
|
+
log("");
|
|
171
|
+
|
|
172
|
+
// Keep process alive while server runs
|
|
173
|
+
devServer.unref();
|
|
174
|
+
} else {
|
|
175
|
+
warn("Server didn't start in time. Start it manually:");
|
|
176
|
+
log(` ${CYAN}cd ${projectName} && npm run dev${RESET}`);
|
|
177
|
+
log(` Then open: ${CYAN}http://localhost:3000/setup${RESET}`);
|
|
178
|
+
devServer.kill();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
rl.close();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
main().catch((err) => {
|
|
185
|
+
console.error(`\n${RED}Error:${RESET} ${err.message}`);
|
|
186
|
+
rl.close();
|
|
187
|
+
process.exit(1);
|
|
188
|
+
});
|
package/package.json
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@yassinello/create-mymcp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Set up your personal MCP server in minutes — interactive installer for MyMCP",
|
|
5
|
-
"bin": {
|
|
6
|
-
"create-mymcp": "./index.mjs"
|
|
7
|
-
},
|
|
8
|
-
"keywords": [
|
|
9
|
-
"mcp",
|
|
10
|
-
"create",
|
|
11
|
-
"installer",
|
|
12
|
-
"claude",
|
|
13
|
-
"chatgpt",
|
|
14
|
-
"ai",
|
|
15
|
-
"model-context-protocol"
|
|
16
|
-
],
|
|
17
|
-
"repository": {
|
|
18
|
-
"type": "git",
|
|
19
|
-
"url": "https://github.com/Yassinello/mymcp",
|
|
20
|
-
"directory": "create-mymcp"
|
|
21
|
-
},
|
|
22
|
-
"license": "MIT",
|
|
23
|
-
"engines": {
|
|
24
|
-
"node": ">=18"
|
|
25
|
-
},
|
|
26
|
-
"files": [
|
|
27
|
-
"index.mjs"
|
|
28
|
-
]
|
|
29
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@yassinello/create-mymcp",
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"description": "Set up your personal MCP server in minutes — interactive installer for MyMCP",
|
|
5
|
+
"bin": {
|
|
6
|
+
"create-mymcp": "./index.mjs"
|
|
7
|
+
},
|
|
8
|
+
"keywords": [
|
|
9
|
+
"mcp",
|
|
10
|
+
"create",
|
|
11
|
+
"installer",
|
|
12
|
+
"claude",
|
|
13
|
+
"chatgpt",
|
|
14
|
+
"ai",
|
|
15
|
+
"model-context-protocol"
|
|
16
|
+
],
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/Yassinello/mymcp",
|
|
20
|
+
"directory": "create-mymcp"
|
|
21
|
+
},
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=18"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"index.mjs"
|
|
28
|
+
]
|
|
29
|
+
}
|