mcp-new 0.1.0 → 1.2.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.
@@ -100,7 +100,9 @@ async function promptLanguage() {
100
100
  message: "Select language:",
101
101
  choices: [
102
102
  { name: "TypeScript", value: "typescript" },
103
- { name: "Python", value: "python" }
103
+ { name: "Python", value: "python" },
104
+ { name: "Go", value: "go" },
105
+ { name: "Rust", value: "rust" }
104
106
  ],
105
107
  default: "typescript"
106
108
  }
@@ -312,6 +314,381 @@ async function promptMultipleResources() {
312
314
  return resources;
313
315
  }
314
316
 
317
+ // src/prompts/generation-method.ts
318
+ import inquirer6 from "inquirer";
319
+ async function promptGenerationMethod() {
320
+ const { method } = await inquirer6.prompt([
321
+ {
322
+ type: "list",
323
+ name: "method",
324
+ message: "How would you like to create your MCP server?",
325
+ choices: [
326
+ {
327
+ name: "From scratch (wizard)",
328
+ value: "wizard"
329
+ },
330
+ {
331
+ name: "From a preset template",
332
+ value: "preset"
333
+ },
334
+ {
335
+ name: "From OpenAPI/Swagger specification",
336
+ value: "openapi"
337
+ },
338
+ {
339
+ name: "Using AI (describe your API)",
340
+ value: "prompt"
341
+ }
342
+ ],
343
+ default: "wizard"
344
+ }
345
+ ]);
346
+ return method;
347
+ }
348
+
349
+ // src/prompts/preset.ts
350
+ import inquirer7 from "inquirer";
351
+
352
+ // src/presets/database.ts
353
+ var DATABASE_PRESET = {
354
+ id: "database",
355
+ name: "Database CRUD",
356
+ description: "Tools for database operations: query, insert, update, delete",
357
+ tools: [
358
+ {
359
+ name: "query",
360
+ description: "Execute a SQL query on the database",
361
+ parameters: [
362
+ {
363
+ name: "sql",
364
+ type: "string",
365
+ description: "SQL query to execute",
366
+ required: true
367
+ },
368
+ {
369
+ name: "params",
370
+ type: "array",
371
+ description: "Query parameters for prepared statements",
372
+ required: false
373
+ }
374
+ ]
375
+ },
376
+ {
377
+ name: "insert",
378
+ description: "Insert a new record into a table",
379
+ parameters: [
380
+ {
381
+ name: "table",
382
+ type: "string",
383
+ description: "Table name",
384
+ required: true
385
+ },
386
+ {
387
+ name: "data",
388
+ type: "object",
389
+ description: "Record data as key-value pairs",
390
+ required: true
391
+ }
392
+ ]
393
+ },
394
+ {
395
+ name: "update",
396
+ description: "Update records in a table",
397
+ parameters: [
398
+ {
399
+ name: "table",
400
+ type: "string",
401
+ description: "Table name",
402
+ required: true
403
+ },
404
+ {
405
+ name: "data",
406
+ type: "object",
407
+ description: "Fields to update as key-value pairs",
408
+ required: true
409
+ },
410
+ {
411
+ name: "where",
412
+ type: "object",
413
+ description: "WHERE conditions as key-value pairs",
414
+ required: true
415
+ }
416
+ ]
417
+ },
418
+ {
419
+ name: "delete",
420
+ description: "Delete records from a table",
421
+ parameters: [
422
+ {
423
+ name: "table",
424
+ type: "string",
425
+ description: "Table name",
426
+ required: true
427
+ },
428
+ {
429
+ name: "where",
430
+ type: "object",
431
+ description: "WHERE conditions as key-value pairs",
432
+ required: true
433
+ }
434
+ ]
435
+ },
436
+ {
437
+ name: "list_tables",
438
+ description: "List all tables in the database",
439
+ parameters: []
440
+ }
441
+ ]
442
+ };
443
+
444
+ // src/presets/rest-api.ts
445
+ var REST_API_PRESET = {
446
+ id: "rest-api",
447
+ name: "REST API Wrapper",
448
+ description: "Tools for making HTTP requests: GET, POST, PUT, DELETE",
449
+ tools: [
450
+ {
451
+ name: "http_get",
452
+ description: "Make an HTTP GET request",
453
+ parameters: [
454
+ {
455
+ name: "url",
456
+ type: "string",
457
+ description: "URL to request (can be relative if base_url is set)",
458
+ required: true
459
+ },
460
+ {
461
+ name: "headers",
462
+ type: "object",
463
+ description: "Request headers as key-value pairs",
464
+ required: false
465
+ },
466
+ {
467
+ name: "query",
468
+ type: "object",
469
+ description: "Query parameters as key-value pairs",
470
+ required: false
471
+ }
472
+ ]
473
+ },
474
+ {
475
+ name: "http_post",
476
+ description: "Make an HTTP POST request",
477
+ parameters: [
478
+ {
479
+ name: "url",
480
+ type: "string",
481
+ description: "URL to request",
482
+ required: true
483
+ },
484
+ {
485
+ name: "body",
486
+ type: "object",
487
+ description: "Request body (will be JSON encoded)",
488
+ required: false
489
+ },
490
+ {
491
+ name: "headers",
492
+ type: "object",
493
+ description: "Request headers as key-value pairs",
494
+ required: false
495
+ }
496
+ ]
497
+ },
498
+ {
499
+ name: "http_put",
500
+ description: "Make an HTTP PUT request",
501
+ parameters: [
502
+ {
503
+ name: "url",
504
+ type: "string",
505
+ description: "URL to request",
506
+ required: true
507
+ },
508
+ {
509
+ name: "body",
510
+ type: "object",
511
+ description: "Request body (will be JSON encoded)",
512
+ required: false
513
+ },
514
+ {
515
+ name: "headers",
516
+ type: "object",
517
+ description: "Request headers as key-value pairs",
518
+ required: false
519
+ }
520
+ ]
521
+ },
522
+ {
523
+ name: "http_delete",
524
+ description: "Make an HTTP DELETE request",
525
+ parameters: [
526
+ {
527
+ name: "url",
528
+ type: "string",
529
+ description: "URL to request",
530
+ required: true
531
+ },
532
+ {
533
+ name: "headers",
534
+ type: "object",
535
+ description: "Request headers as key-value pairs",
536
+ required: false
537
+ }
538
+ ]
539
+ },
540
+ {
541
+ name: "set_base_url",
542
+ description: "Set the base URL for all subsequent requests",
543
+ parameters: [
544
+ {
545
+ name: "base_url",
546
+ type: "string",
547
+ description: "Base URL (e.g., https://api.example.com)",
548
+ required: true
549
+ }
550
+ ]
551
+ }
552
+ ]
553
+ };
554
+
555
+ // src/presets/filesystem.ts
556
+ var FILESYSTEM_PRESET = {
557
+ id: "filesystem",
558
+ name: "File System Tools",
559
+ description: "Tools for file operations: read, write, list, search",
560
+ tools: [
561
+ {
562
+ name: "read_file",
563
+ description: "Read the contents of a file",
564
+ parameters: [
565
+ {
566
+ name: "path",
567
+ type: "string",
568
+ description: "Path to the file to read",
569
+ required: true
570
+ },
571
+ {
572
+ name: "encoding",
573
+ type: "string",
574
+ description: "File encoding (default: utf-8)",
575
+ required: false
576
+ }
577
+ ]
578
+ },
579
+ {
580
+ name: "write_file",
581
+ description: "Write content to a file",
582
+ parameters: [
583
+ {
584
+ name: "path",
585
+ type: "string",
586
+ description: "Path to the file to write",
587
+ required: true
588
+ },
589
+ {
590
+ name: "content",
591
+ type: "string",
592
+ description: "Content to write to the file",
593
+ required: true
594
+ },
595
+ {
596
+ name: "append",
597
+ type: "boolean",
598
+ description: "Append to file instead of overwriting (default: false)",
599
+ required: false
600
+ }
601
+ ]
602
+ },
603
+ {
604
+ name: "list_directory",
605
+ description: "List files and directories in a path",
606
+ parameters: [
607
+ {
608
+ name: "path",
609
+ type: "string",
610
+ description: "Directory path to list",
611
+ required: true
612
+ },
613
+ {
614
+ name: "recursive",
615
+ type: "boolean",
616
+ description: "List recursively (default: false)",
617
+ required: false
618
+ }
619
+ ]
620
+ },
621
+ {
622
+ name: "search_files",
623
+ description: "Search for files matching a pattern",
624
+ parameters: [
625
+ {
626
+ name: "path",
627
+ type: "string",
628
+ description: "Directory to search in",
629
+ required: true
630
+ },
631
+ {
632
+ name: "pattern",
633
+ type: "string",
634
+ description: "Glob pattern to match (e.g., *.txt)",
635
+ required: true
636
+ },
637
+ {
638
+ name: "recursive",
639
+ type: "boolean",
640
+ description: "Search recursively (default: true)",
641
+ required: false
642
+ }
643
+ ]
644
+ },
645
+ {
646
+ name: "file_info",
647
+ description: "Get information about a file or directory",
648
+ parameters: [
649
+ {
650
+ name: "path",
651
+ type: "string",
652
+ description: "Path to the file or directory",
653
+ required: true
654
+ }
655
+ ]
656
+ }
657
+ ]
658
+ };
659
+
660
+ // src/presets/index.ts
661
+ var PRESETS = {
662
+ database: DATABASE_PRESET,
663
+ "rest-api": REST_API_PRESET,
664
+ filesystem: FILESYSTEM_PRESET
665
+ };
666
+ var PRESET_IDS = Object.keys(PRESETS);
667
+ function getPreset(id) {
668
+ return PRESETS[id];
669
+ }
670
+ function isValidPresetId(id) {
671
+ return id in PRESETS;
672
+ }
673
+
674
+ // src/prompts/preset.ts
675
+ async function promptPreset() {
676
+ const choices = Object.values(PRESETS).map((preset2) => ({
677
+ name: `${preset2.name} - ${preset2.description}`,
678
+ value: preset2.id
679
+ }));
680
+ const { preset } = await inquirer7.prompt([
681
+ {
682
+ type: "list",
683
+ name: "preset",
684
+ message: "Select a preset template:",
685
+ choices,
686
+ default: "database"
687
+ }
688
+ ]);
689
+ return preset;
690
+ }
691
+
315
692
  // src/prompts/index.ts
316
693
  async function runWizard(options = {}) {
317
694
  const name = await promptProjectName(options.defaultName);
@@ -528,11 +905,34 @@ var logger = {
528
905
  },
529
906
  nextSteps: (projectName, language) => {
530
907
  logger.blank();
908
+ let installCmd;
909
+ 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";
930
+ }
531
931
  logger.box("Next steps:", [
532
932
  "",
533
933
  ` ${chalk.cyan("cd")} ${projectName}`,
534
- language === "typescript" ? ` ${chalk.cyan("npm install")}` : ` ${chalk.cyan("pip install -e .")}`,
535
- language === "typescript" ? ` ${chalk.cyan("npm run dev")}` : ` ${chalk.cyan("python -m src.server")}`,
934
+ ` ${chalk.cyan(installCmd)}`,
935
+ ` ${chalk.cyan(runCmd)}`,
536
936
  ""
537
937
  ]);
538
938
  }
@@ -639,11 +1039,19 @@ var BaseGenerator = class {
639
1039
  logger.info("Skipping dependency installation (--skip-install)");
640
1040
  return;
641
1041
  }
642
- const isTypescript = this.config.language === "typescript";
643
- if (isTypescript) {
644
- await this.installNodeDependencies();
645
- } else {
646
- await this.installPythonDependencies();
1042
+ switch (this.config.language) {
1043
+ case "typescript":
1044
+ await this.installNodeDependencies();
1045
+ break;
1046
+ case "python":
1047
+ await this.installPythonDependencies();
1048
+ break;
1049
+ case "go":
1050
+ await this.installGoDependencies();
1051
+ break;
1052
+ case "rust":
1053
+ await this.installRustDependencies();
1054
+ break;
647
1055
  }
648
1056
  }
649
1057
  async installNodeDependencies() {
@@ -676,9 +1084,49 @@ var BaseGenerator = class {
676
1084
  "Failed to install dependencies"
677
1085
  );
678
1086
  }
1087
+ async installGoDependencies() {
1088
+ const hasGo = await this.checkCommand("go");
1089
+ if (!hasGo) {
1090
+ logger.warning("Go not found. Please install dependencies manually:");
1091
+ logger.code("go mod download");
1092
+ return;
1093
+ }
1094
+ await withSpinner(
1095
+ "Installing Go dependencies...",
1096
+ async () => {
1097
+ await execa2("go", ["mod", "download"], {
1098
+ cwd: this.outputDir
1099
+ });
1100
+ await execa2("go", ["mod", "tidy"], {
1101
+ cwd: this.outputDir
1102
+ });
1103
+ },
1104
+ "Dependencies installed",
1105
+ "Failed to install dependencies"
1106
+ );
1107
+ }
1108
+ async installRustDependencies() {
1109
+ const hasCargo = await this.checkCommand("cargo");
1110
+ if (!hasCargo) {
1111
+ logger.warning("Cargo not found. Please install dependencies manually:");
1112
+ logger.code("cargo build");
1113
+ return;
1114
+ }
1115
+ await withSpinner(
1116
+ "Building Rust project...",
1117
+ async () => {
1118
+ await execa2("cargo", ["build"], {
1119
+ cwd: this.outputDir
1120
+ });
1121
+ },
1122
+ "Project built successfully",
1123
+ "Failed to build project"
1124
+ );
1125
+ }
679
1126
  async checkCommand(command) {
680
1127
  try {
681
- await execa2("which", [command]);
1128
+ const checkCmd = process.platform === "win32" ? "where" : "which";
1129
+ await execa2(checkCmd, [command]);
682
1130
  return true;
683
1131
  } catch {
684
1132
  return false;
@@ -764,7 +1212,7 @@ async function generateFromWizard(config, outputPath) {
764
1212
 
765
1213
  // src/parsers/openapi.ts
766
1214
  import YAML from "yaml";
767
- import inquirer6 from "inquirer";
1215
+ import inquirer8 from "inquirer";
768
1216
  async function parseOpenAPISpec(content) {
769
1217
  let spec;
770
1218
  try {
@@ -864,7 +1312,7 @@ async function selectEndpoints(endpoints) {
864
1312
  value: ep,
865
1313
  checked: true
866
1314
  }));
867
- const { selected } = await inquirer6.prompt([
1315
+ const { selected } = await inquirer8.prompt([
868
1316
  {
869
1317
  type: "checkbox",
870
1318
  name: "selected",
@@ -1000,7 +1448,7 @@ function mapOpenAPIType(type) {
1000
1448
 
1001
1449
  // src/generators/from-prompt.ts
1002
1450
  import Anthropic from "@anthropic-ai/sdk";
1003
- import inquirer7 from "inquirer";
1451
+ import inquirer9 from "inquirer";
1004
1452
  var SYSTEM_PROMPT = `You are an expert at designing MCP (Model Context Protocol) servers.
1005
1453
  Given a description of an API or functionality, you generate a list of tools that would be useful for that API.
1006
1454
 
@@ -1058,7 +1506,7 @@ var PromptGenerator = class extends BaseGenerator {
1058
1506
  }
1059
1507
  };
1060
1508
  async function generateFromPrompt(baseConfig) {
1061
- const { description } = await inquirer7.prompt([
1509
+ const { description } = await inquirer9.prompt([
1062
1510
  {
1063
1511
  type: "editor",
1064
1512
  name: "description",
@@ -1114,7 +1562,7 @@ async function generateFromPrompt(baseConfig) {
1114
1562
  logger.list([`${index + 1}. ${tool.name} - ${tool.description}`]);
1115
1563
  });
1116
1564
  logger.blank();
1117
- const { confirm } = await inquirer7.prompt([
1565
+ const { confirm } = await inquirer9.prompt([
1118
1566
  {
1119
1567
  type: "confirm",
1120
1568
  name: "confirm",
@@ -1141,10 +1589,85 @@ async function generateFromPrompt(baseConfig) {
1141
1589
  await generator.generate();
1142
1590
  }
1143
1591
 
1592
+ // src/generators/from-preset.ts
1593
+ var PresetGenerator = class extends BaseGenerator {
1594
+ presetName;
1595
+ constructor(context, presetName) {
1596
+ super(context);
1597
+ this.presetName = presetName;
1598
+ }
1599
+ async generate() {
1600
+ logger.title(`Creating ${this.config.name} from "${this.presetName}" preset`);
1601
+ const isSafe = await this.checkOutputDir();
1602
+ if (!isSafe) {
1603
+ throw new Error(
1604
+ `Directory ${this.outputDir} already exists and is not empty. Please choose a different name or delete the existing directory.`
1605
+ );
1606
+ }
1607
+ await withSpinner(
1608
+ "Creating project structure...",
1609
+ async () => {
1610
+ await this.createProjectStructure();
1611
+ },
1612
+ "Project structure created"
1613
+ );
1614
+ await withSpinner(
1615
+ "Generating files from templates...",
1616
+ async () => {
1617
+ await this.renderTemplates();
1618
+ },
1619
+ "Files generated"
1620
+ );
1621
+ await this.installDependencies();
1622
+ await this.initializeGit();
1623
+ logger.success(`Project ${this.config.name} created successfully!`);
1624
+ logger.info(`Preset: ${this.presetName}`);
1625
+ logger.info(`Tools included: ${this.config.tools.map((t) => t.name).join(", ")}`);
1626
+ logger.nextSteps(this.config.name, this.config.language);
1627
+ }
1628
+ };
1629
+ async function generateFromPreset(options) {
1630
+ const preset = getPreset(options.presetId);
1631
+ if (!preset) {
1632
+ throw new Error(`Invalid preset: ${options.presetId}`);
1633
+ }
1634
+ const name = options.projectName || await promptProjectName();
1635
+ const description = options.useDefaults ? "" : await promptProjectDescription();
1636
+ const language = options.language || (options.useDefaults ? "typescript" : await promptLanguage());
1637
+ const transport = options.useDefaults ? "stdio" : await promptTransport();
1638
+ const config = {
1639
+ name,
1640
+ description,
1641
+ language,
1642
+ transport,
1643
+ tools: preset.tools,
1644
+ resources: [],
1645
+ includeExampleTool: false,
1646
+ skipInstall: options.skipInstall || false,
1647
+ initGit: true
1648
+ };
1649
+ const context = createGeneratorContext(config);
1650
+ const generator = new PresetGenerator(context, preset.name);
1651
+ await generator.generate();
1652
+ }
1653
+ function validatePresetId(presetId) {
1654
+ if (!isValidPresetId(presetId)) {
1655
+ const validPresets = ["database", "rest-api", "filesystem"];
1656
+ throw new Error(
1657
+ `Invalid preset "${presetId}". Valid presets are: ${validPresets.join(", ")}`
1658
+ );
1659
+ }
1660
+ return true;
1661
+ }
1662
+
1144
1663
  // src/commands/create.ts
1145
1664
  import path4 from "path";
1146
1665
  async function createCommand(projectName, options) {
1147
1666
  try {
1667
+ if (options.preset) {
1668
+ await handlePresetGeneration(projectName, options);
1669
+ return;
1670
+ }
1148
1671
  if (options.fromOpenapi) {
1149
1672
  await handleOpenAPIGeneration(projectName, options);
1150
1673
  return;
@@ -1165,7 +1688,7 @@ async function createCommand(projectName, options) {
1165
1688
  }
1166
1689
  async function handleWizardGeneration(projectName, options) {
1167
1690
  let config;
1168
- const presetLanguage = options.typescript ? "typescript" : options.python ? "python" : void 0;
1691
+ const presetLanguage = options.typescript ? "typescript" : options.python ? "python" : options.go ? "go" : options.rust ? "rust" : void 0;
1169
1692
  if (options.yes) {
1170
1693
  config = await runQuickWizard(projectName, presetLanguage);
1171
1694
  } else {
@@ -1193,29 +1716,42 @@ async function handleOpenAPIGeneration(projectName, options) {
1193
1716
  const name = projectName || path4.basename(specPath, path4.extname(specPath)) + "-mcp";
1194
1717
  await generateFromOpenAPI(specPath, {
1195
1718
  name,
1196
- language: options.typescript ? "typescript" : options.python ? "python" : void 0,
1719
+ language: options.typescript ? "typescript" : options.python ? "python" : options.go ? "go" : options.rust ? "rust" : void 0,
1197
1720
  skipInstall: options.skipInstall
1198
1721
  });
1199
1722
  }
1200
1723
  async function handlePromptGeneration(projectName, options) {
1201
1724
  await generateFromPrompt({
1202
1725
  name: projectName,
1203
- language: options.typescript ? "typescript" : options.python ? "python" : void 0,
1726
+ language: options.typescript ? "typescript" : options.python ? "python" : options.go ? "go" : options.rust ? "rust" : void 0,
1204
1727
  skipInstall: options.skipInstall
1205
1728
  });
1206
1729
  }
1730
+ async function handlePresetGeneration(projectName, options) {
1731
+ const presetId = options.preset;
1732
+ validatePresetId(presetId);
1733
+ await generateFromPreset({
1734
+ projectName,
1735
+ presetId,
1736
+ language: options.typescript ? "typescript" : options.python ? "python" : options.go ? "go" : options.rust ? "rust" : void 0,
1737
+ skipInstall: options.skipInstall,
1738
+ useDefaults: options.yes
1739
+ });
1740
+ }
1207
1741
 
1208
1742
  // src/commands/init.ts
1209
1743
  import path5 from "path";
1210
- import inquirer8 from "inquirer";
1744
+ import inquirer10 from "inquirer";
1211
1745
  async function initCommand(options) {
1212
1746
  try {
1213
1747
  const currentDir = process.cwd();
1214
1748
  const dirName = path5.basename(currentDir);
1215
1749
  const hasPackageJson = await exists(path5.join(currentDir, "package.json"));
1216
1750
  const hasPyproject = await exists(path5.join(currentDir, "pyproject.toml"));
1217
- if ((hasPackageJson || hasPyproject) && !options.force) {
1218
- const { proceed } = await inquirer8.prompt([
1751
+ const hasGoMod = await exists(path5.join(currentDir, "go.mod"));
1752
+ const hasCargoToml = await exists(path5.join(currentDir, "Cargo.toml"));
1753
+ if ((hasPackageJson || hasPyproject || hasGoMod || hasCargoToml) && !options.force) {
1754
+ const { proceed } = await inquirer10.prompt([
1219
1755
  {
1220
1756
  type: "confirm",
1221
1757
  name: "proceed",
@@ -1233,12 +1769,22 @@ async function initCommand(options) {
1233
1769
  language = "typescript";
1234
1770
  } else if (options.python) {
1235
1771
  language = "python";
1772
+ } else if (options.go) {
1773
+ language = "go";
1774
+ } else if (options.rust) {
1775
+ language = "rust";
1236
1776
  } else if (hasPackageJson) {
1237
1777
  language = "typescript";
1238
1778
  logger.info("Detected existing Node.js project, using TypeScript");
1239
1779
  } else if (hasPyproject) {
1240
1780
  language = "python";
1241
1781
  logger.info("Detected existing Python project");
1782
+ } else if (hasGoMod) {
1783
+ language = "go";
1784
+ logger.info("Detected existing Go project");
1785
+ } else if (hasCargoToml) {
1786
+ language = "rust";
1787
+ logger.info("Detected existing Rust project");
1242
1788
  } else {
1243
1789
  language = await promptLanguage();
1244
1790
  }
@@ -1283,7 +1829,9 @@ async function addToolCommand(options) {
1283
1829
  const currentDir = process.cwd();
1284
1830
  const isTypeScript = await exists(path6.join(currentDir, "package.json"));
1285
1831
  const isPython = await exists(path6.join(currentDir, "pyproject.toml"));
1286
- if (!isTypeScript && !isPython) {
1832
+ const isGo = await exists(path6.join(currentDir, "go.mod"));
1833
+ const isRust = await exists(path6.join(currentDir, "Cargo.toml"));
1834
+ if (!isTypeScript && !isPython && !isGo && !isRust) {
1287
1835
  logger.error("No MCP server project found in current directory.");
1288
1836
  logger.info("Run this command from the root of your MCP server project.");
1289
1837
  process.exit(1);
@@ -1301,8 +1849,12 @@ async function addToolCommand(options) {
1301
1849
  }
1302
1850
  if (isTypeScript) {
1303
1851
  await addToolToTypeScript(currentDir, tool);
1304
- } else {
1852
+ } else if (isPython) {
1305
1853
  await addToolToPython(currentDir, tool);
1854
+ } else if (isGo) {
1855
+ await addToolToGo(currentDir, tool);
1856
+ } else if (isRust) {
1857
+ await addToolToRust(currentDir, tool);
1306
1858
  }
1307
1859
  logger.success(`Tool "${tool.name}" added successfully!`);
1308
1860
  logger.info("Remember to implement the tool logic in the generated file.");
@@ -1479,6 +2031,173 @@ function mapTypeToPython(type) {
1479
2031
  return "str";
1480
2032
  }
1481
2033
  }
2034
+ async function addToolToGo(projectDir, tool) {
2035
+ const toolsDir = path6.join(projectDir, "internal", "tools");
2036
+ const toolFileName = `${tool.name}.go`;
2037
+ const toolFilePath = path6.join(toolsDir, toolFileName);
2038
+ if (await exists(toolFilePath)) {
2039
+ logger.error(`Tool file already exists: ${toolFilePath}`);
2040
+ process.exit(1);
2041
+ }
2042
+ const content = generateGoToolFile(tool);
2043
+ await writeFile(toolFilePath, content);
2044
+ logger.info(`Created: internal/tools/${toolFileName}`);
2045
+ logger.blank();
2046
+ logger.info("Next steps:");
2047
+ logger.list([
2048
+ `Implement the tool logic in internal/tools/${toolFileName}`,
2049
+ "Import and register the tool in cmd/server/main.go"
2050
+ ]);
2051
+ }
2052
+ async function addToolToRust(projectDir, tool) {
2053
+ const srcDir = path6.join(projectDir, "src");
2054
+ const toolFileName = `${tool.name}.rs`;
2055
+ const toolFilePath = path6.join(srcDir, toolFileName);
2056
+ if (await exists(toolFilePath)) {
2057
+ logger.error(`Tool file already exists: ${toolFilePath}`);
2058
+ process.exit(1);
2059
+ }
2060
+ const content = generateRustToolFile(tool);
2061
+ await writeFile(toolFilePath, content);
2062
+ logger.info(`Created: src/${toolFileName}`);
2063
+ logger.blank();
2064
+ logger.info("Next steps:");
2065
+ logger.list([
2066
+ `Implement the tool logic in src/${toolFileName}`,
2067
+ `Add "mod ${tool.name};" to src/main.rs`,
2068
+ "Register the tool in the server builder"
2069
+ ]);
2070
+ }
2071
+ function generateGoToolFile(tool) {
2072
+ const structFields = tool.parameters.map((p) => ` ${toPascalCase(p.name)} ${mapTypeToGo(p.type)} \`json:"${p.name}"\``).join("\n");
2073
+ return `package tools
2074
+
2075
+ import (
2076
+ "context"
2077
+ "fmt"
2078
+
2079
+ "github.com/mark3labs/mcp-go/mcp"
2080
+ )
2081
+
2082
+ // ${toPascalCase(tool.name)}Input represents the input for the ${tool.name} tool
2083
+ type ${toPascalCase(tool.name)}Input struct {
2084
+ ${structFields || " // No parameters"}
2085
+ }
2086
+
2087
+ // ${toPascalCase(tool.name)}Tool creates the ${tool.name} tool definition
2088
+ func ${toPascalCase(tool.name)}Tool() mcp.Tool {
2089
+ return mcp.NewTool("${tool.name}",
2090
+ mcp.WithDescription("${tool.description}"),
2091
+ ${tool.parameters.map((p) => {
2092
+ const mcpType = p.type === "number" ? "WithNumber" : p.type === "boolean" ? "WithBoolean" : "WithString";
2093
+ return ` mcp.${mcpType}("${p.name}",
2094
+ ${p.required ? " mcp.Required(),\n" : ""} mcp.Description("${p.description}"),
2095
+ ),`;
2096
+ }).join("\n")}
2097
+ )
2098
+ }
2099
+
2100
+ // ${toPascalCase(tool.name)}Handler handles the ${tool.name} tool execution
2101
+ func ${toPascalCase(tool.name)}Handler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
2102
+ // TODO: Implement ${tool.name} logic
2103
+ ${tool.parameters.map((p) => {
2104
+ const goType = mapTypeToGo(p.type);
2105
+ if (goType === "float64") {
2106
+ return ` ${p.name}, _ := request.Params.Arguments["${p.name}"].(float64)`;
2107
+ } else if (goType === "bool") {
2108
+ return ` ${p.name}, _ := request.Params.Arguments["${p.name}"].(bool)`;
2109
+ } else {
2110
+ return ` ${p.name}, _ := request.Params.Arguments["${p.name}"].(string)`;
2111
+ }
2112
+ }).join("\n")}
2113
+
2114
+ return mcp.NewToolResultText(fmt.Sprintf("${tool.name} called with: %v", request.Params.Arguments)), nil
2115
+ }
2116
+ `;
2117
+ }
2118
+ function generateRustToolFile(tool) {
2119
+ const structFields = tool.parameters.map((p) => ` pub ${p.name}: ${mapTypeToRust(p.type)},`).join("\n");
2120
+ const required = tool.parameters.filter((p) => p.required).map((p) => `"${p.name}".to_string()`).join(", ");
2121
+ return `use rmcp::{
2122
+ model::{CallToolResult, Content, Tool, ToolInputSchema},
2123
+ tool,
2124
+ };
2125
+ use serde::Deserialize;
2126
+ use serde_json::{json, Value};
2127
+ use std::collections::HashMap;
2128
+
2129
+ /// ${tool.description}
2130
+ #[derive(Debug, Deserialize)]
2131
+ pub struct ${toPascalCase(tool.name)}Input {
2132
+ ${structFields || " // No parameters"}
2133
+ }
2134
+
2135
+ pub fn ${tool.name}_tool() -> Tool {
2136
+ Tool {
2137
+ name: "${tool.name}".to_string(),
2138
+ description: Some("${tool.description}".to_string()),
2139
+ input_schema: ToolInputSchema {
2140
+ r#type: "object".to_string(),
2141
+ properties: Some({
2142
+ let mut props = HashMap::new();
2143
+ ${tool.parameters.map(
2144
+ (p) => ` props.insert(
2145
+ "${p.name}".to_string(),
2146
+ json!({
2147
+ "type": "${p.type}",
2148
+ "description": "${p.description}"
2149
+ }),
2150
+ );`
2151
+ ).join("\n")}
2152
+ props
2153
+ }),
2154
+ required: Some(vec![${required}]),
2155
+ },
2156
+ handler: Box::new(|args| {
2157
+ Box::pin(async move {
2158
+ // TODO: Implement ${tool.name} logic
2159
+ let input: ${toPascalCase(tool.name)}Input = serde_json::from_value(args.clone())?;
2160
+
2161
+ Ok(CallToolResult {
2162
+ content: vec![Content::Text {
2163
+ text: format!("${tool.name} called with: {:?}", args),
2164
+ }],
2165
+ is_error: None,
2166
+ })
2167
+ })
2168
+ }),
2169
+ }
2170
+ }
2171
+ `;
2172
+ }
2173
+ function mapTypeToGo(type) {
2174
+ switch (type) {
2175
+ case "number":
2176
+ return "float64";
2177
+ case "boolean":
2178
+ return "bool";
2179
+ case "array":
2180
+ return "[]interface{}";
2181
+ case "object":
2182
+ return "map[string]interface{}";
2183
+ default:
2184
+ return "string";
2185
+ }
2186
+ }
2187
+ function mapTypeToRust(type) {
2188
+ switch (type) {
2189
+ case "number":
2190
+ return "f64";
2191
+ case "boolean":
2192
+ return "bool";
2193
+ case "array":
2194
+ return "Vec<Value>";
2195
+ case "object":
2196
+ return "HashMap<String, Value>";
2197
+ default:
2198
+ return "String";
2199
+ }
2200
+ }
1482
2201
 
1483
2202
  export {
1484
2203
  projectNameRegex,
@@ -1499,6 +2218,8 @@ export {
1499
2218
  promptAddResources,
1500
2219
  promptResourceConfig,
1501
2220
  promptMultipleResources,
2221
+ promptGenerationMethod,
2222
+ promptPreset,
1502
2223
  runWizard,
1503
2224
  runQuickWizard,
1504
2225
  ensureDir,
@@ -1534,6 +2255,9 @@ export {
1534
2255
  generateFromOpenAPI,
1535
2256
  PromptGenerator,
1536
2257
  generateFromPrompt,
2258
+ PresetGenerator,
2259
+ generateFromPreset,
2260
+ validatePresetId,
1537
2261
  createCommand,
1538
2262
  initCommand,
1539
2263
  addToolCommand