mcp-new 1.2.2 → 1.6.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.
Files changed (50) hide show
  1. package/README.md +33 -1
  2. package/dist/{chunk-3JG4FVS2.js → chunk-LJNMSDBU.js} +1157 -212
  3. package/dist/cli.js +1287 -18
  4. package/dist/index.d.ts +43 -10
  5. package/dist/index.js +22 -35
  6. package/package.json +4 -2
  7. package/templates/ci/circleci/config.yml.ejs +219 -0
  8. package/templates/ci/github/ci.yml.ejs +184 -0
  9. package/templates/ci/gitlab/.gitlab-ci.yml.ejs +233 -0
  10. package/templates/csharp/.env.example +6 -0
  11. package/templates/csharp/.gitignore.ejs +53 -0
  12. package/templates/csharp/McpServer.csproj.ejs +19 -0
  13. package/templates/csharp/README.md.ejs +136 -0
  14. package/templates/csharp/src/Program.cs.ejs +117 -0
  15. package/templates/elixir/.env.example +6 -0
  16. package/templates/elixir/.gitignore.ejs +33 -0
  17. package/templates/elixir/README.md.ejs +154 -0
  18. package/templates/elixir/config/config.exs.ejs +9 -0
  19. package/templates/elixir/config/dev.exs.ejs +3 -0
  20. package/templates/elixir/config/prod.exs.ejs +3 -0
  21. package/templates/elixir/lib/application.ex.ejs +19 -0
  22. package/templates/elixir/lib/cli.ex.ejs +17 -0
  23. package/templates/elixir/lib/server.ex.ejs +112 -0
  24. package/templates/elixir/mix.exs.ejs +32 -0
  25. package/templates/java/gradle/.env.example +6 -0
  26. package/templates/java/gradle/.gitignore.ejs +48 -0
  27. package/templates/java/gradle/README.md.ejs +132 -0
  28. package/templates/java/gradle/build.gradle.ejs +46 -0
  29. package/templates/java/gradle/settings.gradle.ejs +1 -0
  30. package/templates/java/gradle/src/main/java/com/example/mcp/McpServer.java.ejs +149 -0
  31. package/templates/java/gradle/src/main/resources/logback.xml +13 -0
  32. package/templates/java/maven/.env.example +6 -0
  33. package/templates/java/maven/.gitignore.ejs +53 -0
  34. package/templates/java/maven/README.md.ejs +131 -0
  35. package/templates/java/maven/pom.xml.ejs +86 -0
  36. package/templates/java/maven/src/main/java/com/example/mcp/McpServer.java.ejs +149 -0
  37. package/templates/java/maven/src/main/resources/logback.xml +13 -0
  38. package/templates/kotlin/gradle/.env.example +6 -0
  39. package/templates/kotlin/gradle/.gitignore.ejs +45 -0
  40. package/templates/kotlin/gradle/README.md.ejs +138 -0
  41. package/templates/kotlin/gradle/build.gradle.kts.ejs +48 -0
  42. package/templates/kotlin/gradle/settings.gradle.kts.ejs +1 -0
  43. package/templates/kotlin/gradle/src/main/kotlin/com/example/mcp/McpServer.kt.ejs +141 -0
  44. package/templates/kotlin/gradle/src/main/resources/logback.xml +13 -0
  45. package/templates/kotlin/maven/.env.example +6 -0
  46. package/templates/kotlin/maven/.gitignore.ejs +50 -0
  47. package/templates/kotlin/maven/README.md.ejs +96 -0
  48. package/templates/kotlin/maven/pom.xml.ejs +105 -0
  49. package/templates/kotlin/maven/src/main/kotlin/com/example/mcp/McpServer.kt.ejs +141 -0
  50. package/templates/kotlin/maven/src/main/resources/logback.xml +13 -0
@@ -40,12 +40,12 @@ function validateUrl(url) {
40
40
  return { valid: false, error: "Invalid URL format" };
41
41
  }
42
42
  }
43
- function validateFilePath(path7) {
44
- if (!path7 || path7.trim().length === 0) {
43
+ function validateFilePath(path11) {
44
+ if (!path11 || path11.trim().length === 0) {
45
45
  return { valid: false, error: "File path cannot be empty" };
46
46
  }
47
47
  const invalidChars = /[<>:"|?*]/;
48
- if (invalidChars.test(path7)) {
48
+ if (invalidChars.test(path11)) {
49
49
  return { valid: false, error: "File path contains invalid characters" };
50
50
  }
51
51
  return { valid: true };
@@ -90,20 +90,270 @@ async function promptProjectDescription() {
90
90
  return description;
91
91
  }
92
92
 
93
+ // src/utils/file-system.ts
94
+ import fs from "fs-extra";
95
+ import path from "path";
96
+ import ejs from "ejs";
97
+ async function ensureDir(dirPath) {
98
+ await fs.ensureDir(dirPath);
99
+ }
100
+ async function writeFile(filePath, content) {
101
+ await fs.ensureDir(path.dirname(filePath));
102
+ await fs.writeFile(filePath, content, "utf-8");
103
+ }
104
+ async function readFile(filePath) {
105
+ return fs.readFile(filePath, "utf-8");
106
+ }
107
+ async function copyFile(src, dest) {
108
+ await fs.ensureDir(path.dirname(dest));
109
+ await fs.copyFile(src, dest);
110
+ }
111
+ async function copyDir(src, dest) {
112
+ await fs.copy(src, dest);
113
+ }
114
+ async function exists(filePath) {
115
+ return fs.pathExists(filePath);
116
+ }
117
+ async function remove(filePath) {
118
+ await fs.remove(filePath);
119
+ }
120
+ async function readDir(dirPath) {
121
+ return fs.readdir(dirPath);
122
+ }
123
+ async function isDirectory(filePath) {
124
+ try {
125
+ const stat = await fs.stat(filePath);
126
+ return stat.isDirectory();
127
+ } catch {
128
+ return false;
129
+ }
130
+ }
131
+ async function renderTemplate(templatePath, data) {
132
+ const template = await readFile(templatePath);
133
+ return ejs.render(template, data, { async: false });
134
+ }
135
+ async function renderTemplateToFile(templatePath, outputPath, data) {
136
+ const content = await renderTemplate(templatePath, data);
137
+ const finalPath = outputPath.replace(/\.ejs$/, "");
138
+ await writeFile(finalPath, content);
139
+ }
140
+ async function walkDir(dirPath, callback) {
141
+ const entries = await fs.readdir(dirPath, { withFileTypes: true });
142
+ for (const entry of entries) {
143
+ const fullPath = path.join(dirPath, entry.name);
144
+ const isDir = entry.isDirectory();
145
+ await callback(fullPath, isDir);
146
+ if (isDir) {
147
+ await walkDir(fullPath, callback);
148
+ }
149
+ }
150
+ }
151
+ function getTemplateDir() {
152
+ const devPath = path.join(import.meta.dirname, "..", "templates");
153
+ const prodPath = path.join(import.meta.dirname, "..", "..", "templates");
154
+ if (fs.existsSync(devPath)) {
155
+ return devPath;
156
+ }
157
+ return prodPath;
158
+ }
159
+ function getTemplateDirForLanguage(language, pluginTemplateDir) {
160
+ if (pluginTemplateDir) {
161
+ return pluginTemplateDir;
162
+ }
163
+ return path.join(getTemplateDir(), language);
164
+ }
165
+ function resolveOutputPath(basePath, ...segments) {
166
+ return path.resolve(basePath, ...segments);
167
+ }
168
+
169
+ // src/plugins/discovery.ts
170
+ import path2 from "path";
171
+
172
+ // src/types/plugin.ts
173
+ import { z } from "zod";
174
+ var LanguagePluginManifestSchema = z.object({
175
+ languageId: z.string(),
176
+ languageDisplayName: z.string(),
177
+ templateDir: z.string().default("templates"),
178
+ installCommand: z.string().optional(),
179
+ runCommand: z.string().optional(),
180
+ buildCommand: z.string().optional(),
181
+ fileExtension: z.string().optional()
182
+ });
183
+ var PLUGIN_MANIFEST_FILE = "mcp-plugin.json";
184
+
185
+ // src/plugins/discovery.ts
186
+ async function discoverPlugins() {
187
+ const plugins = [];
188
+ const searchPaths = [
189
+ // Global npm modules
190
+ getGlobalNodeModulesPath(),
191
+ // Local node_modules
192
+ path2.join(process.cwd(), "node_modules"),
193
+ // Relative to this package
194
+ path2.join(import.meta.dirname, "..", "..", "node_modules")
195
+ ];
196
+ for (const searchPath of searchPaths) {
197
+ const scopedPath = path2.join(searchPath, "@mcp-new");
198
+ if (!await exists(scopedPath)) {
199
+ continue;
200
+ }
201
+ try {
202
+ const { readdir } = await import("fs/promises");
203
+ const entries = await readdir(scopedPath, { withFileTypes: true });
204
+ for (const entry of entries) {
205
+ if (!entry.isDirectory()) continue;
206
+ if (!entry.name.startsWith("template-")) continue;
207
+ const pluginPath = path2.join(scopedPath, entry.name);
208
+ const plugin = await loadPlugin(pluginPath, `@mcp-new/${entry.name}`);
209
+ if (plugin) {
210
+ if (!plugins.some((p) => p.manifest.languageId === plugin.manifest.languageId)) {
211
+ plugins.push(plugin);
212
+ }
213
+ }
214
+ }
215
+ } catch {
216
+ }
217
+ }
218
+ return plugins;
219
+ }
220
+ async function loadPlugin(packagePath, packageName) {
221
+ const manifestPath = path2.join(packagePath, PLUGIN_MANIFEST_FILE);
222
+ if (!await exists(manifestPath)) {
223
+ return null;
224
+ }
225
+ try {
226
+ const content = await readFile(manifestPath);
227
+ const rawManifest = JSON.parse(content);
228
+ const manifest = LanguagePluginManifestSchema.parse(rawManifest);
229
+ const templatePath = path2.join(packagePath, manifest.templateDir);
230
+ if (!await exists(templatePath)) {
231
+ console.warn(`Plugin ${packageName}: templates directory not found at ${templatePath}`);
232
+ return null;
233
+ }
234
+ return {
235
+ manifest,
236
+ packageName,
237
+ packagePath,
238
+ templatePath
239
+ };
240
+ } catch (error) {
241
+ console.warn(`Failed to load plugin ${packageName}:`, error);
242
+ return null;
243
+ }
244
+ }
245
+ function getGlobalNodeModulesPath() {
246
+ if (process.platform === "win32") {
247
+ return path2.join(process.env.APPDATA || "", "npm", "node_modules");
248
+ }
249
+ return "/usr/local/lib/node_modules";
250
+ }
251
+ function isPluginLanguage(languageId, plugins) {
252
+ return plugins.some((p) => p.manifest.languageId === languageId);
253
+ }
254
+ function getPluginForLanguage(languageId, plugins) {
255
+ return plugins.find((p) => p.manifest.languageId === languageId);
256
+ }
257
+
258
+ // src/plugins/registry.ts
259
+ var PluginRegistry = class {
260
+ plugins = [];
261
+ initialized = false;
262
+ /**
263
+ * Initialize the registry by discovering installed plugins.
264
+ */
265
+ async initialize() {
266
+ if (this.initialized) {
267
+ return;
268
+ }
269
+ this.plugins = await discoverPlugins();
270
+ this.initialized = true;
271
+ }
272
+ /**
273
+ * Get all registered plugins.
274
+ */
275
+ getPlugins() {
276
+ return [...this.plugins];
277
+ }
278
+ /**
279
+ * Get a plugin by language ID.
280
+ */
281
+ getPlugin(languageId) {
282
+ return getPluginForLanguage(languageId, this.plugins);
283
+ }
284
+ /**
285
+ * Check if a language is provided by a plugin.
286
+ */
287
+ isPluginLanguage(languageId) {
288
+ return isPluginLanguage(languageId, this.plugins);
289
+ }
290
+ /**
291
+ * Get all available languages from plugins.
292
+ */
293
+ getPluginLanguages() {
294
+ return this.plugins.map((p) => ({
295
+ id: p.manifest.languageId,
296
+ name: p.manifest.languageDisplayName
297
+ }));
298
+ }
299
+ /**
300
+ * Get the template directory for a plugin language.
301
+ */
302
+ getPluginTemplateDir(languageId) {
303
+ const plugin = this.getPlugin(languageId);
304
+ return plugin?.templatePath;
305
+ }
306
+ /**
307
+ * Get the install command for a plugin language.
308
+ */
309
+ getPluginInstallCommand(languageId) {
310
+ const plugin = this.getPlugin(languageId);
311
+ return plugin?.manifest.installCommand;
312
+ }
313
+ /**
314
+ * Get the run command for a plugin language.
315
+ */
316
+ getPluginRunCommand(languageId) {
317
+ const plugin = this.getPlugin(languageId);
318
+ return plugin?.manifest.runCommand;
319
+ }
320
+ /**
321
+ * Reset the registry (for testing).
322
+ */
323
+ reset() {
324
+ this.plugins = [];
325
+ this.initialized = false;
326
+ }
327
+ };
328
+ var pluginRegistry = new PluginRegistry();
329
+
93
330
  // src/prompts/language.ts
94
331
  import inquirer2 from "inquirer";
332
+ var BUILTIN_CHOICES = [
333
+ { name: "TypeScript", value: "typescript" },
334
+ { name: "Python", value: "python" },
335
+ { name: "Go", value: "go" },
336
+ { name: "Rust", value: "rust" },
337
+ { name: "Java", value: "java" },
338
+ { name: "Kotlin", value: "kotlin" },
339
+ { name: "C# (.NET)", value: "csharp" },
340
+ { name: "Elixir", value: "elixir" }
341
+ ];
95
342
  async function promptLanguage() {
343
+ const pluginLanguages = pluginRegistry.getPluginLanguages();
344
+ const choices = [...BUILTIN_CHOICES];
345
+ if (pluginLanguages.length > 0) {
346
+ choices.push(new inquirer2.Separator("\u2500\u2500 Plugins \u2500\u2500"));
347
+ for (const lang of pluginLanguages) {
348
+ choices.push({ name: `${lang.name} (plugin)`, value: lang.id });
349
+ }
350
+ }
96
351
  const { language } = await inquirer2.prompt([
97
352
  {
98
353
  type: "list",
99
354
  name: "language",
100
355
  message: "Select language:",
101
- choices: [
102
- { name: "TypeScript", value: "typescript" },
103
- { name: "Python", value: "python" },
104
- { name: "Go", value: "go" },
105
- { name: "Rust", value: "rust" }
106
- ],
356
+ choices,
107
357
  default: "typescript"
108
358
  }
109
359
  ]);
@@ -314,10 +564,28 @@ async function promptMultipleResources() {
314
564
  return resources;
315
565
  }
316
566
 
317
- // src/prompts/generation-method.ts
567
+ // src/prompts/java-build-tool.ts
318
568
  import inquirer6 from "inquirer";
569
+ async function promptJavaBuildTool() {
570
+ const { buildTool } = await inquirer6.prompt([
571
+ {
572
+ type: "list",
573
+ name: "buildTool",
574
+ message: "Select Java build tool:",
575
+ choices: [
576
+ { name: "Maven (pom.xml)", value: "maven" },
577
+ { name: "Gradle (build.gradle)", value: "gradle" }
578
+ ],
579
+ default: "maven"
580
+ }
581
+ ]);
582
+ return buildTool;
583
+ }
584
+
585
+ // src/prompts/generation-method.ts
586
+ import inquirer7 from "inquirer";
319
587
  async function promptGenerationMethod() {
320
- const { method } = await inquirer6.prompt([
588
+ const { method } = await inquirer7.prompt([
321
589
  {
322
590
  type: "list",
323
591
  name: "method",
@@ -346,8 +614,67 @@ async function promptGenerationMethod() {
346
614
  return method;
347
615
  }
348
616
 
617
+ // src/types/config.ts
618
+ import { z as z2 } from "zod";
619
+ var BuiltinLanguageSchema = z2.enum([
620
+ "typescript",
621
+ "python",
622
+ "go",
623
+ "rust",
624
+ "java",
625
+ "kotlin",
626
+ "csharp",
627
+ "elixir"
628
+ ]);
629
+ var LanguageSchema = z2.string();
630
+ var BUILTIN_LANGUAGES = [
631
+ "typescript",
632
+ "python",
633
+ "go",
634
+ "rust",
635
+ "java",
636
+ "kotlin",
637
+ "csharp",
638
+ "elixir"
639
+ ];
640
+ function isBuiltinLanguage(lang) {
641
+ return BUILTIN_LANGUAGES.includes(lang);
642
+ }
643
+ var JavaBuildToolSchema = z2.enum(["maven", "gradle"]);
644
+ var TransportSchema = z2.enum(["stdio", "sse"]);
645
+ var ToolParameterSchema = z2.object({
646
+ name: z2.string(),
647
+ type: z2.enum(["string", "number", "boolean", "object", "array"]),
648
+ description: z2.string(),
649
+ required: z2.boolean().default(true)
650
+ });
651
+ var ToolConfigSchema = z2.object({
652
+ name: z2.string(),
653
+ description: z2.string(),
654
+ parameters: z2.array(ToolParameterSchema).default([])
655
+ });
656
+ var ResourceConfigSchema = z2.object({
657
+ name: z2.string(),
658
+ uri: z2.string(),
659
+ description: z2.string(),
660
+ mimeType: z2.string().optional()
661
+ });
662
+ var ProjectConfigSchema = z2.object({
663
+ name: z2.string().min(1, "Project name is required"),
664
+ description: z2.string().default(""),
665
+ language: LanguageSchema,
666
+ transport: TransportSchema,
667
+ tools: z2.array(ToolConfigSchema).default([]),
668
+ resources: z2.array(ResourceConfigSchema).default([]),
669
+ includeExampleTool: z2.boolean().default(true),
670
+ skipInstall: z2.boolean().default(false),
671
+ initGit: z2.boolean().default(true),
672
+ javaBuildTool: JavaBuildToolSchema.optional()
673
+ });
674
+ var PresetIdSchema = z2.enum(["database", "rest-api", "filesystem"]);
675
+
349
676
  // src/prompts/preset.ts
350
- import inquirer7 from "inquirer";
677
+ import inquirer8 from "inquirer";
351
678
 
352
679
  // src/presets/database.ts
353
680
  var DATABASE_PRESET = {
@@ -657,6 +984,230 @@ var FILESYSTEM_PRESET = {
657
984
  ]
658
985
  };
659
986
 
987
+ // src/types/marketplace.ts
988
+ import { z as z3 } from "zod";
989
+ var ExternalPresetManifestSchema = z3.object({
990
+ id: z3.string(),
991
+ name: z3.string(),
992
+ description: z3.string(),
993
+ version: z3.string(),
994
+ tools: z3.array(ToolConfigSchema),
995
+ author: z3.string().optional(),
996
+ repository: z3.string().optional()
997
+ });
998
+ var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
999
+ function parsePresetIdentifier(identifier) {
1000
+ if (identifier.startsWith("github:")) {
1001
+ return {
1002
+ type: "github",
1003
+ identifier: identifier.replace("github:", "")
1004
+ };
1005
+ }
1006
+ if (identifier.startsWith("@")) {
1007
+ return {
1008
+ type: "npm",
1009
+ identifier
1010
+ };
1011
+ }
1012
+ return {
1013
+ type: "local",
1014
+ identifier
1015
+ };
1016
+ }
1017
+ function isExternalPreset(identifier) {
1018
+ return identifier.startsWith("@") || identifier.startsWith("github:");
1019
+ }
1020
+
1021
+ // src/marketplace/preset-resolver.ts
1022
+ import path4 from "path";
1023
+ import os2 from "os";
1024
+ import { execa } from "execa";
1025
+ import * as tar from "tar";
1026
+
1027
+ // src/marketplace/cache.ts
1028
+ import path3 from "path";
1029
+ import os from "os";
1030
+ var CACHE_DIR = path3.join(os.homedir(), ".mcp-new", "preset-cache");
1031
+ function getCacheFilePath(source) {
1032
+ const safeId = source.identifier.replace(/[^a-zA-Z0-9]/g, "_");
1033
+ return path3.join(CACHE_DIR, `${source.type}_${safeId}.json`);
1034
+ }
1035
+ async function getCachedPreset(source) {
1036
+ const cacheFile = getCacheFilePath(source);
1037
+ if (!await exists(cacheFile)) {
1038
+ return null;
1039
+ }
1040
+ try {
1041
+ const content = await readFile(cacheFile);
1042
+ const cached = JSON.parse(content);
1043
+ const now = Date.now();
1044
+ if (now - cached.cachedAt > CACHE_TTL_MS) {
1045
+ return null;
1046
+ }
1047
+ return cached;
1048
+ } catch {
1049
+ return null;
1050
+ }
1051
+ }
1052
+ async function setCachedPreset(source, manifest) {
1053
+ await ensureDir(CACHE_DIR);
1054
+ const cached = {
1055
+ manifest,
1056
+ cachedAt: Date.now(),
1057
+ source
1058
+ };
1059
+ const cacheFile = getCacheFilePath(source);
1060
+ await writeFile(cacheFile, JSON.stringify(cached, null, 2));
1061
+ }
1062
+ async function clearPresetCache() {
1063
+ if (!await exists(CACHE_DIR)) {
1064
+ return 0;
1065
+ }
1066
+ try {
1067
+ const { readdir, stat, unlink } = await import("fs/promises");
1068
+ const files = await readdir(CACHE_DIR);
1069
+ let count = 0;
1070
+ for (const file of files) {
1071
+ if (file.endsWith(".json")) {
1072
+ await unlink(path3.join(CACHE_DIR, file));
1073
+ count++;
1074
+ }
1075
+ }
1076
+ return count;
1077
+ } catch {
1078
+ return 0;
1079
+ }
1080
+ }
1081
+ async function listCachedPresets() {
1082
+ if (!await exists(CACHE_DIR)) {
1083
+ return [];
1084
+ }
1085
+ try {
1086
+ const { readdir } = await import("fs/promises");
1087
+ const files = await readdir(CACHE_DIR);
1088
+ const presets = [];
1089
+ for (const file of files) {
1090
+ if (file.endsWith(".json")) {
1091
+ try {
1092
+ const content = await readFile(path3.join(CACHE_DIR, file));
1093
+ const cached = JSON.parse(content);
1094
+ presets.push(cached);
1095
+ } catch {
1096
+ }
1097
+ }
1098
+ }
1099
+ return presets;
1100
+ } catch {
1101
+ return [];
1102
+ }
1103
+ }
1104
+ function getCacheDir() {
1105
+ return CACHE_DIR;
1106
+ }
1107
+
1108
+ // src/marketplace/preset-resolver.ts
1109
+ var TEMP_DIR = path4.join(os2.tmpdir(), "mcp-new-presets");
1110
+ async function resolveExternalPreset(source) {
1111
+ const cached = await getCachedPreset(source);
1112
+ if (cached) {
1113
+ return cached.manifest;
1114
+ }
1115
+ let manifest;
1116
+ switch (source.type) {
1117
+ case "npm":
1118
+ manifest = await resolveNpmPreset(source.identifier);
1119
+ break;
1120
+ case "github":
1121
+ manifest = await resolveGitHubPreset(source.identifier);
1122
+ break;
1123
+ default:
1124
+ throw new Error(`Unknown preset source type: ${source.type}`);
1125
+ }
1126
+ await setCachedPreset(source, manifest);
1127
+ return manifest;
1128
+ }
1129
+ async function resolveNpmPreset(packageName) {
1130
+ await ensureDir(TEMP_DIR);
1131
+ const extractDir = path4.join(TEMP_DIR, `npm_${packageName.replace(/[^a-zA-Z0-9]/g, "_")}`);
1132
+ try {
1133
+ if (await exists(extractDir)) {
1134
+ await remove(extractDir);
1135
+ }
1136
+ await ensureDir(extractDir);
1137
+ const { stdout } = await execa("npm", ["pack", packageName, "--pack-destination", extractDir], {
1138
+ cwd: extractDir
1139
+ });
1140
+ const tarballName = stdout.trim();
1141
+ const tarballPath = path4.join(extractDir, tarballName);
1142
+ await tar.x({
1143
+ file: tarballPath,
1144
+ cwd: extractDir
1145
+ });
1146
+ const manifestPath = path4.join(extractDir, "package", "mcp-preset.json");
1147
+ if (!await exists(manifestPath)) {
1148
+ throw new Error(
1149
+ `Invalid preset package: ${packageName} - missing mcp-preset.json manifest file`
1150
+ );
1151
+ }
1152
+ const manifestContent = await readFile(manifestPath);
1153
+ const rawManifest = JSON.parse(manifestContent);
1154
+ const manifest = ExternalPresetManifestSchema.parse(rawManifest);
1155
+ return manifest;
1156
+ } finally {
1157
+ try {
1158
+ if (await exists(extractDir)) {
1159
+ await remove(extractDir);
1160
+ }
1161
+ } catch {
1162
+ }
1163
+ }
1164
+ }
1165
+ async function resolveGitHubPreset(repoPath) {
1166
+ const [repo, branch = "main"] = repoPath.split("@");
1167
+ const [owner, repoName] = repo.split("/");
1168
+ if (!owner || !repoName) {
1169
+ throw new Error(`Invalid GitHub preset format: ${repoPath}. Expected: user/repo[@branch]`);
1170
+ }
1171
+ await ensureDir(TEMP_DIR);
1172
+ const extractDir = path4.join(TEMP_DIR, `github_${owner}_${repoName}`);
1173
+ try {
1174
+ if (await exists(extractDir)) {
1175
+ await remove(extractDir);
1176
+ }
1177
+ await ensureDir(extractDir);
1178
+ const tarballUrl = `https://github.com/${owner}/${repoName}/archive/refs/heads/${branch}.tar.gz`;
1179
+ const tarballPath = path4.join(extractDir, "repo.tar.gz");
1180
+ await execa("curl", ["-L", "-o", tarballPath, tarballUrl]);
1181
+ await tar.x({
1182
+ file: tarballPath,
1183
+ cwd: extractDir
1184
+ });
1185
+ const { readdir } = await import("fs/promises");
1186
+ const entries = await readdir(extractDir);
1187
+ const repoDir = entries.find((e) => e.startsWith(`${repoName}-`));
1188
+ if (!repoDir) {
1189
+ throw new Error(`Failed to extract GitHub repository: ${repoPath}`);
1190
+ }
1191
+ const manifestPath = path4.join(extractDir, repoDir, "mcp-preset.json");
1192
+ if (!await exists(manifestPath)) {
1193
+ throw new Error(
1194
+ `Invalid preset repository: ${repoPath} - missing mcp-preset.json manifest file`
1195
+ );
1196
+ }
1197
+ const manifestContent = await readFile(manifestPath);
1198
+ const rawManifest = JSON.parse(manifestContent);
1199
+ const manifest = ExternalPresetManifestSchema.parse(rawManifest);
1200
+ return manifest;
1201
+ } finally {
1202
+ try {
1203
+ if (await exists(extractDir)) {
1204
+ await remove(extractDir);
1205
+ }
1206
+ } catch {
1207
+ }
1208
+ }
1209
+ }
1210
+
660
1211
  // src/presets/index.ts
661
1212
  var PRESETS = {
662
1213
  database: DATABASE_PRESET,
@@ -670,6 +1221,28 @@ function getPreset(id) {
670
1221
  function isValidPresetId(id) {
671
1222
  return id in PRESETS;
672
1223
  }
1224
+ async function getPresetByIdentifier(identifier) {
1225
+ if (!isExternalPreset(identifier)) {
1226
+ const preset = getPreset(identifier);
1227
+ if (!preset) {
1228
+ throw new Error(
1229
+ `Unknown preset: ${identifier}. Valid local presets: ${PRESET_IDS.join(", ")}`
1230
+ );
1231
+ }
1232
+ return preset;
1233
+ }
1234
+ const source = parsePresetIdentifier(identifier);
1235
+ const manifest = await resolveExternalPreset(source);
1236
+ return externalManifestToPreset(manifest);
1237
+ }
1238
+ function externalManifestToPreset(manifest) {
1239
+ return {
1240
+ id: manifest.id,
1241
+ name: manifest.name,
1242
+ description: manifest.description,
1243
+ tools: manifest.tools
1244
+ };
1245
+ }
673
1246
 
674
1247
  // src/prompts/preset.ts
675
1248
  async function promptPreset() {
@@ -677,7 +1250,7 @@ async function promptPreset() {
677
1250
  name: `${preset2.name} - ${preset2.description}`,
678
1251
  value: preset2.id
679
1252
  }));
680
- const { preset } = await inquirer7.prompt([
1253
+ const { preset } = await inquirer8.prompt([
681
1254
  {
682
1255
  type: "list",
683
1256
  name: "preset",
@@ -689,6 +1262,24 @@ async function promptPreset() {
689
1262
  return preset;
690
1263
  }
691
1264
 
1265
+ // src/prompts/ci-provider.ts
1266
+ import inquirer9 from "inquirer";
1267
+ async function promptCIProvider() {
1268
+ const { provider } = await inquirer9.prompt([
1269
+ {
1270
+ type: "list",
1271
+ name: "provider",
1272
+ message: "Which CI/CD provider would you like to use?",
1273
+ choices: [
1274
+ { name: "GitHub Actions", value: "github" },
1275
+ { name: "GitLab CI", value: "gitlab" },
1276
+ { name: "CircleCI", value: "circleci" }
1277
+ ]
1278
+ }
1279
+ ]);
1280
+ return provider;
1281
+ }
1282
+
692
1283
  // src/prompts/index.ts
693
1284
  async function runWizard(options = {}) {
694
1285
  const name = await promptProjectName(options.defaultName);
@@ -697,6 +1288,10 @@ async function runWizard(options = {}) {
697
1288
  description = await promptProjectDescription();
698
1289
  }
699
1290
  const language = options.presetLanguage || await promptLanguage();
1291
+ let javaBuildTool;
1292
+ if (language === "java" || language === "kotlin") {
1293
+ javaBuildTool = options.presetJavaBuildTool || await promptJavaBuildTool();
1294
+ }
700
1295
  const transport = await promptTransport();
701
1296
  const includeExampleTool = await promptIncludeExampleTool();
702
1297
  let tools = [];
@@ -720,14 +1315,19 @@ async function runWizard(options = {}) {
720
1315
  resources,
721
1316
  includeExampleTool,
722
1317
  skipInstall: false,
723
- initGit: true
1318
+ initGit: true,
1319
+ javaBuildTool
724
1320
  };
725
1321
  }
726
- async function runQuickWizard(defaultName, presetLanguage) {
727
- const name = await promptProjectName(defaultName);
1322
+ async function runQuickWizard(defaultName, presetLanguage, presetJavaBuildTool) {
1323
+ const name = defaultName || await promptProjectName();
728
1324
  const language = presetLanguage || await promptLanguage();
729
- const transport = await promptTransport();
730
- const includeExampleTool = await promptIncludeExampleTool();
1325
+ let javaBuildTool;
1326
+ if (language === "java" || language === "kotlin") {
1327
+ javaBuildTool = presetJavaBuildTool || await promptJavaBuildTool();
1328
+ }
1329
+ const transport = "stdio";
1330
+ const includeExampleTool = true;
731
1331
  return {
732
1332
  name,
733
1333
  description: "",
@@ -737,102 +1337,33 @@ async function runQuickWizard(defaultName, presetLanguage) {
737
1337
  resources: [],
738
1338
  includeExampleTool,
739
1339
  skipInstall: false,
740
- initGit: true
1340
+ initGit: true,
1341
+ javaBuildTool
741
1342
  };
742
1343
  }
743
1344
 
744
- // src/utils/file-system.ts
745
- import fs from "fs-extra";
746
- import path from "path";
747
- import ejs from "ejs";
748
- async function ensureDir(dirPath) {
749
- await fs.ensureDir(dirPath);
750
- }
751
- async function writeFile(filePath, content) {
752
- await fs.ensureDir(path.dirname(filePath));
753
- await fs.writeFile(filePath, content, "utf-8");
754
- }
755
- async function readFile(filePath) {
756
- return fs.readFile(filePath, "utf-8");
757
- }
758
- async function copyFile(src, dest) {
759
- await fs.ensureDir(path.dirname(dest));
760
- await fs.copyFile(src, dest);
761
- }
762
- async function copyDir(src, dest) {
763
- await fs.copy(src, dest);
764
- }
765
- async function exists(filePath) {
766
- return fs.pathExists(filePath);
767
- }
768
- async function remove(filePath) {
769
- await fs.remove(filePath);
770
- }
771
- async function readDir(dirPath) {
772
- return fs.readdir(dirPath);
773
- }
774
- async function isDirectory(filePath) {
775
- try {
776
- const stat = await fs.stat(filePath);
777
- return stat.isDirectory();
778
- } catch {
779
- return false;
780
- }
781
- }
782
- async function renderTemplate(templatePath, data) {
783
- const template = await readFile(templatePath);
784
- return ejs.render(template, data, { async: false });
785
- }
786
- async function renderTemplateToFile(templatePath, outputPath, data) {
787
- const content = await renderTemplate(templatePath, data);
788
- const finalPath = outputPath.replace(/\.ejs$/, "");
789
- await writeFile(finalPath, content);
790
- }
791
- async function walkDir(dirPath, callback) {
792
- const entries = await fs.readdir(dirPath, { withFileTypes: true });
793
- for (const entry of entries) {
794
- const fullPath = path.join(dirPath, entry.name);
795
- const isDir = entry.isDirectory();
796
- await callback(fullPath, isDir);
797
- if (isDir) {
798
- await walkDir(fullPath, callback);
799
- }
800
- }
801
- }
802
- function getTemplateDir() {
803
- const devPath = path.join(import.meta.dirname, "..", "templates");
804
- const prodPath = path.join(import.meta.dirname, "..", "..", "templates");
805
- if (fs.existsSync(devPath)) {
806
- return devPath;
807
- }
808
- return prodPath;
809
- }
810
- function resolveOutputPath(basePath, ...segments) {
811
- return path.resolve(basePath, ...segments);
812
- }
813
-
814
1345
  // src/utils/git.ts
815
- import { execa } from "execa";
816
- import path2 from "path";
1346
+ import { execa as execa2 } from "execa";
1347
+ import path5 from "path";
817
1348
  async function isGitInstalled() {
818
1349
  try {
819
- await execa("git", ["--version"]);
1350
+ await execa2("git", ["--version"]);
820
1351
  return true;
821
1352
  } catch {
822
1353
  return false;
823
1354
  }
824
1355
  }
825
1356
  async function initGitRepository(projectPath) {
826
- const gitDir = path2.join(projectPath, ".git");
1357
+ const gitDir = path5.join(projectPath, ".git");
827
1358
  if (await exists(gitDir)) {
828
1359
  return;
829
1360
  }
830
- await execa("git", ["init"], { cwd: projectPath });
1361
+ await execa2("git", ["init"], { cwd: projectPath });
831
1362
  }
832
1363
  async function createInitialCommit(projectPath) {
833
1364
  try {
834
- await execa("git", ["add", "."], { cwd: projectPath });
835
- await execa("git", ["commit", "-m", "Initial commit from create-mcp-server"], {
1365
+ await execa2("git", ["add", "."], { cwd: projectPath });
1366
+ await execa2("git", ["commit", "-m", "Initial commit from create-mcp-server"], {
836
1367
  cwd: projectPath
837
1368
  });
838
1369
  } catch {
@@ -841,8 +1372,8 @@ async function createInitialCommit(projectPath) {
841
1372
  async function getGitUser() {
842
1373
  try {
843
1374
  const [nameResult, emailResult] = await Promise.all([
844
- execa("git", ["config", "--get", "user.name"]).catch(() => ({ stdout: "" })),
845
- execa("git", ["config", "--get", "user.email"]).catch(() => ({ stdout: "" }))
1375
+ execa2("git", ["config", "--get", "user.name"]).catch(() => ({ stdout: "" })),
1376
+ execa2("git", ["config", "--get", "user.email"]).catch(() => ({ stdout: "" }))
846
1377
  ]);
847
1378
  return {
848
1379
  name: nameResult.stdout.trim() || void 0,
@@ -854,7 +1385,7 @@ async function getGitUser() {
854
1385
  }
855
1386
  async function isInsideGitRepository(dirPath) {
856
1387
  try {
857
- await execa("git", ["rev-parse", "--is-inside-work-tree"], { cwd: dirPath });
1388
+ await execa2("git", ["rev-parse", "--is-inside-work-tree"], { cwd: dirPath });
858
1389
  return true;
859
1390
  } catch {
860
1391
  return false;
@@ -903,30 +1434,55 @@ var logger = {
903
1434
  });
904
1435
  console.log(chalk.green("\u2514\u2500"));
905
1436
  },
906
- nextSteps: (projectName, language) => {
1437
+ nextSteps: (projectName, language, javaBuildTool) => {
907
1438
  logger.blank();
908
1439
  let installCmd;
909
1440
  let runCmd;
910
- switch (language) {
911
- case "typescript":
912
- installCmd = "npm install";
913
- runCmd = "npm run dev";
914
- break;
915
- case "python":
916
- installCmd = "pip install -e .";
917
- runCmd = "python -m src.server";
918
- break;
919
- case "go":
920
- installCmd = "go mod download";
921
- runCmd = "go run ./cmd/server";
922
- break;
923
- case "rust":
924
- installCmd = "cargo build";
925
- runCmd = "cargo run";
926
- break;
927
- default:
928
- installCmd = "npm install";
929
- runCmd = "npm run dev";
1441
+ if (!isBuiltinLanguage(language)) {
1442
+ const pluginInstallCmd = pluginRegistry.getPluginInstallCommand(language);
1443
+ const pluginRunCmd = pluginRegistry.getPluginRunCommand(language);
1444
+ installCmd = pluginInstallCmd || "# See plugin documentation for install command";
1445
+ runCmd = pluginRunCmd || "# See plugin documentation for run command";
1446
+ } else {
1447
+ switch (language) {
1448
+ case "typescript":
1449
+ installCmd = "npm install";
1450
+ runCmd = "npm run dev";
1451
+ break;
1452
+ case "python":
1453
+ installCmd = "pip install -e .";
1454
+ runCmd = "python -m src.server";
1455
+ break;
1456
+ case "go":
1457
+ installCmd = "go mod download";
1458
+ runCmd = "go run ./cmd/server";
1459
+ break;
1460
+ case "rust":
1461
+ installCmd = "cargo build";
1462
+ runCmd = "cargo run";
1463
+ break;
1464
+ case "java":
1465
+ case "kotlin":
1466
+ if (javaBuildTool === "gradle") {
1467
+ installCmd = "./gradlew build";
1468
+ runCmd = "./gradlew run";
1469
+ } else {
1470
+ installCmd = "mvn install";
1471
+ runCmd = 'mvn exec:java -Dexec.mainClass="com.example.mcp.McpServer"';
1472
+ }
1473
+ break;
1474
+ case "csharp":
1475
+ installCmd = "dotnet restore";
1476
+ runCmd = "dotnet run";
1477
+ break;
1478
+ case "elixir":
1479
+ installCmd = "mix deps.get";
1480
+ runCmd = "mix run --no-halt";
1481
+ break;
1482
+ default:
1483
+ installCmd = "npm install";
1484
+ runCmd = "npm run dev";
1485
+ }
930
1486
  }
931
1487
  logger.box("Next steps:", [
932
1488
  "",
@@ -995,8 +1551,8 @@ async function withSpinner(text, fn, successText, failText) {
995
1551
  }
996
1552
 
997
1553
  // src/generators/base.ts
998
- import path3 from "path";
999
- import { execa as execa2 } from "execa";
1554
+ import path6 from "path";
1555
+ import { execa as execa3 } from "execa";
1000
1556
  var BaseGenerator = class {
1001
1557
  config;
1002
1558
  outputDir;
@@ -1008,14 +1564,14 @@ var BaseGenerator = class {
1008
1564
  }
1009
1565
  async createProjectStructure() {
1010
1566
  await ensureDir(this.outputDir);
1011
- await ensureDir(path3.join(this.outputDir, "src"));
1567
+ await ensureDir(path6.join(this.outputDir, "src"));
1012
1568
  }
1013
1569
  async renderTemplates() {
1014
1570
  const templateData = this.getTemplateData();
1015
1571
  await walkDir(this.templateDir, async (filePath, isDir) => {
1016
1572
  if (isDir) return;
1017
- const relativePath = path3.relative(this.templateDir, filePath);
1018
- const outputPath = path3.join(this.outputDir, relativePath);
1573
+ const relativePath = path6.relative(this.templateDir, filePath);
1574
+ const outputPath = path6.join(this.outputDir, relativePath);
1019
1575
  if (filePath.endsWith(".ejs")) {
1020
1576
  await renderTemplateToFile(filePath, outputPath, templateData);
1021
1577
  } else {
@@ -1024,6 +1580,8 @@ var BaseGenerator = class {
1024
1580
  });
1025
1581
  }
1026
1582
  getTemplateData() {
1583
+ const cleanName = this.config.name.replace(/[^a-zA-Z0-9]/g, "");
1584
+ const capitalizedName = cleanName.charAt(0).toUpperCase() + cleanName.slice(1);
1027
1585
  return {
1028
1586
  name: this.config.name,
1029
1587
  description: this.config.description,
@@ -1031,7 +1589,12 @@ var BaseGenerator = class {
1031
1589
  transport: this.config.transport,
1032
1590
  tools: this.config.tools,
1033
1591
  resources: this.config.resources,
1034
- includeExampleTool: this.config.includeExampleTool
1592
+ includeExampleTool: this.config.includeExampleTool,
1593
+ javaBuildTool: this.config.javaBuildTool,
1594
+ // Helper for Java/Elixir package name (lowercase, no special chars)
1595
+ packageName: this.config.name.toLowerCase().replace(/[^a-z0-9]/g, ""),
1596
+ // Helper for C#/Elixir namespace (PascalCase)
1597
+ namespace: capitalizedName
1035
1598
  };
1036
1599
  }
1037
1600
  async installDependencies() {
@@ -1039,6 +1602,10 @@ var BaseGenerator = class {
1039
1602
  logger.info("Skipping dependency installation (--skip-install)");
1040
1603
  return;
1041
1604
  }
1605
+ if (!isBuiltinLanguage(this.config.language)) {
1606
+ await this.installPluginDependencies();
1607
+ return;
1608
+ }
1042
1609
  switch (this.config.language) {
1043
1610
  case "typescript":
1044
1611
  await this.installNodeDependencies();
@@ -1052,13 +1619,39 @@ var BaseGenerator = class {
1052
1619
  case "rust":
1053
1620
  await this.installRustDependencies();
1054
1621
  break;
1622
+ case "java":
1623
+ case "kotlin":
1624
+ await this.installJavaDependencies();
1625
+ break;
1626
+ case "csharp":
1627
+ await this.installDotnetDependencies();
1628
+ break;
1629
+ case "elixir":
1630
+ await this.installElixirDependencies();
1631
+ break;
1632
+ }
1633
+ }
1634
+ async installPluginDependencies() {
1635
+ const installCommand = pluginRegistry.getPluginInstallCommand(this.config.language);
1636
+ if (!installCommand) {
1637
+ logger.info(`No install command defined for plugin language: ${this.config.language}`);
1638
+ return;
1055
1639
  }
1640
+ await withSpinner(
1641
+ "Installing dependencies...",
1642
+ async () => {
1643
+ const [cmd, ...args] = installCommand.split(" ");
1644
+ await execa3(cmd, args, { cwd: this.outputDir });
1645
+ },
1646
+ "Dependencies installed",
1647
+ "Failed to install dependencies"
1648
+ );
1056
1649
  }
1057
1650
  async installNodeDependencies() {
1058
1651
  await withSpinner(
1059
1652
  "Installing dependencies...",
1060
1653
  async () => {
1061
- await execa2("npm", ["install"], { cwd: this.outputDir });
1654
+ await execa3("npm", ["install"], { cwd: this.outputDir });
1062
1655
  },
1063
1656
  "Dependencies installed",
1064
1657
  "Failed to install dependencies"
@@ -1076,7 +1669,7 @@ var BaseGenerator = class {
1076
1669
  await withSpinner(
1077
1670
  "Installing dependencies...",
1078
1671
  async () => {
1079
- await execa2(pipCommand, ["install", "-r", "requirements.txt"], {
1672
+ await execa3(pipCommand, ["install", "-r", "requirements.txt"], {
1080
1673
  cwd: this.outputDir
1081
1674
  });
1082
1675
  },
@@ -1094,10 +1687,10 @@ var BaseGenerator = class {
1094
1687
  await withSpinner(
1095
1688
  "Installing Go dependencies...",
1096
1689
  async () => {
1097
- await execa2("go", ["mod", "download"], {
1690
+ await execa3("go", ["mod", "download"], {
1098
1691
  cwd: this.outputDir
1099
1692
  });
1100
- await execa2("go", ["mod", "tidy"], {
1693
+ await execa3("go", ["mod", "tidy"], {
1101
1694
  cwd: this.outputDir
1102
1695
  });
1103
1696
  },
@@ -1115,7 +1708,7 @@ var BaseGenerator = class {
1115
1708
  await withSpinner(
1116
1709
  "Building Rust project...",
1117
1710
  async () => {
1118
- await execa2("cargo", ["build"], {
1711
+ await execa3("cargo", ["build"], {
1119
1712
  cwd: this.outputDir
1120
1713
  });
1121
1714
  },
@@ -1123,10 +1716,92 @@ var BaseGenerator = class {
1123
1716
  "Failed to build project"
1124
1717
  );
1125
1718
  }
1719
+ async installJavaDependencies() {
1720
+ const buildTool = this.config.javaBuildTool || "maven";
1721
+ if (buildTool === "maven") {
1722
+ const hasMvn = await this.checkCommand("mvn");
1723
+ if (!hasMvn) {
1724
+ logger.warning("Maven not found. Please install dependencies manually:");
1725
+ logger.code("mvn install");
1726
+ return;
1727
+ }
1728
+ await withSpinner(
1729
+ "Installing Maven dependencies...",
1730
+ async () => {
1731
+ await execa3("mvn", ["install", "-DskipTests"], {
1732
+ cwd: this.outputDir
1733
+ });
1734
+ },
1735
+ "Dependencies installed",
1736
+ "Failed to install dependencies"
1737
+ );
1738
+ } else {
1739
+ const hasGradle = await this.checkCommand("gradle");
1740
+ const hasGradlew = await exists(path6.join(this.outputDir, "gradlew"));
1741
+ if (!hasGradle && !hasGradlew) {
1742
+ logger.warning("Gradle not found. Please install dependencies manually:");
1743
+ logger.code("gradle build");
1744
+ return;
1745
+ }
1746
+ const gradleCmd = hasGradlew ? "./gradlew" : "gradle";
1747
+ await withSpinner(
1748
+ "Installing Gradle dependencies...",
1749
+ async () => {
1750
+ await execa3(gradleCmd, ["build", "-x", "test"], {
1751
+ cwd: this.outputDir
1752
+ });
1753
+ },
1754
+ "Dependencies installed",
1755
+ "Failed to install dependencies"
1756
+ );
1757
+ }
1758
+ }
1759
+ async installDotnetDependencies() {
1760
+ const hasDotnet = await this.checkCommand("dotnet");
1761
+ if (!hasDotnet) {
1762
+ logger.warning(".NET SDK not found. Please install dependencies manually:");
1763
+ logger.code("dotnet restore");
1764
+ return;
1765
+ }
1766
+ await withSpinner(
1767
+ "Restoring .NET dependencies...",
1768
+ async () => {
1769
+ await execa3("dotnet", ["restore"], {
1770
+ cwd: this.outputDir
1771
+ });
1772
+ await execa3("dotnet", ["build"], {
1773
+ cwd: this.outputDir
1774
+ });
1775
+ },
1776
+ "Dependencies installed",
1777
+ "Failed to install dependencies"
1778
+ );
1779
+ }
1780
+ async installElixirDependencies() {
1781
+ const hasMix = await this.checkCommand("mix");
1782
+ if (!hasMix) {
1783
+ logger.warning("Elixir/Mix not found. Please install dependencies manually:");
1784
+ logger.code("mix deps.get");
1785
+ return;
1786
+ }
1787
+ await withSpinner(
1788
+ "Installing Elixir dependencies...",
1789
+ async () => {
1790
+ await execa3("mix", ["deps.get"], {
1791
+ cwd: this.outputDir
1792
+ });
1793
+ await execa3("mix", ["compile"], {
1794
+ cwd: this.outputDir
1795
+ });
1796
+ },
1797
+ "Dependencies installed",
1798
+ "Failed to install dependencies"
1799
+ );
1800
+ }
1126
1801
  async checkCommand(command) {
1127
1802
  try {
1128
1803
  const checkCmd = process.platform === "win32" ? "where" : "which";
1129
- await execa2(checkCmd, [command]);
1804
+ await execa3(checkCmd, [command]);
1130
1805
  return true;
1131
1806
  } catch {
1132
1807
  return false;
@@ -1162,8 +1837,16 @@ var BaseGenerator = class {
1162
1837
  }
1163
1838
  };
1164
1839
  function createGeneratorContext(config, outputPath) {
1165
- const outputDir = outputPath || path3.resolve(process.cwd(), config.name);
1166
- const templateDir = path3.join(getTemplateDir(), config.language);
1840
+ const outputDir = outputPath || path6.resolve(process.cwd(), config.name);
1841
+ let templateDir;
1842
+ const pluginTemplateDir = pluginRegistry.getPluginTemplateDir(config.language);
1843
+ if (pluginTemplateDir) {
1844
+ templateDir = pluginTemplateDir;
1845
+ } else if ((config.language === "java" || config.language === "kotlin") && config.javaBuildTool) {
1846
+ templateDir = path6.join(getTemplateDir(), config.language, config.javaBuildTool);
1847
+ } else {
1848
+ templateDir = path6.join(getTemplateDir(), config.language);
1849
+ }
1167
1850
  return {
1168
1851
  config,
1169
1852
  outputDir,
@@ -1201,7 +1884,7 @@ var WizardGenerator = class extends BaseGenerator {
1201
1884
  await this.installDependencies();
1202
1885
  await this.initializeGit();
1203
1886
  logger.success(`Project ${this.config.name} created successfully!`);
1204
- logger.nextSteps(this.config.name, this.config.language);
1887
+ logger.nextSteps(this.config.name, this.config.language, this.config.javaBuildTool);
1205
1888
  }
1206
1889
  };
1207
1890
  async function generateFromWizard(config, outputPath) {
@@ -1212,7 +1895,7 @@ async function generateFromWizard(config, outputPath) {
1212
1895
 
1213
1896
  // src/parsers/openapi.ts
1214
1897
  import YAML from "yaml";
1215
- import inquirer8 from "inquirer";
1898
+ import inquirer10 from "inquirer";
1216
1899
  async function parseOpenAPISpec(content) {
1217
1900
  let spec;
1218
1901
  try {
@@ -1224,18 +1907,18 @@ async function parseOpenAPISpec(content) {
1224
1907
  throw new Error('Invalid OpenAPI specification. Missing "openapi" or "swagger" field.');
1225
1908
  }
1226
1909
  const endpoints = [];
1227
- for (const [path7, pathItem] of Object.entries(spec.paths)) {
1910
+ for (const [path11, pathItem] of Object.entries(spec.paths)) {
1228
1911
  const methods = ["get", "post", "put", "delete", "patch", "options", "head"];
1229
1912
  for (const method of methods) {
1230
1913
  const operation = pathItem[method];
1231
1914
  if (!operation) continue;
1232
- const endpoint = parseOperation(path7, method, operation, spec);
1915
+ const endpoint = parseOperation(path11, method, operation, spec);
1233
1916
  endpoints.push(endpoint);
1234
1917
  }
1235
1918
  }
1236
1919
  return endpoints;
1237
1920
  }
1238
- function parseOperation(path7, method, operation, spec) {
1921
+ function parseOperation(path11, method, operation, spec) {
1239
1922
  const parameters = [];
1240
1923
  if (operation.parameters) {
1241
1924
  for (const param of operation.parameters) {
@@ -1259,7 +1942,7 @@ function parseOperation(path7, method, operation, spec) {
1259
1942
  }
1260
1943
  }
1261
1944
  return {
1262
- path: path7,
1945
+ path: path11,
1263
1946
  method: method.toUpperCase(),
1264
1947
  operationId: operation.operationId || "",
1265
1948
  summary: operation.summary || "",
@@ -1312,7 +1995,7 @@ async function selectEndpoints(endpoints) {
1312
1995
  value: ep,
1313
1996
  checked: true
1314
1997
  }));
1315
- const { selected } = await inquirer8.prompt([
1998
+ const { selected } = await inquirer10.prompt([
1316
1999
  {
1317
2000
  type: "checkbox",
1318
2001
  name: "selected",
@@ -1359,9 +2042,7 @@ var OpenAPIGenerator = class extends BaseGenerator {
1359
2042
  logger.title(`Creating ${this.config.name} from OpenAPI`);
1360
2043
  const isSafe = await this.checkOutputDir();
1361
2044
  if (!isSafe) {
1362
- throw new Error(
1363
- `Directory ${this.outputDir} already exists and is not empty.`
1364
- );
2045
+ throw new Error(`Directory ${this.outputDir} already exists and is not empty.`);
1365
2046
  }
1366
2047
  await withSpinner(
1367
2048
  "Creating project structure...",
@@ -1381,7 +2062,7 @@ var OpenAPIGenerator = class extends BaseGenerator {
1381
2062
  await this.initializeGit();
1382
2063
  logger.success(`Project ${this.config.name} created successfully!`);
1383
2064
  logger.info(`Generated ${this.config.tools.length} tools from OpenAPI spec`);
1384
- logger.nextSteps(this.config.name, this.config.language);
2065
+ logger.nextSteps(this.config.name, this.config.language, this.config.javaBuildTool);
1385
2066
  }
1386
2067
  setEndpoints(endpoints) {
1387
2068
  this._endpoints = endpoints;
@@ -1415,7 +2096,8 @@ async function generateFromOpenAPI(specPath, baseConfig) {
1415
2096
  resources: [],
1416
2097
  includeExampleTool: false,
1417
2098
  skipInstall: baseConfig.skipInstall || false,
1418
- initGit: baseConfig.initGit !== false
2099
+ initGit: baseConfig.initGit !== false,
2100
+ javaBuildTool: baseConfig.javaBuildTool
1419
2101
  };
1420
2102
  const context = createGeneratorContext(config);
1421
2103
  const generator = new OpenAPIGenerator(context);
@@ -1448,7 +2130,7 @@ function mapOpenAPIType(type) {
1448
2130
 
1449
2131
  // src/generators/from-prompt.ts
1450
2132
  import Anthropic from "@anthropic-ai/sdk";
1451
- import inquirer9 from "inquirer";
2133
+ import inquirer11 from "inquirer";
1452
2134
  var SYSTEM_PROMPT = `You are an expert at designing MCP (Model Context Protocol) servers.
1453
2135
  Given a description of an API or functionality, you generate a list of tools that would be useful for that API.
1454
2136
 
@@ -1480,9 +2162,7 @@ var PromptGenerator = class extends BaseGenerator {
1480
2162
  logger.title(`Creating ${this.config.name}`);
1481
2163
  const isSafe = await this.checkOutputDir();
1482
2164
  if (!isSafe) {
1483
- throw new Error(
1484
- `Directory ${this.outputDir} already exists and is not empty.`
1485
- );
2165
+ throw new Error(`Directory ${this.outputDir} already exists and is not empty.`);
1486
2166
  }
1487
2167
  await withSpinner(
1488
2168
  "Creating project structure...",
@@ -1502,11 +2182,11 @@ var PromptGenerator = class extends BaseGenerator {
1502
2182
  await this.initializeGit();
1503
2183
  logger.success(`Project ${this.config.name} created successfully!`);
1504
2184
  logger.info(`Generated ${this.config.tools.length} tools from your description`);
1505
- logger.nextSteps(this.config.name, this.config.language);
2185
+ logger.nextSteps(this.config.name, this.config.language, this.config.javaBuildTool);
1506
2186
  }
1507
2187
  };
1508
2188
  async function generateFromPrompt(baseConfig) {
1509
- const { description } = await inquirer9.prompt([
2189
+ const { description } = await inquirer11.prompt([
1510
2190
  {
1511
2191
  type: "editor",
1512
2192
  name: "description",
@@ -1562,7 +2242,7 @@ async function generateFromPrompt(baseConfig) {
1562
2242
  logger.list([`${index + 1}. ${tool.name} - ${tool.description}`]);
1563
2243
  });
1564
2244
  logger.blank();
1565
- const { confirm } = await inquirer9.prompt([
2245
+ const { confirm } = await inquirer11.prompt([
1566
2246
  {
1567
2247
  type: "confirm",
1568
2248
  name: "confirm",
@@ -1582,7 +2262,8 @@ async function generateFromPrompt(baseConfig) {
1582
2262
  resources: [],
1583
2263
  includeExampleTool: false,
1584
2264
  skipInstall: baseConfig.skipInstall || false,
1585
- initGit: baseConfig.initGit !== false
2265
+ initGit: baseConfig.initGit !== false,
2266
+ javaBuildTool: baseConfig.javaBuildTool
1586
2267
  };
1587
2268
  const context = createGeneratorContext(config);
1588
2269
  const generator = new PromptGenerator(context);
@@ -1623,17 +2304,32 @@ var PresetGenerator = class extends BaseGenerator {
1623
2304
  logger.success(`Project ${this.config.name} created successfully!`);
1624
2305
  logger.info(`Preset: ${this.presetName}`);
1625
2306
  logger.info(`Tools included: ${this.config.tools.map((t) => t.name).join(", ")}`);
1626
- logger.nextSteps(this.config.name, this.config.language);
2307
+ logger.nextSteps(this.config.name, this.config.language, this.config.javaBuildTool);
1627
2308
  }
1628
2309
  };
1629
2310
  async function generateFromPreset(options) {
1630
- const preset = getPreset(options.presetId);
1631
- if (!preset) {
1632
- throw new Error(`Invalid preset: ${options.presetId}`);
2311
+ let preset;
2312
+ if (isExternalPreset(options.presetId)) {
2313
+ logger.info(`Fetching external preset: ${options.presetId}...`);
2314
+ preset = await withSpinner(
2315
+ "Resolving external preset...",
2316
+ async () => await getPresetByIdentifier(options.presetId),
2317
+ "Preset resolved",
2318
+ "Failed to resolve preset"
2319
+ );
2320
+ } else {
2321
+ preset = getPreset(options.presetId);
2322
+ if (!preset) {
2323
+ throw new Error(`Invalid preset: ${options.presetId}`);
2324
+ }
1633
2325
  }
1634
2326
  const name = options.projectName || await promptProjectName();
1635
2327
  const description = options.useDefaults ? "" : await promptProjectDescription();
1636
2328
  const language = options.language || (options.useDefaults ? "typescript" : await promptLanguage());
2329
+ let javaBuildTool;
2330
+ if (language === "java" || language === "kotlin") {
2331
+ javaBuildTool = options.javaBuildTool || (options.useDefaults ? "maven" : await promptJavaBuildTool());
2332
+ }
1637
2333
  const transport = options.useDefaults ? "stdio" : await promptTransport();
1638
2334
  const config = {
1639
2335
  name,
@@ -1644,24 +2340,221 @@ async function generateFromPreset(options) {
1644
2340
  resources: [],
1645
2341
  includeExampleTool: false,
1646
2342
  skipInstall: options.skipInstall || false,
1647
- initGit: true
2343
+ initGit: true,
2344
+ javaBuildTool
1648
2345
  };
1649
2346
  const context = createGeneratorContext(config);
1650
2347
  const generator = new PresetGenerator(context, preset.name);
1651
2348
  await generator.generate();
2349
+ return config;
1652
2350
  }
1653
2351
  function validatePresetId(presetId) {
1654
2352
  if (!isValidPresetId(presetId)) {
1655
2353
  const validPresets = ["database", "rest-api", "filesystem"];
1656
- throw new Error(
1657
- `Invalid preset "${presetId}". Valid presets are: ${validPresets.join(", ")}`
1658
- );
2354
+ throw new Error(`Invalid preset "${presetId}". Valid presets are: ${validPresets.join(", ")}`);
1659
2355
  }
1660
2356
  return true;
1661
2357
  }
1662
2358
 
1663
2359
  // src/commands/create.ts
1664
- import path4 from "path";
2360
+ import path8 from "path";
2361
+
2362
+ // src/types/ci.ts
2363
+ import { z as z4 } from "zod";
2364
+ var CIProviderSchema = z4.enum(["github", "gitlab", "circleci"]);
2365
+ var CI_PROVIDERS = ["github", "gitlab", "circleci"];
2366
+ function isValidCIProvider(provider) {
2367
+ return CI_PROVIDERS.includes(provider);
2368
+ }
2369
+
2370
+ // src/generators/ci.ts
2371
+ import path7 from "path";
2372
+
2373
+ // src/ci/language-config.ts
2374
+ var LANGUAGE_CI_CONFIG = {
2375
+ typescript: {
2376
+ installCommand: "npm ci",
2377
+ buildCommand: "npm run build",
2378
+ testCommand: "npm test",
2379
+ nodeVersion: "20"
2380
+ },
2381
+ python: {
2382
+ installCommand: "pip install -r requirements.txt",
2383
+ testCommand: "pytest",
2384
+ pythonVersion: "3.11"
2385
+ },
2386
+ go: {
2387
+ installCommand: "go mod download",
2388
+ buildCommand: "go build ./...",
2389
+ testCommand: "go test ./...",
2390
+ goVersion: "1.21"
2391
+ },
2392
+ rust: {
2393
+ installCommand: "cargo fetch",
2394
+ buildCommand: "cargo build --release",
2395
+ testCommand: "cargo test",
2396
+ rustVersion: "stable"
2397
+ },
2398
+ java: {
2399
+ installCommand: "mvn install -DskipTests",
2400
+ buildCommand: "mvn package -DskipTests",
2401
+ testCommand: "mvn test",
2402
+ javaVersion: "21"
2403
+ },
2404
+ kotlin: {
2405
+ installCommand: "mvn install -DskipTests",
2406
+ buildCommand: "mvn package -DskipTests",
2407
+ testCommand: "mvn test",
2408
+ javaVersion: "21"
2409
+ },
2410
+ csharp: {
2411
+ installCommand: "dotnet restore",
2412
+ buildCommand: "dotnet build --configuration Release",
2413
+ testCommand: "dotnet test",
2414
+ dotnetVersion: "8.0"
2415
+ },
2416
+ elixir: {
2417
+ installCommand: "mix deps.get",
2418
+ buildCommand: "mix compile",
2419
+ testCommand: "mix test",
2420
+ elixirVersion: "1.15"
2421
+ }
2422
+ };
2423
+ function getJavaCIConfig(buildTool) {
2424
+ if (buildTool === "gradle") {
2425
+ return {
2426
+ installCommand: "./gradlew dependencies",
2427
+ buildCommand: "./gradlew build -x test",
2428
+ testCommand: "./gradlew test",
2429
+ javaVersion: "21"
2430
+ };
2431
+ }
2432
+ return LANGUAGE_CI_CONFIG.java;
2433
+ }
2434
+ function getCITemplateContext(projectName, language, javaBuildTool) {
2435
+ const config = (language === "java" || language === "kotlin") && javaBuildTool === "gradle" ? getJavaCIConfig("gradle") : LANGUAGE_CI_CONFIG[language];
2436
+ return {
2437
+ projectName,
2438
+ language,
2439
+ ...config
2440
+ };
2441
+ }
2442
+
2443
+ // src/generators/ci.ts
2444
+ var CIGenerator = class {
2445
+ options;
2446
+ templateDir;
2447
+ context;
2448
+ constructor(options) {
2449
+ this.options = options;
2450
+ this.templateDir = path7.join(getTemplateDir(), "ci", options.provider);
2451
+ this.context = getCITemplateContext(
2452
+ options.projectName || path7.basename(options.projectDir),
2453
+ options.language,
2454
+ options.javaBuildTool
2455
+ );
2456
+ }
2457
+ async generate() {
2458
+ await withSpinner(
2459
+ `Generating ${this.getProviderName()} CI configuration...`,
2460
+ async () => {
2461
+ switch (this.options.provider) {
2462
+ case "github":
2463
+ await this.generateGitHubActions();
2464
+ break;
2465
+ case "gitlab":
2466
+ await this.generateGitLabCI();
2467
+ break;
2468
+ case "circleci":
2469
+ await this.generateCircleCI();
2470
+ break;
2471
+ }
2472
+ },
2473
+ `${this.getProviderName()} CI configuration generated`,
2474
+ `Failed to generate ${this.getProviderName()} CI configuration`
2475
+ );
2476
+ }
2477
+ async generateGitHubActions() {
2478
+ const workflowDir = path7.join(this.options.projectDir, ".github", "workflows");
2479
+ await ensureDir(workflowDir);
2480
+ const templatePath = path7.join(this.templateDir, "ci.yml.ejs");
2481
+ const outputPath = path7.join(workflowDir, "ci.yml");
2482
+ await renderTemplateToFile(templatePath, outputPath, this.context);
2483
+ }
2484
+ async generateGitLabCI() {
2485
+ const templatePath = path7.join(this.templateDir, ".gitlab-ci.yml.ejs");
2486
+ const outputPath = path7.join(this.options.projectDir, ".gitlab-ci.yml");
2487
+ await renderTemplateToFile(templatePath, outputPath, this.context);
2488
+ }
2489
+ async generateCircleCI() {
2490
+ const circleDir = path7.join(this.options.projectDir, ".circleci");
2491
+ await ensureDir(circleDir);
2492
+ const templatePath = path7.join(this.templateDir, "config.yml.ejs");
2493
+ const outputPath = path7.join(circleDir, "config.yml");
2494
+ await renderTemplateToFile(templatePath, outputPath, this.context);
2495
+ }
2496
+ getProviderName() {
2497
+ switch (this.options.provider) {
2498
+ case "github":
2499
+ return "GitHub Actions";
2500
+ case "gitlab":
2501
+ return "GitLab CI";
2502
+ case "circleci":
2503
+ return "CircleCI";
2504
+ }
2505
+ }
2506
+ };
2507
+ async function generateCI(options) {
2508
+ const generator = new CIGenerator(options);
2509
+ await generator.generate();
2510
+ }
2511
+ async function detectLanguageFromProject(projectDir) {
2512
+ const checks = [
2513
+ { file: "package.json", language: "typescript" },
2514
+ { file: "pyproject.toml", language: "python" },
2515
+ { file: "requirements.txt", language: "python" },
2516
+ { file: "go.mod", language: "go" },
2517
+ { file: "Cargo.toml", language: "rust" },
2518
+ { file: "pom.xml", language: "java" },
2519
+ { file: "build.gradle", language: "java" },
2520
+ { file: "build.gradle.kts", language: "kotlin" },
2521
+ { file: "*.csproj", language: "csharp" },
2522
+ { file: "mix.exs", language: "elixir" }
2523
+ ];
2524
+ for (const check of checks) {
2525
+ if (await exists(path7.join(projectDir, check.file))) {
2526
+ return check.language;
2527
+ }
2528
+ }
2529
+ return void 0;
2530
+ }
2531
+ async function detectJavaBuildTool(projectDir) {
2532
+ if (await exists(path7.join(projectDir, "build.gradle")) || await exists(path7.join(projectDir, "build.gradle.kts"))) {
2533
+ return "gradle";
2534
+ }
2535
+ if (await exists(path7.join(projectDir, "pom.xml"))) {
2536
+ return "maven";
2537
+ }
2538
+ return void 0;
2539
+ }
2540
+
2541
+ // src/commands/create.ts
2542
+ function getLanguageFromOptions(options) {
2543
+ if (options.typescript) return "typescript";
2544
+ if (options.python) return "python";
2545
+ if (options.go) return "go";
2546
+ if (options.rust) return "rust";
2547
+ if (options.java) return "java";
2548
+ if (options.kotlin) return "kotlin";
2549
+ if (options.csharp) return "csharp";
2550
+ if (options.elixir) return "elixir";
2551
+ return void 0;
2552
+ }
2553
+ function getJavaBuildToolFromOptions(options) {
2554
+ if (options.maven) return "maven";
2555
+ if (options.gradle) return "gradle";
2556
+ return void 0;
2557
+ }
1665
2558
  async function createCommand(projectName, options) {
1666
2559
  try {
1667
2560
  if (options.preset) {
@@ -1688,16 +2581,17 @@ async function createCommand(projectName, options) {
1688
2581
  }
1689
2582
  async function handleWizardGeneration(projectName, options) {
1690
2583
  let config;
1691
- const presetLanguage = options.typescript ? "typescript" : options.python ? "python" : options.go ? "go" : options.rust ? "rust" : void 0;
2584
+ const presetLanguage = getLanguageFromOptions(options);
2585
+ const presetJavaBuildTool = getJavaBuildToolFromOptions(options);
1692
2586
  if (options.yes) {
1693
- config = await runQuickWizard(projectName, presetLanguage);
2587
+ config = await runQuickWizard(projectName, presetLanguage, presetJavaBuildTool);
1694
2588
  } else {
1695
- config = await runWizard({ defaultName: projectName, presetLanguage });
2589
+ config = await runWizard({ defaultName: projectName, presetLanguage, presetJavaBuildTool });
1696
2590
  }
1697
2591
  if (options.skipInstall) {
1698
2592
  config.skipInstall = true;
1699
2593
  }
1700
- const outputPath = path4.resolve(process.cwd(), config.name);
2594
+ const outputPath = path8.resolve(process.cwd(), config.name);
1701
2595
  if (await exists(outputPath)) {
1702
2596
  const files = await import("fs-extra").then((m) => m.readdir(outputPath));
1703
2597
  if (files.length > 0) {
@@ -1706,6 +2600,9 @@ async function handleWizardGeneration(projectName, options) {
1706
2600
  }
1707
2601
  }
1708
2602
  await generateFromWizard(config);
2603
+ if (options.ci) {
2604
+ await handleCIGeneration(config.name, config.language, config.javaBuildTool, options.ci);
2605
+ }
1709
2606
  }
1710
2607
  async function handleOpenAPIGeneration(projectName, options) {
1711
2608
  const specPath = options.fromOpenapi;
@@ -1713,45 +2610,71 @@ async function handleOpenAPIGeneration(projectName, options) {
1713
2610
  logger.error(`OpenAPI specification file not found: ${specPath}`);
1714
2611
  process.exit(1);
1715
2612
  }
1716
- const name = projectName || path4.basename(specPath, path4.extname(specPath)) + "-mcp";
2613
+ const name = projectName || path8.basename(specPath, path8.extname(specPath)) + "-mcp";
1717
2614
  await generateFromOpenAPI(specPath, {
1718
2615
  name,
1719
- language: options.typescript ? "typescript" : options.python ? "python" : options.go ? "go" : options.rust ? "rust" : void 0,
1720
- skipInstall: options.skipInstall
2616
+ language: getLanguageFromOptions(options),
2617
+ skipInstall: options.skipInstall,
2618
+ javaBuildTool: getJavaBuildToolFromOptions(options)
1721
2619
  });
1722
2620
  }
1723
2621
  async function handlePromptGeneration(projectName, options) {
1724
2622
  await generateFromPrompt({
1725
2623
  name: projectName,
1726
- language: options.typescript ? "typescript" : options.python ? "python" : options.go ? "go" : options.rust ? "rust" : void 0,
1727
- skipInstall: options.skipInstall
2624
+ language: getLanguageFromOptions(options),
2625
+ skipInstall: options.skipInstall,
2626
+ javaBuildTool: getJavaBuildToolFromOptions(options)
1728
2627
  });
1729
2628
  }
1730
2629
  async function handlePresetGeneration(projectName, options) {
1731
2630
  const presetId = options.preset;
1732
- validatePresetId(presetId);
1733
- await generateFromPreset({
2631
+ if (!isExternalPreset(presetId) && !isValidPresetId(presetId)) {
2632
+ logger.error(
2633
+ `Invalid preset "${presetId}". Valid local presets: ${PRESET_IDS.join(", ")}
2634
+ For external presets use: @org/package or github:user/repo`
2635
+ );
2636
+ process.exit(1);
2637
+ }
2638
+ const result = await generateFromPreset({
1734
2639
  projectName,
1735
2640
  presetId,
1736
- language: options.typescript ? "typescript" : options.python ? "python" : options.go ? "go" : options.rust ? "rust" : void 0,
2641
+ language: getLanguageFromOptions(options),
1737
2642
  skipInstall: options.skipInstall,
1738
- useDefaults: options.yes
2643
+ useDefaults: options.yes,
2644
+ javaBuildTool: getJavaBuildToolFromOptions(options)
2645
+ });
2646
+ if (options.ci && result) {
2647
+ await handleCIGeneration(result.name, result.language, result.javaBuildTool, options.ci);
2648
+ }
2649
+ }
2650
+ async function handleCIGeneration(projectName, language, javaBuildTool, ciProvider) {
2651
+ if (!isValidCIProvider(ciProvider)) {
2652
+ logger.error(`Invalid CI provider: ${ciProvider}. Valid options: github, gitlab, circleci`);
2653
+ return;
2654
+ }
2655
+ const projectDir = path8.resolve(process.cwd(), projectName);
2656
+ await generateCI({
2657
+ projectDir,
2658
+ provider: ciProvider,
2659
+ language,
2660
+ javaBuildTool,
2661
+ projectName
1739
2662
  });
1740
2663
  }
1741
2664
 
1742
2665
  // src/commands/init.ts
1743
- import path5 from "path";
1744
- import inquirer10 from "inquirer";
2666
+ import path9 from "path";
2667
+ import inquirer12 from "inquirer";
1745
2668
  async function initCommand(options) {
1746
2669
  try {
1747
2670
  const currentDir = process.cwd();
1748
- const dirName = path5.basename(currentDir);
1749
- const hasPackageJson = await exists(path5.join(currentDir, "package.json"));
1750
- const hasPyproject = await exists(path5.join(currentDir, "pyproject.toml"));
1751
- const hasGoMod = await exists(path5.join(currentDir, "go.mod"));
1752
- const hasCargoToml = await exists(path5.join(currentDir, "Cargo.toml"));
2671
+ const dirName = path9.basename(currentDir);
2672
+ const hasPackageJson = await exists(path9.join(currentDir, "package.json"));
2673
+ const hasPyproject = await exists(path9.join(currentDir, "pyproject.toml"));
2674
+ const hasGoMod = await exists(path9.join(currentDir, "go.mod"));
2675
+ const hasCargoToml = await exists(path9.join(currentDir, "Cargo.toml"));
1753
2676
  if ((hasPackageJson || hasPyproject || hasGoMod || hasCargoToml) && !options.force) {
1754
- const { proceed } = await inquirer10.prompt([
2677
+ const { proceed } = await inquirer12.prompt([
1755
2678
  {
1756
2679
  type: "confirm",
1757
2680
  name: "proceed",
@@ -1793,7 +2716,7 @@ async function initCommand(options) {
1793
2716
  let projectName = dirName;
1794
2717
  if (hasPackageJson) {
1795
2718
  try {
1796
- const pkgContent = await readFile(path5.join(currentDir, "package.json"));
2719
+ const pkgContent = await readFile(path9.join(currentDir, "package.json"));
1797
2720
  const pkg = JSON.parse(pkgContent);
1798
2721
  projectName = pkg.name || dirName;
1799
2722
  } catch {
@@ -1823,14 +2746,14 @@ async function initCommand(options) {
1823
2746
  }
1824
2747
 
1825
2748
  // src/commands/add-tool.ts
1826
- import path6 from "path";
2749
+ import path10 from "path";
1827
2750
  async function addToolCommand(options) {
1828
2751
  try {
1829
2752
  const currentDir = process.cwd();
1830
- const isTypeScript = await exists(path6.join(currentDir, "package.json"));
1831
- const isPython = await exists(path6.join(currentDir, "pyproject.toml"));
1832
- const isGo = await exists(path6.join(currentDir, "go.mod"));
1833
- const isRust = await exists(path6.join(currentDir, "Cargo.toml"));
2753
+ const isTypeScript = await exists(path10.join(currentDir, "package.json"));
2754
+ const isPython = await exists(path10.join(currentDir, "pyproject.toml"));
2755
+ const isGo = await exists(path10.join(currentDir, "go.mod"));
2756
+ const isRust = await exists(path10.join(currentDir, "Cargo.toml"));
1834
2757
  if (!isTypeScript && !isPython && !isGo && !isRust) {
1835
2758
  logger.error("No MCP server project found in current directory.");
1836
2759
  logger.info("Run this command from the root of your MCP server project.");
@@ -1868,9 +2791,9 @@ async function addToolCommand(options) {
1868
2791
  }
1869
2792
  }
1870
2793
  async function addToolToTypeScript(projectDir, tool) {
1871
- const toolsDir = path6.join(projectDir, "src", "tools");
2794
+ const toolsDir = path10.join(projectDir, "src", "tools");
1872
2795
  const toolFileName = `${tool.name.replace(/_/g, "-")}.ts`;
1873
- const toolFilePath = path6.join(toolsDir, toolFileName);
2796
+ const toolFilePath = path10.join(toolsDir, toolFileName);
1874
2797
  if (await exists(toolFilePath)) {
1875
2798
  logger.error(`Tool file already exists: ${toolFilePath}`);
1876
2799
  process.exit(1);
@@ -1886,9 +2809,9 @@ async function addToolToTypeScript(projectDir, tool) {
1886
2809
  ]);
1887
2810
  }
1888
2811
  async function addToolToPython(projectDir, tool) {
1889
- const toolsDir = path6.join(projectDir, "src", "tools");
2812
+ const toolsDir = path10.join(projectDir, "src", "tools");
1890
2813
  const toolFileName = `${tool.name}.py`;
1891
- const toolFilePath = path6.join(toolsDir, toolFileName);
2814
+ const toolFilePath = path10.join(toolsDir, toolFileName);
1892
2815
  if (await exists(toolFilePath)) {
1893
2816
  logger.error(`Tool file already exists: ${toolFilePath}`);
1894
2817
  process.exit(1);
@@ -2032,9 +2955,9 @@ function mapTypeToPython(type) {
2032
2955
  }
2033
2956
  }
2034
2957
  async function addToolToGo(projectDir, tool) {
2035
- const toolsDir = path6.join(projectDir, "internal", "tools");
2958
+ const toolsDir = path10.join(projectDir, "internal", "tools");
2036
2959
  const toolFileName = `${tool.name}.go`;
2037
- const toolFilePath = path6.join(toolsDir, toolFileName);
2960
+ const toolFilePath = path10.join(toolsDir, toolFileName);
2038
2961
  if (await exists(toolFilePath)) {
2039
2962
  logger.error(`Tool file already exists: ${toolFilePath}`);
2040
2963
  process.exit(1);
@@ -2050,9 +2973,9 @@ async function addToolToGo(projectDir, tool) {
2050
2973
  ]);
2051
2974
  }
2052
2975
  async function addToolToRust(projectDir, tool) {
2053
- const srcDir = path6.join(projectDir, "src");
2976
+ const srcDir = path10.join(projectDir, "src");
2054
2977
  const toolFileName = `${tool.name}.rs`;
2055
- const toolFilePath = path6.join(srcDir, toolFileName);
2978
+ const toolFilePath = path10.join(srcDir, toolFileName);
2056
2979
  if (await exists(toolFilePath)) {
2057
2980
  logger.error(`Tool file already exists: ${toolFilePath}`);
2058
2981
  process.exit(1);
@@ -2200,6 +3123,7 @@ function mapTypeToRust(type) {
2200
3123
  }
2201
3124
 
2202
3125
  export {
3126
+ isValidCIProvider,
2203
3127
  projectNameRegex,
2204
3128
  validateProjectName,
2205
3129
  validateToolName,
@@ -2209,20 +3133,6 @@ export {
2209
3133
  safeParseAndValidate,
2210
3134
  promptProjectName,
2211
3135
  promptProjectDescription,
2212
- promptLanguage,
2213
- promptTransport,
2214
- promptIncludeExampleTool,
2215
- promptAddTools,
2216
- promptToolConfig,
2217
- promptMultipleTools,
2218
- promptAddResources,
2219
- promptResourceConfig,
2220
- promptMultipleResources,
2221
- promptGenerationMethod,
2222
- PRESETS,
2223
- promptPreset,
2224
- runWizard,
2225
- runQuickWizard,
2226
3136
  ensureDir,
2227
3137
  writeFile,
2228
3138
  readFile,
@@ -2236,7 +3146,39 @@ export {
2236
3146
  renderTemplateToFile,
2237
3147
  walkDir,
2238
3148
  getTemplateDir,
3149
+ getTemplateDirForLanguage,
2239
3150
  resolveOutputPath,
3151
+ pluginRegistry,
3152
+ promptLanguage,
3153
+ promptTransport,
3154
+ promptIncludeExampleTool,
3155
+ promptAddTools,
3156
+ promptToolConfig,
3157
+ promptMultipleTools,
3158
+ promptAddResources,
3159
+ promptResourceConfig,
3160
+ promptMultipleResources,
3161
+ promptJavaBuildTool,
3162
+ promptGenerationMethod,
3163
+ BuiltinLanguageSchema,
3164
+ LanguageSchema,
3165
+ BUILTIN_LANGUAGES,
3166
+ isBuiltinLanguage,
3167
+ JavaBuildToolSchema,
3168
+ TransportSchema,
3169
+ ToolParameterSchema,
3170
+ ToolConfigSchema,
3171
+ ResourceConfigSchema,
3172
+ ProjectConfigSchema,
3173
+ PresetIdSchema,
3174
+ clearPresetCache,
3175
+ listCachedPresets,
3176
+ getCacheDir,
3177
+ PRESETS,
3178
+ promptPreset,
3179
+ promptCIProvider,
3180
+ runWizard,
3181
+ runQuickWizard,
2240
3182
  isGitInstalled,
2241
3183
  initGitRepository,
2242
3184
  createInitialCommit,
@@ -2259,6 +3201,9 @@ export {
2259
3201
  PresetGenerator,
2260
3202
  generateFromPreset,
2261
3203
  validatePresetId,
3204
+ generateCI,
3205
+ detectLanguageFromProject,
3206
+ detectJavaBuildTool,
2262
3207
  createCommand,
2263
3208
  initCommand,
2264
3209
  addToolCommand