fa-mcp-sdk 0.2.120 → 0.2.121

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 (2) hide show
  1. package/bin/fa-mcp.js +83 -24
  2. package/package.json +3 -1
package/bin/fa-mcp.js CHANGED
@@ -6,6 +6,7 @@ import { fileURLToPath } from 'url';
6
6
  import readline from 'readline';
7
7
  import { v4 as uuidv4 } from 'uuid';
8
8
  import chalk from 'chalk';
9
+ import yaml from 'js-yaml';
9
10
 
10
11
  const __filename = fileURLToPath(import.meta.url);
11
12
  const __dirname = path.dirname(__filename);
@@ -71,6 +72,34 @@ const getAsk = () => {
71
72
  };
72
73
  };
73
74
 
75
+ /**
76
+ * Parse configuration file (JSON or YAML)
77
+ * @param {string} filePath - Path to the configuration file
78
+ * @param {string} content - Content of the file
79
+ * @returns {object} Parsed configuration object
80
+ */
81
+ const parseConfigFile = (filePath, content) => {
82
+ const ext = path.extname(filePath).toLowerCase();
83
+
84
+ try {
85
+ if (ext === '.json') {
86
+ return JSON.parse(content);
87
+ } else if (ext === '.yaml' || ext === '.yml') {
88
+ return yaml.load(content, { schema: yaml.DEFAULT_SCHEMA });
89
+ } else {
90
+ // Try to detect format by content
91
+ const trimmed = content.trim();
92
+ if (trimmed.startsWith('{') || trimmed.startsWith('[')) {
93
+ return JSON.parse(content);
94
+ } else {
95
+ return yaml.load(content, { schema: yaml.DEFAULT_SCHEMA });
96
+ }
97
+ }
98
+ } catch (error) {
99
+ throw new Error(`Failed to parse configuration file ${filePath}: ${error.message}`);
100
+ }
101
+ };
102
+
74
103
  class MCPGenerator {
75
104
  constructor () {
76
105
  this.templateDir = path.join(__dirname, '..', 'cli-template');
@@ -166,6 +195,11 @@ class MCPGenerator {
166
195
  defaultValue: '<envCode.prod>',
167
196
  title: 'Production environment code for Consul service ID generation',
168
197
  },
198
+ {
199
+ name: 'NODE_CONSUL_ENV',
200
+ defaultValue: '',
201
+ title: 'Affects how the Consul service ID is formed - as a product or development ID. Valid values: "" | "development" | "production"',
202
+ },
169
203
 
170
204
  {
171
205
  name: 'mcp.domain',
@@ -487,6 +521,18 @@ certificate's public and private keys`,
487
521
  config[name] = String(enabled);
488
522
  continue;
489
523
  }
524
+ case 'NODE_CONSUL_ENV': {
525
+ if (currentValue === '') {
526
+ continue;
527
+ }
528
+ value = await ask.optional(title, name, defaultValue);
529
+ if (value === '' || value === 'development' || value === 'production') {
530
+ config[name] = value;
531
+ } else {
532
+ config[name] = '';
533
+ }
534
+ continue;
535
+ }
490
536
 
491
537
  default:
492
538
  value = await ask.optional(title, name, defaultValue);
@@ -534,17 +580,17 @@ certificate's public and private keys`,
534
580
 
535
581
  async collectConfiguration () {
536
582
  const config = {};
537
- const configFile = process.argv.find((arg) => arg.endsWith('.json')) ||
583
+ const configFile = process.argv.find((arg) => arg.endsWith('.json') || arg.endsWith('.yaml') || arg.endsWith('.yml')) ||
538
584
  process.argv.find((arg) => arg.startsWith('--config='))?.split('=')[1];
539
585
 
540
586
  if (configFile) {
541
587
  try {
542
588
  const configData = await fs.readFile(configFile, 'utf8');
543
- const parsedConfig = JSON.parse(configData);
589
+ const parsedConfig = parseConfigFile(configFile, configData);
544
590
  Object.assign(config, parsedConfig);
545
591
  console.log(`šŸ“‹ Loaded configuration from: ${hly(configFile)}`);
546
592
  } catch (error) {
547
- console.warn(`āš ļø Warning: Could not load config file ${configFile}`);
593
+ console.warn(`āš ļø Warning: Could not load config file ${configFile}: ${error.message}`);
548
594
  }
549
595
  }
550
596
 
@@ -565,7 +611,9 @@ certificate's public and private keys`,
565
611
  } else if (configProxy.NODE_ENV === 'production') {
566
612
  configProxy.isProduction = 'true';
567
613
  }
568
-
614
+ if (config['logger.useFileLogger'] !== 'true') {
615
+ config['logger.dir'] = '';
616
+ }
569
617
  let confirmed = false;
570
618
  let isRetry = false;
571
619
 
@@ -592,34 +640,34 @@ certificate's public and private keys`,
592
640
  async getTargetPath (config = {}) {
593
641
  const ask = getAsk();
594
642
 
595
- let targetPath = process.cwd();
643
+ let tp = process.cwd();
596
644
  let createInCurrent;
597
645
  let pPath = trim(config.projectAbsPath);
598
646
  if (pPath) {
599
- targetPath = path.resolve(pPath);
600
- console.log(`Create project in: ${hl(targetPath)}${FROM_CONFIG}`);
647
+ tp = path.resolve(pPath);
648
+ console.log(`Create project in: ${hl(tp)}${FROM_CONFIG}`);
601
649
  } else {
602
- createInCurrent = await ask.yn(`Create project in current directory? (${hl(targetPath)})`, '', 'n');
650
+ createInCurrent = await ask.yn(`Create project in current directory? (${hl(tp)})`, '', 'n');
603
651
  if (!createInCurrent) {
604
- targetPath = await ask.question('Enter absolute path for project: ');
605
- targetPath = path.resolve(targetPath);
652
+ tp = await ask.question('Enter absolute path for project: ');
653
+ tp = path.resolve(tp);
606
654
  }
607
655
  }
608
656
 
609
- config.projectAbsPath = targetPath;
657
+ config.projectAbsPath = tp;
610
658
  // Create directory if it doesn't exist
611
659
  try {
612
- await fs.access(targetPath);
660
+ await fs.access(tp);
613
661
  } catch {
614
662
  console.log('Creating directory recursively...');
615
- await fs.mkdir(targetPath, { recursive: true });
663
+ await fs.mkdir(tp, { recursive: true });
616
664
  }
617
665
 
618
- const errMsg = `āŒ Directory ${hl(targetPath)} not empty - cannot create project here. Use an empty directory or specify a different path.`;
666
+ const errMsg = `āŒ Directory ${hl(tp)} not empty - cannot create project here. Use an empty directory or specify a different path.`;
619
667
 
620
668
  // Check if directory is empty
621
669
  try {
622
- const files = await fs.readdir(targetPath);
670
+ const files = await fs.readdir(tp);
623
671
  const allowedFiles = [
624
672
  '.git',
625
673
  '.idea',
@@ -650,7 +698,7 @@ certificate's public and private keys`,
650
698
  }
651
699
 
652
700
  ask.close();
653
- return targetPath;
701
+ return tp;
654
702
  }
655
703
 
656
704
  async copyDirectory (source, target) {
@@ -728,7 +776,16 @@ certificate's public and private keys`,
728
776
  return files;
729
777
  }
730
778
 
731
- async replaceTemplateParameters (targetPath, config) {
779
+ async transformTargetFile (config, targetRelPath, transformFn) {
780
+ const targetPath = config.projectAbsPath;
781
+ const targetFullPath = path.join(targetPath, targetRelPath);
782
+ const content = await fs.readFile(targetFullPath, 'utf8');
783
+ const transformedContent = transformFn(content, config);
784
+ await fs.writeFile(targetFullPath, transformedContent, 'utf8');
785
+ }
786
+
787
+ async replaceTemplateParameters (config) {
788
+ const targetPath = config.projectAbsPath;
732
789
  const files = await this.getAllFiles(targetPath);
733
790
 
734
791
  for (const filePath of files) {
@@ -754,10 +811,11 @@ certificate's public and private keys`,
754
811
  await fs.writeFile(filePath, content, 'utf8');
755
812
  }
756
813
  }
814
+ if (config['NODE_CONSUL_ENV'] === '') {
815
+ await this.transformTargetFile(config, '.env', (c) => c.replace(/^(NODE_CONSUL_ENV)=([^\r\n]*)/m, '#$1=$2'));
816
+ }
757
817
  if (config['claude.isBypassPermissions'] === 'true') {
758
- const settingsPath = path.join(targetPath, '.claude', 'settings.json');
759
- const content = await fs.readFile(settingsPath, 'utf8')
760
- .replace('"acceptEdits"', '"bypassPermissions"')
818
+ const transformFn = (c) => c.replace('"acceptEdits"', '"bypassPermissions"')
761
819
  .replace(/"allow": \[\s+"Edit",/, `"allow": [
762
820
  "Bash(sudo cp:*)",
763
821
  "Bash(sudo:*)",
@@ -791,11 +849,12 @@ certificate's public and private keys`,
791
849
  "Bash(unset http_proxy)",
792
850
  "Bash(wc:*)",
793
851
  "Edit",`);
794
- await fs.writeFile(settingsPath, content, 'utf8');
852
+ await this.transformTargetFile(config, '.claude/settings.json', transformFn);
795
853
  }
796
854
  }
797
855
 
798
- async createProject (targetPath, config) {
856
+ async createProject (config) {
857
+ const targetPath = config.projectAbsPath;
799
858
  // Copy template files
800
859
  await this.copyDirectory(this.templateDir, targetPath);
801
860
  await fs.copyFile(path.join(targetPath, '.env.example'), path.join(targetPath, '.env')); // VVT
@@ -829,7 +888,7 @@ certificate's public and private keys`,
829
888
  }
830
889
 
831
890
  // Replace template parameters
832
- await this.replaceTemplateParameters(targetPath, config);
891
+ await this.replaceTemplateParameters(config);
833
892
 
834
893
  // Replace template placeholders with defaultValue from optionalParams and save as _local.yaml
835
894
  if (localYamlContent) {
@@ -878,7 +937,7 @@ certificate's public and private keys`,
878
937
  const targetPath = await this.getTargetPath(config);
879
938
 
880
939
  console.log(`\nšŸ“ Creating project in: ${targetPath}`);
881
- await this.createProject(targetPath, config);
940
+ await this.createProject(config);
882
941
 
883
942
  console.log('\nāœ… MCP Server template created successfully!');
884
943
  console.log('\nšŸ“‹ Next steps:');
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fa-mcp-sdk",
3
3
  "productName": "FA MCP SDK",
4
- "version": "0.2.120",
4
+ "version": "0.2.121",
5
5
  "description": "Core infrastructure and templates for building Model Context Protocol (MCP) servers with TypeScript",
6
6
  "type": "module",
7
7
  "main": "dist/core/index.js",
@@ -69,6 +69,7 @@
69
69
  "dotenv": "^17.2.3",
70
70
  "express": "^5.2.1",
71
71
  "helmet": "^8.1.0",
72
+ "js-yaml": "^4.1.0",
72
73
  "node-cache": "^5.1.2",
73
74
  "pgvector": "^0.2.1",
74
75
  "rate-limiter-flexible": "^9.0.0",
@@ -83,6 +84,7 @@
83
84
  "@types/config": "^3.3.5",
84
85
  "@types/cors": "^2.8.19",
85
86
  "@types/express": "^5.0.6",
87
+ "@types/js-yaml": "^4.0.9",
86
88
  "@types/mssql": "^9.1.8",
87
89
  "@types/node": "^24.10.1",
88
90
  "@types/swagger-jsdoc": "^6.0.4",