create-mcp-i-app
Version:
Bootstrap MCP applications with identity features (temporary - use create-mcpi-app after Oct 7)
322 lines • 13.1 kB
JavaScript
import path from "path";
import fs from "fs-extra";
import chalk from "chalk";
import { Command } from "commander";
import inquirer from "inquirer";
import ora from "ora";
import { fileURLToPath } from "url";
import { checkNodeVersion } from "./utils/check-node.js";
import { createProject } from "./helpers/create.js";
import { createKYAOSBanner } from "./effects/index.js";
import { validateProjectName, validateDirectoryAvailability, } from "./utils/validate-project-name.js";
checkNodeVersion();
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, "../package.json"), "utf8"));
const program = new Command()
.name("create-mcpi-app")
.description("Create a new xmcp application with identity features built-in")
.version(packageJson.version, "-v, --version", "Output the current version of create-mcpi-app.")
.argument("[directory]")
.usage("[directory] [options]")
.helpOption("-h, --help", "Display help message.")
.option("-y, --yes", "Skip confirmation prompt", false)
.option("--use-npm", "Use npm as package manager (default: use npm)")
.option("--use-yarn", "Use yarn as package manager")
.option("--use-pnpm", "Use pnpm as package manager")
.option("--skip-install", "Skip installing dependencies", false)
.option("--skip-identity", "Skip identity generation", false)
.option("--no-identity", "Create plain XMCP project without identity features")
.option("--vercel", "Add Vercel support for deployment", false)
.option("--http", "Enable HTTP transport", false)
.option("--stdio", "Enable STDIO transport", false)
.option("--local", "Use local xmcp-i dependency", false)
.option("--xmcp-version <version>", "Specify XMCP version (e.g., 0.3.1)")
.option("--xmcp-channel <channel>", "Use dist-tag (latest|next)", "latest")
.option("--no-animation", "Skip the black hole animation", false)
.option("--fast", "Use shorter animation duration", false)
.action(async (projectDir, options) => {
console.log(chalk.bold(`\ncreate-mcpi-app@${packageJson.version}`));
// Show KYA-OS banner
const banner = await createKYAOSBanner();
console.log(chalk.cyan(banner));
console.log(chalk.dim("\nEnhanced with identity features by MCP-I\n"));
// If project directory wasn't specified, ask for it
if (!projectDir) {
const answers = await inquirer.prompt([
{
type: "input",
name: "projectDir",
message: "What is your project named?",
default: "my-mcpi-app",
},
]);
projectDir = answers.projectDir;
}
// Normalize project directory
const resolvedProjectPath = path.resolve(process.cwd(), projectDir);
const projectName = path.basename(resolvedProjectPath);
// Validate project name
const nameValidation = validateProjectName(projectName);
if (!nameValidation.valid) {
console.error(chalk.red("Invalid project name:"));
for (const issue of nameValidation.issues) {
console.error(chalk.red(` - ${issue}`));
}
process.exit(1);
}
// Validate directory availability
const dirValidation = validateDirectoryAvailability(resolvedProjectPath);
if (!dirValidation.valid) {
console.error(chalk.red("Directory validation failed:"));
for (const issue of dirValidation.issues) {
console.error(chalk.red(` - ${issue}`));
}
process.exit(1);
}
let packageManager = "npm";
let useLocalXmcp = options.local;
let xmcpVersion = options.xmcpVersion;
let xmcpChannel = options.xmcpChannel;
let deployToVercel = options.vercel;
let skipInstall = options.skipInstall;
let skipIdentity = options.skipIdentity || !options.identity;
let transports = ["http"];
let agentName = projectName;
let agentDescription = "XMCP-I server with identity features";
let agentRepository = "";
// Handle transport selection from CLI options
if (options.http || options.stdio) {
transports = [];
if (options.http)
transports.push("http");
if (options.stdio)
transports.push("stdio");
}
if (!options.yes) {
// Package manager selection
if (options.useYarn)
packageManager = "yarn";
if (options.usePnpm)
packageManager = "pnpm";
if (!options.useYarn && !options.usePnpm && !options.useNpm) {
const pmAnswers = await inquirer.prompt([
{
type: "list",
name: "packageManager",
message: "Select a package manager:",
choices: [
{ name: "npm", value: "npm" },
{ name: "yarn", value: "yarn" },
{ name: "pnpm", value: "pnpm" },
],
default: "npm",
},
]);
packageManager = pmAnswers.packageManager;
}
// Transport selection (skip if already specified via CLI options)
if (!options.http && !options.stdio) {
const transportAnswers = await inquirer.prompt([
{
type: "checkbox",
name: "transports",
message: "Select the transports you want to use:",
choices: [
{
name: "HTTP (runs on a server)",
value: "http",
checked: true,
},
{
name: "STDIO (runs on the user's machine)",
value: "stdio",
checked: false,
},
],
validate: (input) => {
if (input.length === 0) {
return "You must select at least one transport.";
}
return true;
},
},
]);
transports = transportAnswers.transports;
}
// Vercel deployment option
if (!options.vercel && transports.includes("http")) {
const vercelAnswers = await inquirer.prompt([
{
type: "confirm",
name: "deployToVercel",
message: "Add Vercel deployment support?",
default: true,
},
]);
deployToVercel = vercelAnswers.deployToVercel;
}
// Agent information for identity generation
if (!skipIdentity) {
console.log(chalk.blue("\n🤖 Agent Configuration:"));
const agentInfo = await inquirer.prompt([
{
type: "input",
name: "name",
message: "What's your agent name?",
default: projectName,
},
{
type: "input",
name: "description",
message: "Brief description of your agent:",
default: "XMCP-I server with identity features",
},
{
type: "input",
name: "repository",
message: "Repository URL (optional):",
default: "",
},
]);
agentName = agentInfo.name;
agentDescription = agentInfo.description;
agentRepository = agentInfo.repository;
}
console.log();
console.log(`Creating a new xmcp app in ${chalk.green(resolvedProjectPath)}.\n`);
const { confirmed } = await inquirer.prompt([
{
type: "confirm",
name: "confirmed",
message: "Ok to continue?",
default: true,
},
]);
if (!confirmed) {
console.log(chalk.yellow("Aborting installation."));
process.exit(0);
}
}
else {
// Use command-line options when --yes is provided
if (options.useYarn)
packageManager = "yarn";
if (options.usePnpm)
packageManager = "pnpm";
}
const spinner = ora("Creating your xmcp-i app with identity features...").start();
try {
spinner.text = "Scaffolding project structure...";
const result = await createProject({
projectPath: resolvedProjectPath,
projectName,
packageManager,
transports: transports,
packageVersion: packageJson.version,
useLocalXmcp,
xmcpVersion,
xmcpChannel,
deployToVercel,
skipInstall,
agentName,
agentDescription,
agentRepository,
skipIdentity,
skipAnimation: options.noAnimation === false ? true : false, // Handle --no-animation flag
fastAnimation: options.fast,
spinner, // Pass spinner to stop it before animation
});
if (!result.success) {
spinner.fail(chalk.red("Failed to create the project."));
if (result.warnings) {
for (const warning of result.warnings) {
console.error(chalk.red(` ${warning}`));
}
}
process.exit(1);
}
if (result.warnings && result.warnings.length > 0) {
spinner.warn(chalk.yellow("Your xmcp-i app is ready with warnings"));
for (const warning of result.warnings) {
console.warn(chalk.yellow(` ⚠️ ${warning}`));
}
}
else {
spinner.succeed(chalk.green("Your xmcp-i app is ready"));
}
console.log();
console.log("Next Steps:");
// Show agent management with claim URL first
if (!skipIdentity) {
console.log("Agent management:");
console.log(" Follow the Claim URL above to claim your agent");
if (resolvedProjectPath !== process.cwd()) {
console.log(` cd ${chalk.cyan(projectDir)}`);
}
console.log(` ${chalk.cyan(`${packageManager} run status`)} - Check agent status`);
console.log(` ${chalk.cyan(`${packageManager} run register`)} - Register with registry`);
console.log();
}
console.log("Start agent:");
if (resolvedProjectPath !== process.cwd()) {
console.log(` cd ${chalk.cyan(projectDir)}`);
}
if (skipInstall) {
if (packageManager === "yarn") {
console.log(` ${chalk.cyan("yarn install")}`);
}
else if (packageManager === "pnpm") {
console.log(` ${chalk.cyan("pnpm install")}`);
}
else {
console.log(` ${chalk.cyan("npm install")}`);
}
}
// Show appropriate command based on transport
if (transports.includes("stdio")) {
console.log(` ${chalk.cyan("npx xmcp build")}`);
}
else {
// HTTP transport - show dev command
if (packageManager === "yarn") {
console.log(` ${chalk.cyan("yarn dev")}`);
}
else if (packageManager === "pnpm") {
console.log(` ${chalk.cyan("pnpm dev")}`);
}
else {
console.log(` ${chalk.cyan("npm run dev")}`);
}
}
console.log();
console.log("Manage identity:");
if (resolvedProjectPath !== process.cwd()) {
console.log(` cd ${chalk.cyan(projectDir)}`);
}
// Show identity management commands
if (packageManager === "yarn") {
console.log(` ${chalk.cyan("yarn keys:rotate")} - Rotate cryptographic keys`);
console.log(` ${chalk.cyan("yarn identity:clean")} - Clean identity data`);
}
else if (packageManager === "pnpm") {
console.log(` ${chalk.cyan("pnpm keys:rotate")} - Rotate cryptographic keys`);
console.log(` ${chalk.cyan("pnpm identity:clean")} - Clean identity data`);
}
else {
console.log(` ${chalk.cyan("npm run keys:rotate")} - Rotate cryptographic keys`);
console.log(` ${chalk.cyan("npm run identity:clean")} - Clean identity data`);
}
console.log();
// Explicitly exit after successful completion
process.exit(0);
}
catch (error) {
spinner.fail(chalk.red("Failed to create the project."));
console.error(error);
process.exit(1);
}
});
program.parse(process.argv);
//# sourceMappingURL=index.js.map