@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.
Files changed (2) hide show
  1. package/index.mjs +188 -404
  2. 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 { execSync, spawnSync } from "node:child_process";
7
- import { createInterface } from "node:readline";
8
- import { randomBytes } from "node:crypto";
9
- import { existsSync, writeFileSync, readFileSync, readdirSync } from "node:fs";
10
- import { join, resolve, isAbsolute } from "node:path";
11
-
12
- // ── Helpers ──────────────────────────────────────────────────────────
13
-
14
- const rl = createInterface({ input: process.stdin, output: process.stdout });
15
- const ask = (q) => new Promise((r) => rl.question(q, r));
16
-
17
- const BOLD = "\x1b[1m";
18
- const DIM = "\x1b[2m";
19
- const GREEN = "\x1b[32m";
20
- const CYAN = "\x1b[36m";
21
- const YELLOW = "\x1b[33m";
22
- const RED = "\x1b[31m";
23
- const RESET = "\x1b[0m";
24
-
25
- const log = (msg) => console.log(msg);
26
- const step = (n, msg) => log(`\n${CYAN}[${n}]${RESET} ${BOLD}${msg}${RESET}`);
27
- const ok = (msg) => log(` ${GREEN}✓${RESET} ${msg}`);
28
- const warn = (msg) => log(` ${YELLOW}!${RESET} ${msg}`);
29
- const info = (msg) => log(` ${DIM}${msg}${RESET}`);
30
-
31
- function run(cmd, opts = {}) {
32
- try {
33
- return execSync(cmd, { encoding: "utf-8", stdio: "pipe", ...opts }).trim();
34
- } catch {
35
- return null;
36
- }
37
- }
38
-
39
- function hasCommand(cmd) {
40
- const check = process.platform === "win32" ? `where ${cmd}` : `which ${cmd}`;
41
- return run(check) !== null;
42
- }
43
-
44
- async function confirm(msg, defaultYes = true) {
45
- const hint = defaultYes ? "Y/n" : "y/N";
46
- const answer = (await ask(` ${msg} [${hint}] `)).trim().toLowerCase();
47
- if (answer === "") return defaultYes;
48
- return answer === "y" || answer === "yes";
49
- }
50
-
51
- /** Clean user input: strip surrounding quotes, trim whitespace */
52
- function cleanPath(input) {
53
- return input.trim().replace(/^["']|["']$/g, "");
54
- }
55
-
56
- /** Check if a directory exists and is non-empty */
57
- function isDirNonEmpty(dir) {
58
- try {
59
- const entries = readdirSync(dir);
60
- return entries.length > 0;
61
- } catch {
62
- return false;
63
- }
64
- }
65
-
66
- // ── Pack definitions ─────────────────────────────────────────────────
67
-
68
- const PACKS = [
69
- {
70
- id: "google",
71
- name: "Google Workspace",
72
- tools: "Gmail, Calendar, Contacts, Drive (18 tools)",
73
- vars: [
74
- {
75
- key: "GOOGLE_CLIENT_ID",
76
- prompt: "Google OAuth Client ID",
77
- help: "https://console.cloud.google.com/apis/credentials",
78
- },
79
- { key: "GOOGLE_CLIENT_SECRET", prompt: "Google OAuth Client Secret" },
80
- {
81
- key: "GOOGLE_REFRESH_TOKEN",
82
- prompt: "Google OAuth Refresh Token",
83
- help: "Run the OAuth flow after deploy at /api/auth/google",
84
- optional: true,
85
- },
86
- ],
87
- },
88
- {
89
- id: "vault",
90
- name: "Obsidian Vault",
91
- tools: "Read, write, search, backlinks, web clipper (15 tools)",
92
- vars: [
93
- {
94
- key: "GITHUB_PAT",
95
- prompt: "GitHub PAT (with repo scope)",
96
- help: "https://github.com/settings/tokens",
97
- },
98
- {
99
- key: "GITHUB_REPO",
100
- prompt: "GitHub repo (owner/repo format)",
101
- },
102
- ],
103
- },
104
- {
105
- id: "browser",
106
- name: "Browser Automation",
107
- tools: "Web browse, extract, act, LinkedIn feed (4 tools)",
108
- vars: [
109
- {
110
- key: "BROWSERBASE_API_KEY",
111
- prompt: "Browserbase API key",
112
- help: "https://browserbase.com",
113
- },
114
- { key: "BROWSERBASE_PROJECT_ID", prompt: "Browserbase Project ID" },
115
- {
116
- key: "OPENROUTER_API_KEY",
117
- prompt: "OpenRouter API key",
118
- help: "https://openrouter.ai/keys",
119
- },
120
- ],
121
- },
122
- {
123
- id: "slack",
124
- name: "Slack",
125
- tools: "Channels, messages, threads, profiles, search (6 tools)",
126
- vars: [
127
- {
128
- key: "SLACK_BOT_TOKEN",
129
- prompt: "Slack Bot User OAuth Token",
130
- help: "https://api.slack.com/apps → OAuth & Permissions",
131
- },
132
- ],
133
- },
134
- {
135
- id: "notion",
136
- name: "Notion",
137
- tools: "Search, read, create, update, query databases (5 tools)",
138
- vars: [
139
- {
140
- key: "NOTION_API_KEY",
141
- prompt: "Notion Internal Integration Token",
142
- help: "https://www.notion.so/my-integrations",
143
- },
144
- ],
145
- },
146
- {
147
- id: "composio",
148
- name: "Composio",
149
- tools: "1000+ app integrations — Jira, HubSpot, Salesforce, Airtable... (2 tools)",
150
- vars: [
151
- {
152
- key: "COMPOSIO_API_KEY",
153
- prompt: "Composio API key",
154
- help: "https://composio.dev → Settings",
155
- },
156
- ],
157
- },
158
- ];
159
-
160
- // ── Main ─────────────────────────────────────────────────────────────
161
-
162
- async function main() {
163
- log("");
164
- log(
165
- `${BOLD} ╔══════════════════════════════════════════╗${RESET}`
166
- );
167
- log(
168
- `${BOLD} ${CYAN}create-mymcp${RESET}${BOLD} ║${RESET}`
169
- );
170
- log(
171
- `${BOLD} ║ Your personal AI backend in minutes ║${RESET}`
172
- );
173
- log(
174
- `${BOLD} ╚══════════════════════════════════════════╝${RESET}`
175
- );
176
-
177
- // ── Step 1: Project directory ────────────────────────────────────
178
-
179
- step("1/5", "Project setup");
180
-
181
- const defaultDir = "mymcp";
182
- const rawInput = (await ask(` Project directory [${defaultDir}]: `)).trim();
183
- const cleaned = cleanPath(rawInput) || defaultDir;
184
-
185
- // If it's already absolute, use as-is; otherwise resolve relative to CWD
186
- const projectDir = isAbsolute(cleaned) ? cleaned : resolve(cleaned);
187
- const projectName = projectDir.split(/[/\\]/).pop();
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.2.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
+ }