create-mcp-use-app 0.12.3 → 0.13.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/README.md +11 -2
- package/dist/index.js +164 -3
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -40,7 +40,6 @@ Create a new MCP application in seconds:
|
|
|
40
40
|
```bash
|
|
41
41
|
npx create-mcp-use-app my-mcp-server
|
|
42
42
|
cd my-mcp-server
|
|
43
|
-
npm run dev
|
|
44
43
|
```
|
|
45
44
|
|
|
46
45
|
That's it! Your MCP server is running at `http://localhost:3000` with the inspector automatically opened in your browser.
|
|
@@ -96,6 +95,8 @@ You'll be prompted for:
|
|
|
96
95
|
- Project name
|
|
97
96
|
- Project template
|
|
98
97
|
- Package manager preference
|
|
98
|
+
- Install dependencies (Y/n)
|
|
99
|
+
- Skills installation (Claude Code, Cursor, Both, or None)
|
|
99
100
|
|
|
100
101
|
### Direct Mode
|
|
101
102
|
|
|
@@ -122,8 +123,16 @@ npx create-mcp-use-app my-project --npm
|
|
|
122
123
|
npx create-mcp-use-app my-project --yarn
|
|
123
124
|
npx create-mcp-use-app my-project --pnpm
|
|
124
125
|
|
|
125
|
-
# Install deps automatically
|
|
126
|
+
# Install deps automatically (or --no-install to skip and skip prompt)
|
|
126
127
|
npx create-mcp-use-app my-project --install
|
|
128
|
+
npx create-mcp-use-app my-project --no-install
|
|
129
|
+
|
|
130
|
+
# Skills presets for Claude Code / Cursor (omit to prompt)
|
|
131
|
+
npx create-mcp-use-app my-project --skills
|
|
132
|
+
npx create-mcp-use-app my-project --no-skills
|
|
133
|
+
|
|
134
|
+
# List all available templates
|
|
135
|
+
npx create-mcp-use-app --list-templates
|
|
127
136
|
```
|
|
128
137
|
|
|
129
138
|
---
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import TextInput from "ink-text-input";
|
|
|
9
9
|
import { spawn, spawnSync } from "child_process";
|
|
10
10
|
import {
|
|
11
11
|
copyFileSync,
|
|
12
|
+
cpSync,
|
|
12
13
|
existsSync,
|
|
13
14
|
mkdirSync,
|
|
14
15
|
mkdtempSync,
|
|
@@ -19,9 +20,12 @@ import {
|
|
|
19
20
|
} from "fs";
|
|
20
21
|
import { tmpdir } from "os";
|
|
21
22
|
import { dirname, join, resolve } from "path";
|
|
23
|
+
import { Readable } from "stream";
|
|
24
|
+
import { pipeline } from "stream/promises";
|
|
22
25
|
import { fileURLToPath } from "url";
|
|
23
26
|
import ora from "ora";
|
|
24
27
|
import React, { useState } from "react";
|
|
28
|
+
import { extract } from "tar";
|
|
25
29
|
var __filename = fileURLToPath(import.meta.url);
|
|
26
30
|
var __dirname = dirname(__filename);
|
|
27
31
|
function runPackageManager(packageManager, args, cwd) {
|
|
@@ -88,6 +92,81 @@ function getInstallArgs(packageManager) {
|
|
|
88
92
|
return ["install"];
|
|
89
93
|
}
|
|
90
94
|
}
|
|
95
|
+
function sendInstallTelemetryEvent(agents, skills) {
|
|
96
|
+
const TELEMETRY_URL = "https://add-skill.vercel.sh/t";
|
|
97
|
+
const SOURCE_REPO = "mcp-use/mcp-use";
|
|
98
|
+
const telemetryData = {
|
|
99
|
+
event: "install",
|
|
100
|
+
source: SOURCE_REPO,
|
|
101
|
+
skills,
|
|
102
|
+
agents,
|
|
103
|
+
sourceType: "github"
|
|
104
|
+
};
|
|
105
|
+
try {
|
|
106
|
+
const params = new URLSearchParams();
|
|
107
|
+
for (const [key, value] of Object.entries(telemetryData)) {
|
|
108
|
+
if (value !== void 0 && value !== null) {
|
|
109
|
+
params.set(key, String(value));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
fetch(`${TELEMETRY_URL}?${params.toString()}`).catch(() => {
|
|
113
|
+
});
|
|
114
|
+
} catch {
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async function addSkillsToProject(projectPath) {
|
|
118
|
+
const REPO_OWNER = "mcp-use";
|
|
119
|
+
const REPO_NAME = "mcp-use";
|
|
120
|
+
const REPO_COMMIT = "main";
|
|
121
|
+
const tarballUrl = `https://codeload.github.com/${REPO_OWNER}/${REPO_NAME}/tar.gz/${REPO_COMMIT}`;
|
|
122
|
+
const tempDir = mkdtempSync(join(tmpdir(), "mcp-use-skills-"));
|
|
123
|
+
try {
|
|
124
|
+
const response = await fetch(tarballUrl);
|
|
125
|
+
if (!response.ok) {
|
|
126
|
+
throw new Error(`Failed to download tarball: ${response.statusText}`);
|
|
127
|
+
}
|
|
128
|
+
await pipeline(
|
|
129
|
+
Readable.fromWeb(response.body),
|
|
130
|
+
extract({
|
|
131
|
+
cwd: tempDir,
|
|
132
|
+
filter: (path) => path.includes("/skills/"),
|
|
133
|
+
strip: 1
|
|
134
|
+
// Removes 'mcp-use-{commit}/' prefix
|
|
135
|
+
})
|
|
136
|
+
);
|
|
137
|
+
const skillsPath = join(tempDir, "skills");
|
|
138
|
+
if (!existsSync(skillsPath)) {
|
|
139
|
+
throw new Error("Skills folder not found in tarball");
|
|
140
|
+
}
|
|
141
|
+
const presets = ["cursor", "claude-code", "codex"];
|
|
142
|
+
const presetFolders = {
|
|
143
|
+
cursor: ".cursor",
|
|
144
|
+
"claude-code": ".claude",
|
|
145
|
+
codex: ".agent"
|
|
146
|
+
};
|
|
147
|
+
for (const preset of presets) {
|
|
148
|
+
const folderName = presetFolders[preset];
|
|
149
|
+
const outputPath = join(projectPath, folderName, "skills");
|
|
150
|
+
cpSync(skillsPath, outputPath, { recursive: true });
|
|
151
|
+
}
|
|
152
|
+
const skillNames = readdirSync(skillsPath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
153
|
+
sendInstallTelemetryEvent(presets.join(","), skillNames.join(","));
|
|
154
|
+
} catch (error) {
|
|
155
|
+
console.log(
|
|
156
|
+
chalk.yellow(
|
|
157
|
+
"\u26A0\uFE0F Failed to download skills from GitHub. Continuing without skills..."
|
|
158
|
+
)
|
|
159
|
+
);
|
|
160
|
+
console.log(
|
|
161
|
+
chalk.yellow(
|
|
162
|
+
` Error: ${error instanceof Error ? error.message : String(error)}`
|
|
163
|
+
)
|
|
164
|
+
);
|
|
165
|
+
return;
|
|
166
|
+
} finally {
|
|
167
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
168
|
+
}
|
|
169
|
+
}
|
|
91
170
|
var program = new Command();
|
|
92
171
|
function renderLogo() {
|
|
93
172
|
console.log(chalk.cyan("\u259B\u259B\u258C\u259B\u2598\u259B\u258C\u2584\u2596\u258C\u258C\u259B\u2598\u2588\u258C"));
|
|
@@ -237,7 +316,7 @@ function listTemplates() {
|
|
|
237
316
|
program.name("create-mcp-use-app").description("Create a new MCP server project").version(packageJson.version).argument("[project-name]", "Name of the MCP server project").option(
|
|
238
317
|
"-t, --template <template>",
|
|
239
318
|
"Template to use (starter, mcp-ui, mcp-apps, blank) or GitHub repo URL (owner/repo or https://github.com/owner/repo)"
|
|
240
|
-
).option("--list-templates", "List all available templates").option("--install", "Install dependencies after creating project").option("--no-git", "Skip initializing a git repository").option("--dev", "Use workspace dependencies for development").option("--canary", "Use canary versions of packages").option("--yarn", "Use yarn as package manager").option("--npm", "Use npm as package manager").option("--pnpm", "Use pnpm as package manager").action(
|
|
319
|
+
).option("--list-templates", "List all available templates").option("--install", "Install dependencies after creating project").option("--no-install", "Skip installing dependencies").option("--skills", "Install skills for all agents").option("--no-skills", "Skip installing skills").option("--no-git", "Skip initializing a git repository").option("--dev", "Use workspace dependencies for development").option("--canary", "Use canary versions of packages").option("--yarn", "Use yarn as package manager").option("--npm", "Use npm as package manager").option("--pnpm", "Use pnpm as package manager").action(
|
|
241
320
|
async (projectName, options) => {
|
|
242
321
|
try {
|
|
243
322
|
if (options.listTemplates) {
|
|
@@ -325,6 +404,16 @@ program.name("create-mcp-use-app").description("Create a new MCP server project"
|
|
|
325
404
|
);
|
|
326
405
|
updatePackageJson(projectPath, sanitizedProjectName);
|
|
327
406
|
updateIndexTs(projectPath, sanitizedProjectName);
|
|
407
|
+
if (options.template !== void 0) {
|
|
408
|
+
if (options.install === void 0) {
|
|
409
|
+
options.install = false;
|
|
410
|
+
}
|
|
411
|
+
if (options.skills === void 0) {
|
|
412
|
+
options.skills = true;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
console.log("");
|
|
416
|
+
const shouldInstall = options.install !== void 0 ? options.install : await promptForInstall();
|
|
328
417
|
let usedPackageManager = "npm";
|
|
329
418
|
if (options.yarn) {
|
|
330
419
|
usedPackageManager = "yarn";
|
|
@@ -341,7 +430,7 @@ program.name("create-mcp-use-app").description("Create a new MCP server project"
|
|
|
341
430
|
usedPackageManager = defaultOrder[0];
|
|
342
431
|
}
|
|
343
432
|
}
|
|
344
|
-
if (
|
|
433
|
+
if (shouldInstall) {
|
|
345
434
|
console.log("");
|
|
346
435
|
console.log(chalk.cyan("\u{1F4E6} Installing dependencies..."));
|
|
347
436
|
console.log("");
|
|
@@ -442,6 +531,22 @@ program.name("create-mcp-use-app").description("Create a new MCP server project"
|
|
|
442
531
|
}
|
|
443
532
|
}
|
|
444
533
|
console.log("");
|
|
534
|
+
const shouldInstallSkills = options.skills !== void 0 ? options.skills : await promptForSkillsPresets();
|
|
535
|
+
if (shouldInstallSkills) {
|
|
536
|
+
console.log("");
|
|
537
|
+
console.log(chalk.cyan("\u{1F4DA} Installing skills..."));
|
|
538
|
+
try {
|
|
539
|
+
await addSkillsToProject(projectPath);
|
|
540
|
+
console.log(chalk.green("\u2705 Skills installed successfully!"));
|
|
541
|
+
} catch (err) {
|
|
542
|
+
console.log(
|
|
543
|
+
chalk.yellow(
|
|
544
|
+
"\u26A0\uFE0F Skills install failed. Run `npx skills add mcp-use/mcp-use` manually in root directory."
|
|
545
|
+
)
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
console.log("");
|
|
445
550
|
console.log(chalk.green("\u2705 MCP server created successfully!"));
|
|
446
551
|
if (options.dev) {
|
|
447
552
|
console.log(
|
|
@@ -477,7 +582,7 @@ program.name("create-mcp-use-app").description("Create a new MCP server project"
|
|
|
477
582
|
console.log("");
|
|
478
583
|
console.log(chalk.bold("\u{1F680} To get started:"));
|
|
479
584
|
console.log(chalk.cyan(` cd ${sanitizedProjectName}`));
|
|
480
|
-
if (!
|
|
585
|
+
if (!shouldInstall) {
|
|
481
586
|
console.log(
|
|
482
587
|
chalk.cyan(` ${getInstallCommand(usedPackageManager)}`)
|
|
483
588
|
);
|
|
@@ -767,6 +872,62 @@ function updateIndexTs(projectPath, projectName) {
|
|
|
767
872
|
content = content.replace(/\{\{PROJECT_NAME\}\}/g, projectName);
|
|
768
873
|
writeFileSync(indexPath, content);
|
|
769
874
|
}
|
|
875
|
+
function InstallPrompt({ onSubmit }) {
|
|
876
|
+
const [value, setValue] = useState("");
|
|
877
|
+
const handleSubmit = (val) => {
|
|
878
|
+
const trimmed = val.trim().toLowerCase();
|
|
879
|
+
if (trimmed === "" || trimmed === "y" || trimmed === "yes") {
|
|
880
|
+
onSubmit(true);
|
|
881
|
+
} else if (trimmed === "n" || trimmed === "no") {
|
|
882
|
+
onSubmit(false);
|
|
883
|
+
}
|
|
884
|
+
};
|
|
885
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true }, "Install dependencies now? (Y/n)")), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: "cyan" }, "\u276F "), /* @__PURE__ */ React.createElement(TextInput, { value, onChange: setValue, onSubmit: handleSubmit })));
|
|
886
|
+
}
|
|
887
|
+
async function promptForInstall() {
|
|
888
|
+
return new Promise((resolve2) => {
|
|
889
|
+
const { unmount } = render(
|
|
890
|
+
/* @__PURE__ */ React.createElement(
|
|
891
|
+
InstallPrompt,
|
|
892
|
+
{
|
|
893
|
+
onSubmit: (install) => {
|
|
894
|
+
unmount();
|
|
895
|
+
resolve2(install);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
)
|
|
899
|
+
);
|
|
900
|
+
});
|
|
901
|
+
}
|
|
902
|
+
function SkillsPresetPrompt({
|
|
903
|
+
onSubmit
|
|
904
|
+
}) {
|
|
905
|
+
const [value, setValue] = useState("");
|
|
906
|
+
const handleSubmit = (val) => {
|
|
907
|
+
const trimmed = val.trim().toLowerCase();
|
|
908
|
+
if (trimmed === "" || trimmed === "y" || trimmed === "yes") {
|
|
909
|
+
onSubmit(true);
|
|
910
|
+
} else if (trimmed === "n" || trimmed === "no") {
|
|
911
|
+
onSubmit(false);
|
|
912
|
+
}
|
|
913
|
+
};
|
|
914
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true }, "Install skills (Recommended)? (Y/n)")), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: "cyan" }, "\u276F "), /* @__PURE__ */ React.createElement(TextInput, { value, onChange: setValue, onSubmit: handleSubmit })));
|
|
915
|
+
}
|
|
916
|
+
async function promptForSkillsPresets() {
|
|
917
|
+
return new Promise((resolve2) => {
|
|
918
|
+
const { unmount } = render(
|
|
919
|
+
/* @__PURE__ */ React.createElement(
|
|
920
|
+
SkillsPresetPrompt,
|
|
921
|
+
{
|
|
922
|
+
onSubmit: (presets) => {
|
|
923
|
+
unmount();
|
|
924
|
+
resolve2(presets);
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
)
|
|
928
|
+
);
|
|
929
|
+
});
|
|
930
|
+
}
|
|
770
931
|
function ProjectNameInput({ onSubmit }) {
|
|
771
932
|
const [value, setValue] = useState("");
|
|
772
933
|
const [error, setError] = useState("");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-mcp-use-app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Create MCP-Use apps with one command",
|
|
6
6
|
"author": "mcp-use, Inc.",
|
|
@@ -43,10 +43,12 @@
|
|
|
43
43
|
"ink-select-input": "^6.2.0",
|
|
44
44
|
"ink-text-input": "^6.0.0",
|
|
45
45
|
"ora": "^9.0.0",
|
|
46
|
-
"react": "^19.2.3"
|
|
46
|
+
"react": "^19.2.3",
|
|
47
|
+
"tar": "^7.4.3"
|
|
47
48
|
},
|
|
48
49
|
"devDependencies": {
|
|
49
50
|
"@types/fs-extra": "^11.0.4",
|
|
51
|
+
"@types/tar": "^6.1.13",
|
|
50
52
|
"vitest": "^4.0.17"
|
|
51
53
|
},
|
|
52
54
|
"publishConfig": {
|