1+ #!/usr/bin/env node
2+
3+ import fs from 'fs' ;
4+ import path from 'path' ;
5+ import { fileURLToPath } from 'url' ;
6+ import { execSync } from 'child_process' ;
7+
8+ // Get the directory where the source files are stored
9+ const __filename = fileURLToPath ( import . meta. url ) ;
10+ const rootDir = path . join ( path . dirname ( __filename ) , '..' ) ;
11+ const sourceDir = path . join ( rootDir , 'src' ) ;
12+ const targetDir = process . cwd ( ) ;
13+
14+ // Check if the target directory is empty
15+ const isDirectoryEmpty = ( ) => {
16+ const files = fs . readdirSync ( targetDir ) ;
17+ return files . length === 0 || ( files . length === 1 && files [ 0 ] === '.git' ) ;
18+ } ;
19+
20+ // Print a colorful message
21+ const printColorMessage = ( message , color ) => {
22+ const colors = {
23+ red : '\x1b[31m' ,
24+ green : '\x1b[32m' ,
25+ yellow : '\x1b[33m' ,
26+ blue : '\x1b[34m' ,
27+ magenta : '\x1b[35m' ,
28+ cyan : '\x1b[36m' ,
29+ reset : '\x1b[0m'
30+ } ;
31+
32+ console . log ( `${ colors [ color ] } ${ message } ${ colors . reset } ` ) ;
33+ } ;
34+
35+ // Main function
36+ async function main ( ) {
37+ console . log ( '\n' ) ;
38+ printColorMessage ( '🚀 Creating a new MCP server project...' , 'cyan' ) ;
39+ console . log ( '\n' ) ;
40+
41+ // Check if the directory is empty
42+ if ( ! isDirectoryEmpty ( ) ) {
43+ printColorMessage ( '⚠️ The current directory is not empty!' , 'yellow' ) ;
44+ console . log ( 'To avoid overwriting existing files, please run this command in an empty directory.' ) ;
45+ console . log ( 'You can create a new directory and run the command there:' ) ;
46+ console . log ( '\n mkdir my-mcp-server && cd my-mcp-server && npx @mcpdotdirect/create-mcp-server\n' ) ;
47+ process . exit ( 1 ) ;
48+ }
49+
50+ // Check if source directory exists
51+ if ( ! fs . existsSync ( sourceDir ) ) {
52+ printColorMessage ( '⚠️ Source directory not found!' , 'red' ) ;
53+ console . log ( 'This is likely an issue with the package installation.' ) ;
54+ console . log ( 'Please report this issue at: https://github.com/mcpdotdirect/create-mcp-server/issues' ) ;
55+ process . exit ( 1 ) ;
56+ }
57+
58+ try {
59+ // Copy source files to target directory
60+ copyFiles ( sourceDir , path . join ( targetDir , 'src' ) ) ;
61+
62+ // Copy other important files
63+ const filesToCopy = [
64+ '.gitignore' ,
65+ 'tsconfig.json' ,
66+ 'README.md'
67+ ] ;
68+
69+ for ( const file of filesToCopy ) {
70+ const srcPath = path . join ( rootDir , file ) ;
71+ const destPath = path . join ( targetDir , file ) ;
72+
73+ if ( fs . existsSync ( srcPath ) ) {
74+ fs . copyFileSync ( srcPath , destPath ) ;
75+ console . log ( `📄 Created ${ destPath } ` ) ;
76+ }
77+ }
78+
79+ // Create a package.json for the new project
80+ createProjectPackageJson ( ) ;
81+
82+ printColorMessage ( '✅ Source files copied successfully!' , 'green' ) ;
83+
84+ printColorMessage ( '\n🎉 MCP server project created successfully!' , 'green' ) ;
85+ console . log ( '\nNext steps:' ) ;
86+ console . log ( ' 1. Install dependencies:' ) ;
87+ console . log ( ' npm install' ) ;
88+ console . log ( ' # or with yarn' ) ;
89+ console . log ( ' yarn' ) ;
90+ console . log ( ' # or with pnpm' ) ;
91+ console . log ( ' pnpm install' ) ;
92+ console . log ( ' # or with bun' ) ;
93+ console . log ( ' bun install' ) ;
94+ console . log ( ' 2. Review the README.md file for usage instructions' ) ;
95+ console . log ( ' 3. Run "npm start" or "npm run dev" to start the server' ) ;
96+ console . log ( '\nHappy coding! 🚀\n' ) ;
97+ } catch ( error ) {
98+ printColorMessage ( `\n❌ Error creating MCP server project: ${ error . message } ` , 'red' ) ;
99+ console . log ( 'Please report this issue at: https://github.com/mcpdotdirect/create-mcp-server/issues' ) ;
100+ process . exit ( 1 ) ;
101+ }
102+ }
103+
104+ // Function to copy files recursively
105+ function copyFiles ( source , destination ) {
106+ // Create destination directory if it doesn't exist
107+ if ( ! fs . existsSync ( destination ) ) {
108+ fs . mkdirSync ( destination , { recursive : true } ) ;
109+ }
110+
111+ // Read all files/folders in the source directory
112+ const entries = fs . readdirSync ( source , { withFileTypes : true } ) ;
113+
114+ for ( const entry of entries ) {
115+ const srcPath = path . join ( source , entry . name ) ;
116+ const destPath = path . join ( destination , entry . name ) ;
117+
118+ // Skip node_modules, package-lock.json, .git, and other unnecessary directories/files
119+ // This ensures we don't copy any lock files or node_modules, letting the user generate their own
120+ if ( entry . name === 'node_modules' ||
121+ entry . name === 'package-lock.json' ||
122+ entry . name === 'npm-debug.log' ||
123+ entry . name === 'yarn.lock' ||
124+ entry . name === 'pnpm-lock.yaml' ||
125+ entry . name === 'bun.lock' ||
126+ entry . name === '.git' ||
127+ entry . name === 'bin' ||
128+ entry . name === '.cursor' ||
129+ entry . name === 'LICENSE' ||
130+ entry . name === 'build' ) {
131+ continue ;
132+ }
133+
134+ if ( entry . isDirectory ( ) ) {
135+ // Recursively copy directories
136+ copyFiles ( srcPath , destPath ) ;
137+ } else {
138+ // Copy files
139+ fs . copyFileSync ( srcPath , destPath ) ;
140+ console . log ( `📄 Created ${ destPath } ` ) ;
141+ }
142+ }
143+ }
144+
145+ // Create a package.json for the new project
146+ function createProjectPackageJson ( ) {
147+ const packageJsonPath = path . join ( targetDir , 'package.json' ) ;
148+
149+ const projectPackageJson = {
150+ name : "mcp-server" ,
151+ module : "src/index.ts" ,
152+ type : "module" ,
153+ version : "1.0.0" ,
154+ description : "Model Context Protocol (MCP) Server" ,
155+ private : true ,
156+ scripts : {
157+ "start" : "bun run src/index.ts" ,
158+ "build" : "bun build src/index.ts --outdir build --target node" ,
159+ "build:http" : "bun build src/server/http-server.ts --outdir build --target node" ,
160+ "dev" : "bun --watch src/index.ts" ,
161+ "start:http" : "bun run src/server/http-server.ts" ,
162+ "dev:http" : "bun --watch src/server/http-server.ts"
163+ } ,
164+ devDependencies : {
165+ "@types/bun" : "latest" ,
166+ "@types/cors" : "^2.8.17" ,
167+ "@types/express" : "^5.0.0" ,
168+ "@types/node" : "^20.11.0"
169+ } ,
170+ peerDependencies : {
171+ "typescript" : "^5.8.2"
172+ } ,
173+ dependencies : {
174+ "@modelcontextprotocol/sdk" : "^1.7.0" ,
175+ "cors" : "^2.8.5" ,
176+ "express" : "^4.21.2" ,
177+ "zod" : "^3.24.2"
178+ }
179+ } ;
180+
181+ fs . writeFileSync (
182+ packageJsonPath ,
183+ JSON . stringify ( projectPackageJson , null , 2 )
184+ ) ;
185+ console . log ( `📄 Created ${ packageJsonPath } ` ) ;
186+ }
187+
188+ // Run the main function
189+ main ( ) . catch ( error => {
190+ printColorMessage ( `\n❌ Unexpected error: ${ error . message } ` , 'red' ) ;
191+ process . exit ( 1 ) ;
192+ } ) ;
0 commit comments