|
1 | 1 | #!/usr/bin/env node |
2 | | -import { Command } from 'commander'; |
3 | | -import prompts from 'prompts'; |
4 | | -import chalk from 'chalk'; |
5 | | -import fs from 'fs-extra'; |
6 | | -import path from 'path'; |
7 | 2 |
|
8 | | -const program = new Command(); |
| 3 | +import { execSync } from 'node:child_process' |
| 4 | +import { copyFileSync, existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs' |
| 5 | +import { dirname, join, resolve } from 'node:path' |
| 6 | +import { fileURLToPath } from 'node:url' |
| 7 | +import { Command } from 'commander' |
| 8 | + |
| 9 | +const __filename = fileURLToPath(import.meta.url) |
| 10 | +const __dirname = dirname(__filename) |
| 11 | + |
| 12 | +const program = new Command() |
9 | 13 |
|
10 | 14 | program |
11 | 15 | .name('create-mcp-use-app') |
12 | | - .description('Create a new MCP-Use application') |
| 16 | + .description('Create a new MCP server project') |
13 | 17 | .version('0.1.0') |
14 | | - .argument('[project-name]', 'Name of the project') |
15 | | - .option('-t, --template <template>', 'Template to use (basic, advanced)', 'basic') |
16 | | - .option('--typescript', 'Use TypeScript', true) |
17 | | - .option('--no-typescript', 'Use JavaScript') |
18 | | - .option('--git', 'Initialize git repository', true) |
19 | | - .option('--no-git', 'Skip git initialization') |
20 | | - .action(async (projectName, options) => { |
21 | | - if (!projectName) { |
22 | | - const response = await prompts({ |
23 | | - type: 'text', |
24 | | - name: 'projectName', |
25 | | - message: 'What is your project named?', |
26 | | - initial: 'my-mcp-app' |
27 | | - }); |
28 | | - projectName = response.projectName; |
| 18 | + .argument('<project-name>', 'Name of the MCP server project') |
| 19 | + .option('-t, --template <template>', 'Template to use', 'basic') |
| 20 | + .option('--no-install', 'Skip installing dependencies') |
| 21 | + .action(async (projectName: string, options: { template: string, install: boolean }) => { |
| 22 | + try { |
| 23 | + console.log(`🚀 Creating MCP server "${projectName}"...`) |
| 24 | + |
| 25 | + const projectPath = resolve(process.cwd(), projectName) |
| 26 | + |
| 27 | + // Check if directory already exists |
| 28 | + if (existsSync(projectPath)) { |
| 29 | + console.error(`❌ Directory "${projectName}" already exists!`) |
| 30 | + process.exit(1) |
| 31 | + } |
| 32 | + |
| 33 | + // Create project directory |
| 34 | + mkdirSync(projectPath, { recursive: true }) |
| 35 | + |
| 36 | + // Copy template files |
| 37 | + await copyTemplate(projectPath, options.template) |
| 38 | + |
| 39 | + // Update package.json with project name |
| 40 | + updatePackageJson(projectPath, projectName) |
| 41 | + |
| 42 | + // Install dependencies if requested |
| 43 | + if (options.install) { |
| 44 | + console.log('📦 Installing dependencies...') |
| 45 | + try { |
| 46 | + execSync('pnpm install', { cwd: projectPath, stdio: 'inherit' }) |
| 47 | + } |
| 48 | + catch { |
| 49 | + console.log('⚠️ pnpm not found, trying npm...') |
| 50 | + try { |
| 51 | + execSync('npm install', { cwd: projectPath, stdio: 'inherit' }) |
| 52 | + } |
| 53 | + catch { |
| 54 | + console.log('⚠️ npm install failed, please run "npm install" manually') |
| 55 | + } |
| 56 | + } |
| 57 | + } |
| 58 | + |
| 59 | + console.log('✅ MCP server created successfully!') |
| 60 | + console.log('') |
| 61 | + console.log('📁 Project structure:') |
| 62 | + console.log(` ${projectName}/`) |
| 63 | + console.log(' ├── src/') |
| 64 | + console.log(' │ └── server.ts') |
| 65 | + console.log(' ├── package.json') |
| 66 | + console.log(' ├── tsconfig.json') |
| 67 | + console.log(' └── README.md') |
| 68 | + console.log('') |
| 69 | + console.log('🚀 To get started:') |
| 70 | + console.log(` cd ${projectName}`) |
| 71 | + if (!options.install) { |
| 72 | + console.log(' npm install') |
| 73 | + } |
| 74 | + console.log(' npm run dev') |
| 75 | + console.log('') |
| 76 | + console.log('📚 Learn more: https://docs.mcp-use.io') |
29 | 77 | } |
30 | | - |
31 | | - if (!projectName) { |
32 | | - console.log(chalk.red('Project name is required')); |
33 | | - process.exit(1); |
| 78 | + catch (error) { |
| 79 | + console.error('❌ Error creating MCP server:', error) |
| 80 | + process.exit(1) |
34 | 81 | } |
| 82 | + }) |
35 | 83 |
|
36 | | - const projectPath = path.join(process.cwd(), projectName); |
| 84 | +async function copyTemplate(projectPath: string, template: string) { |
| 85 | + const templatePath = join(__dirname, 'templates', template) |
37 | 86 |
|
38 | | - if (fs.existsSync(projectPath)) { |
39 | | - console.log(chalk.red(`Directory ${projectName} already exists`)); |
40 | | - process.exit(1); |
41 | | - } |
| 87 | + if (!existsSync(templatePath)) { |
| 88 | + console.error(`❌ Template "${template}" not found!`) |
| 89 | + console.log('Available templates: basic, filesystem, api, ui') |
| 90 | + process.exit(1) |
| 91 | + } |
42 | 92 |
|
43 | | - console.log(chalk.green(`Creating ${projectName}...`)); |
44 | | - |
45 | | - // Create project directory |
46 | | - fs.ensureDirSync(projectPath); |
47 | | - |
48 | | - // Create package.json |
49 | | - const packageJson = { |
50 | | - name: projectName, |
51 | | - version: '0.1.0', |
52 | | - private: true, |
53 | | - scripts: { |
54 | | - dev: 'node src/index.js', |
55 | | - build: options.typescript ? 'tsc' : 'echo "No build step"', |
56 | | - start: 'node dist/index.js' |
57 | | - }, |
58 | | - dependencies: { |
59 | | - 'mcp-use': '^0.1.20' |
60 | | - }, |
61 | | - devDependencies: options.typescript ? { |
62 | | - '@types/node': '^20.0.0', |
63 | | - 'typescript': '^5.0.0' |
64 | | - } : {} |
65 | | - }; |
66 | | - |
67 | | - fs.writeJsonSync(path.join(projectPath, 'package.json'), packageJson, { spaces: 2 }); |
68 | | - |
69 | | - // Create source files |
70 | | - const srcDir = path.join(projectPath, 'src'); |
71 | | - fs.ensureDirSync(srcDir); |
72 | | - |
73 | | - const ext = options.typescript ? 'ts' : 'js'; |
74 | | - const indexContent = `import { MCPClient } from 'mcp-use'; |
75 | | -
|
76 | | -async function main() { |
77 | | - const client = new MCPClient({ |
78 | | - name: '${projectName}', |
79 | | - version: '0.1.0' |
80 | | - }); |
81 | | -
|
82 | | - // Add your MCP logic here |
83 | | - |
84 | | - console.log('MCP app initialized'); |
| 93 | + copyDirectory(templatePath, projectPath) |
85 | 94 | } |
86 | 95 |
|
87 | | -main().catch(console.error); |
88 | | -`; |
89 | | - |
90 | | - fs.writeFileSync(path.join(srcDir, `index.${ext}`), indexContent); |
91 | | - |
92 | | - // Create tsconfig if TypeScript |
93 | | - if (options.typescript) { |
94 | | - const tsconfig = { |
95 | | - compilerOptions: { |
96 | | - target: 'ES2022', |
97 | | - module: 'commonjs', |
98 | | - lib: ['ES2022'], |
99 | | - outDir: './dist', |
100 | | - rootDir: './src', |
101 | | - strict: true, |
102 | | - esModuleInterop: true, |
103 | | - skipLibCheck: true, |
104 | | - forceConsistentCasingInFileNames: true |
105 | | - }, |
106 | | - include: ['src/**/*'], |
107 | | - exclude: ['node_modules', 'dist'] |
108 | | - }; |
109 | | - fs.writeJsonSync(path.join(projectPath, 'tsconfig.json'), tsconfig, { spaces: 2 }); |
110 | | - } |
111 | | - |
112 | | - // Create README |
113 | | - const readme = `# ${projectName} |
| 96 | +function copyDirectory(src: string, dest: string) { |
| 97 | + const entries = readdirSync(src, { withFileTypes: true }) |
114 | 98 |
|
115 | | -An MCP-Use application |
| 99 | + for (const entry of entries) { |
| 100 | + const srcPath = join(src, entry.name) |
| 101 | + const destPath = join(dest, entry.name) |
116 | 102 |
|
117 | | -## Getting Started |
118 | | -
|
119 | | -\`\`\`bash |
120 | | -npm install |
121 | | -npm run dev |
122 | | -\`\`\` |
| 103 | + if (entry.isDirectory()) { |
| 104 | + mkdirSync(destPath, { recursive: true }) |
| 105 | + copyDirectory(srcPath, destPath) |
| 106 | + } |
| 107 | + else { |
| 108 | + copyFileSync(srcPath, destPath) |
| 109 | + } |
| 110 | + } |
| 111 | +} |
123 | 112 |
|
124 | | -## License |
| 113 | +function updatePackageJson(projectPath: string, projectName: string) { |
| 114 | + const packageJsonPath = join(projectPath, 'package.json') |
| 115 | + const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8')) |
125 | 116 |
|
126 | | -MIT |
127 | | -`; |
128 | | - fs.writeFileSync(path.join(projectPath, 'README.md'), readme); |
| 117 | + packageJson.name = projectName |
| 118 | + packageJson.description = `MCP server: ${projectName}` |
129 | 119 |
|
130 | | - // Initialize git if requested |
131 | | - if (options.git) { |
132 | | - const gitignore = `node_modules/ |
133 | | -dist/ |
134 | | -.env |
135 | | -*.log |
136 | | -`; |
137 | | - fs.writeFileSync(path.join(projectPath, '.gitignore'), gitignore); |
138 | | - } |
| 120 | + writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2)) |
| 121 | +} |
139 | 122 |
|
140 | | - console.log(chalk.green('✓ Project created successfully!')); |
141 | | - console.log(); |
142 | | - console.log('Next steps:'); |
143 | | - console.log(chalk.cyan(` cd ${projectName}`)); |
144 | | - console.log(chalk.cyan(' npm install')); |
145 | | - console.log(chalk.cyan(' npm run dev')); |
146 | | - }); |
| 123 | +program.parse() |
147 | 124 |
|
148 | | -program.parse(); |
0 commit comments