@natomalabs/natoma-mcp-gateway 1.0.3 → 1.0.4

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.
package/README.md CHANGED
@@ -4,12 +4,13 @@ A robust, production-ready gateway that bridges stdio-based MCP clients (like Cl
4
4
 
5
5
  ## Overview
6
6
 
7
- The Natoma MCP Gateway acts as a translation layer that enables seamless communication between different MCP (Model Context Protocol) implementations. It supports both standard and enterprise deployment modes, with automatic reconnection, health monitoring, and robust error handling.
7
+ The Natoma MCP Gateway acts as a translation layer that enables seamless communication between different MCP (Model Context Protocol) implementations. It operates exclusively in enterprise mode, providing production-grade features including automatic reconnection, health monitoring, and robust error handling.
8
8
 
9
9
  ## Features
10
10
 
11
- - **Dual Gateway Modes**: NMS (standard) and Enterprise gateways for different deployment scenarios
11
+ - **Enterprise Gateway**: Production-ready gateway with enhanced reliability and monitoring
12
12
  - **Protocol Translation**: Converts stdio JSON-RPC messages to HTTP/SSE format and vice versa
13
+ - **Custom URL Support**: Configure custom endpoints for private deployments
13
14
 
14
15
  ## Installation
15
16
 
@@ -26,13 +27,28 @@ Required environment variables:
26
27
  - `NATOMA_MCP_SERVER_INSTALLATION_ID`: Your MCP server installation ID/slug
27
28
  - `NATOMA_MCP_API_KEY`: Your Natoma API key for authentication
28
29
 
29
- ### Command Line Usage
30
+ Optional environment variables:
31
+
32
+ - `NATOMA_MCP_CUSTOM_URL`: Custom endpoint URL (overrides default api.natoma.app endpoint)
33
+
34
+ ### Corporate Proxy/Firewall Support
35
+
36
+ If you're running in a corporate environment with tools like ZScaler that perform TLS interception, you may encounter certificate validation errors. You can resolve this using Node.js's built-in support for custom CA certificates:
30
37
 
31
38
  ```bash
32
- # Standard NMS Gateway mode
39
+ # Export your corporate CA bundle
40
+ export NODE_EXTRA_CA_CERTS="/path/to/corporate-ca-bundle.pem"
41
+
42
+ # Run the gateway
33
43
  npx @natomalabs/natoma-mcp-gateway
44
+ ```
34
45
 
35
- # Enterprise Gateway mode
46
+ This approach is the standard Node.js solution for corporate environments.
47
+
48
+ ### Command Line Usage
49
+
50
+ ```bash
51
+ # Run the gateway (--enterprise flag is required)
36
52
  npx @natomalabs/natoma-mcp-gateway --enterprise
37
53
  ```
38
54
 
@@ -46,7 +62,8 @@ Add to your Claude Desktop MCP configuration:
46
62
  "your-server-name": {
47
63
  "command": "npx",
48
64
  "args": [
49
- "@natomalabs/natoma-mcp-gateway"
65
+ "@natomalabs/natoma-mcp-gateway",
66
+ "--enterprise"
50
67
  ],
51
68
  "env": {
52
69
  "NATOMA_MCP_SERVER_INSTALLATION_ID": "your-installation-id",
@@ -57,26 +74,60 @@ Add to your Claude Desktop MCP configuration:
57
74
  }
58
75
  ```
59
76
 
60
- For enterprise deployments, add `--enterprise` to the args array.
77
+ For custom endpoint URLs:
61
78
 
62
- ## Architecture
79
+ ```json
80
+ {
81
+ "mcpServers": {
82
+ "your-server-name": {
83
+ "command": "npx",
84
+ "args": [
85
+ "@natomalabs/natoma-mcp-gateway",
86
+ "--enterprise"
87
+ ],
88
+ "env": {
89
+ "NATOMA_MCP_SERVER_INSTALLATION_ID": "your-installation-id",
90
+ "NATOMA_MCP_API_KEY": "your-api-key",
91
+ "NATOMA_MCP_CUSTOM_URL": "https://your-custom-endpoint.com/mcp"
92
+ }
93
+ }
94
+ }
95
+ }
96
+ ```
97
+
98
+ For corporate environments with custom certificates:
63
99
 
64
- ### Gateway Modes
100
+ ```json
101
+ {
102
+ "mcpServers": {
103
+ "your-server-name": {
104
+ "command": "npx",
105
+ "args": [
106
+ "@natomalabs/natoma-mcp-gateway",
107
+ "--enterprise"
108
+ ],
109
+ "env": {
110
+ "NATOMA_MCP_SERVER_INSTALLATION_ID": "your-installation-id",
111
+ "NATOMA_MCP_API_KEY": "your-api-key",
112
+ "NODE_EXTRA_CA_CERTS": "/path/to/corporate-ca-bundle.pem"
113
+ }
114
+ }
115
+ }
116
+ }
117
+ ```
65
118
 
66
- #### NMS Gateway (Standard)
119
+ ## Architecture
67
120
 
68
- - Uses EventSource for Server-Sent Events
69
- - Optimized for standard MCP deployments
70
- - Faster reconnection times (1 second)
71
- - HTTP-based message delivery
121
+ ### Enterprise Gateway
72
122
 
73
- #### Enterprise Gateway
123
+ The gateway operates in enterprise mode with the following features:
74
124
 
75
- - Uses fetch API with enhanced features
125
+ - Uses fetch API with enhanced reliability
76
126
  - Support for both JSON and SSE responses
77
127
  - Health check monitoring (every 5 minutes)
78
128
  - Extended timeouts (60 seconds)
79
129
  - Enhanced error recovery
130
+ - Custom endpoint URL support
80
131
 
81
132
  ### Protocol Flow
82
133
 
@@ -92,9 +143,11 @@ The gateway accepts several configuration options through the `MCPConfig` interf
92
143
 
93
144
  - `slug`: Server installation ID (required)
94
145
  - `apiKey`: Authentication API key (required)
146
+ - `isEnterprise`: Must be set to `true` (mandatory for enterprise mode)
147
+ - `customUrl`: Optional custom endpoint URL (overrides default api.natoma.app)
95
148
  - `maxReconnectAttempts`: Maximum reconnection attempts (default: 5)
96
- - `reconnectDelay`: Delay between reconnection attempts (default: 1000ms for NMS, 2000ms for Enterprise)
97
- - `timeout`: Request timeout (default: 30000ms for NMS, 60000ms for Enterprise)
149
+ - `reconnectDelay`: Delay between reconnection attempts (default: 2000ms)
150
+ - `timeout`: Request timeout (default: 60000ms)
98
151
 
99
152
  ## What is MCP?
100
153
 
package/build/base.js CHANGED
@@ -1,5 +1,4 @@
1
1
  // base.ts
2
- export const NATOMA_NMS_SERVER_URL = "https://api.natoma.app/api/mcp";
3
2
  export const NATOMA_ENTERPRISE_SERVER_URL = "https://api.natoma.app/mcp";
4
3
  export const MCP_SESSION_ID_HEADER = "Mcp-Session-Id";
5
4
  // Handle EPIPE errors gracefully
@@ -23,20 +22,24 @@ export class BaseMCPGateway {
23
22
  reconnectDelay;
24
23
  apiKey;
25
24
  constructor(config) {
26
- // Set base URL based on gateway type
27
- this.baseUrl = config?.isEnterprise
28
- ? NATOMA_ENTERPRISE_SERVER_URL
29
- : NATOMA_NMS_SERVER_URL;
25
+ // Validate that config is provided with required isEnterprise flag
26
+ if (!config || config.isEnterprise !== true) {
27
+ throw new Error("Configuration with isEnterprise: true is required for MCP Gateway");
28
+ }
29
+ // Use custom URL if provided, otherwise use enterprise URL
30
+ this.baseUrl = config.customUrl || NATOMA_ENTERPRISE_SERVER_URL;
30
31
  this.maxReconnectAttempts = 3;
31
32
  this.reconnectDelay = 1000;
32
- this.apiKey = config?.apiKey;
33
+ this.apiKey = config.apiKey;
33
34
  // Validate that API key is provided
34
35
  if (!this.apiKey) {
35
36
  throw new Error("API key is required for MCP Gateway");
36
37
  }
37
38
  // Debug logging
38
- console.error(`[BaseMCPGateway] Gateway Type: ${config?.isEnterprise ? "Enterprise" : "NMS"}`);
39
39
  console.error(`[BaseMCPGateway] Base URL set to: ${this.baseUrl}`);
40
+ if (config.customUrl) {
41
+ console.error(`[BaseMCPGateway] Using custom URL`);
42
+ }
40
43
  console.error(`[BaseMCPGateway] API Key: ${this.apiKey ? "PROVIDED" : "NOT PROVIDED"}`);
41
44
  console.error(`[BaseMCPGateway] Max reconnect attempts: ${this.maxReconnectAttempts}`);
42
45
  }
package/build/gateway.js CHANGED
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/env node
2
- import { NMSGateway } from "./nms-gateway.js";
3
2
  import { EnterpriseGateway } from "./ent-gateway.js";
4
3
  // Parse command line arguments
5
4
  function parseArgs() {
6
5
  const args = process.argv.slice(2);
7
- return {
8
- enterprise: args.includes("--enterprise"),
9
- };
6
+ if (!args.includes("--enterprise")) {
7
+ console.error("Error: --enterprise flag is required");
8
+ process.exit(1);
9
+ }
10
10
  }
11
11
  // Main function
12
12
  async function main() {
13
- const { enterprise } = parseArgs();
13
+ parseArgs();
14
14
  const slug = process.env.NATOMA_MCP_SERVER_INSTALLATION_ID;
15
15
  if (!slug) {
16
16
  console.error("Please set NATOMA_MCP_SERVER_INSTALLATION_ID env var");
@@ -20,14 +20,17 @@ async function main() {
20
20
  slug,
21
21
  apiKey: process.env.NATOMA_MCP_API_KEY,
22
22
  maxReconnectAttempts: 5,
23
- reconnectDelay: enterprise ? 2000 : 1000,
24
- timeout: enterprise ? 60000 : undefined,
23
+ reconnectDelay: 2000,
24
+ timeout: 60000,
25
+ isEnterprise: true, // Mandatory flag
26
+ customUrl: process.env.NATOMA_MCP_CUSTOM_URL, // Optional custom URL from env
25
27
  };
26
- // Create appropriate gateway based on flag
27
- const gateway = enterprise
28
- ? new EnterpriseGateway(config)
29
- : new NMSGateway(config);
30
- console.error(`--- Starting ${enterprise ? "Enterprise" : "NMS"} Gateway ---`);
28
+ // Always create Enterprise gateway
29
+ const gateway = new EnterpriseGateway(config);
30
+ console.error(`--- Starting Enterprise Gateway ---`);
31
+ if (config.customUrl) {
32
+ console.error(`--- Using custom URL: ${config.customUrl} ---`);
33
+ }
31
34
  try {
32
35
  await gateway.connect();
33
36
  process.stdin.on("data", (data) => {
@@ -46,8 +49,8 @@ async function main() {
46
49
  console.error("Uncaught exception:", err);
47
50
  shutdown();
48
51
  });
49
- // Optional health check for enterprise gateway
50
- if (enterprise && gateway instanceof EnterpriseGateway) {
52
+ // Health check for enterprise gateway
53
+ if (gateway instanceof EnterpriseGateway) {
51
54
  setInterval(async () => {
52
55
  if (gateway.ready) {
53
56
  const ok = await gateway.healthCheck();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@natomalabs/natoma-mcp-gateway",
3
- "version": "1.0.3",
4
- "description": "Natoma MCP Gateway with NMS and Enterprise modes",
3
+ "version": "1.0.4",
4
+ "description": "Natoma MCP Gateway",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "bin": {
package/build/cli.js DELETED
@@ -1,64 +0,0 @@
1
- import yargs from 'yargs';
2
- import { hideBin } from 'yargs/helpers';
3
- import { setupCommand } from './setup.js';
4
- import { MCPGateway } from './gateway.js';
5
- import chalk from 'chalk';
6
- const startCommand = {
7
- command: 'start',
8
- describe: 'Start the Natoma MCP Gateway',
9
- builder: (yargs) => {
10
- return yargs
11
- .option('url', {
12
- type: 'string',
13
- describe: 'The Natoma MCP URL to connect to',
14
- })
15
- .option('apiKey', {
16
- type: 'string',
17
- describe: 'API key for authentication',
18
- demandOption: true,
19
- })
20
- .option('slug', {
21
- type: 'string',
22
- describe: 'Installation ID/slug for the connection',
23
- });
24
- },
25
- handler: async (argv) => {
26
- try {
27
- const { url, apiKey, slug } = argv;
28
- console.log(chalk.cyan('šŸš€ Starting Natoma MCP Gateway...'));
29
- if (url) {
30
- console.log(chalk.cyan(` URL: ${url}`));
31
- }
32
- if (slug) {
33
- console.log(chalk.cyan(` Installation ID: ${slug}`));
34
- }
35
- const gateway = new MCPGateway({
36
- apiKey: apiKey || process.env.NATOMA_MCP_API_KEY,
37
- slug: slug || process.env.NATOMA_MCP_SERVER_INSTALLATION_ID,
38
- });
39
- await gateway.connect();
40
- console.log(chalk.green('āœ… Connected to Natoma MCP Server'));
41
- process.stdin.on("data", (data) => gateway.processMessage(data));
42
- // Handle cleanup
43
- const cleanup = () => {
44
- console.log(chalk.yellow("Shutting down..."));
45
- gateway.cleanup();
46
- process.exit(0);
47
- };
48
- process.on("SIGINT", cleanup);
49
- process.on("SIGTERM", cleanup);
50
- }
51
- catch (error) {
52
- console.log(chalk.red('\nāŒ Error occurred while starting Natoma MCP Gateway:'));
53
- console.log(chalk.red(` ${error.message}`));
54
- console.log(chalk.yellow('\nPlease try again or contact support if the issue persists.\n'));
55
- process.exit(1);
56
- }
57
- },
58
- };
59
- yargs(hideBin(process.argv))
60
- .command(setupCommand)
61
- .command(startCommand)
62
- .demandCommand(1, 'You need to specify a command.')
63
- .help()
64
- .argv;
@@ -1,131 +0,0 @@
1
- // nms-gateway.ts
2
- import EventSource from "eventsource";
3
- import { BaseMCPGateway } from "./base.js";
4
- // NMS Gateway (Non-Enterprise) - EventSource based
5
- export class NMSGateway extends BaseMCPGateway {
6
- eventSource = null;
7
- sessionId = null;
8
- sseUrl;
9
- messageUrl;
10
- constructor(config) {
11
- // Set isEnterprise to false for NMS Gateway
12
- super({ ...config, isEnterprise: false });
13
- const slug = config?.slug;
14
- this.sseUrl = slug ? `${this.baseUrl}/${slug}` : `${this.baseUrl}`;
15
- this.messageUrl = slug
16
- ? `${this.baseUrl}/${slug}/message`
17
- : `${this.baseUrl}/message`;
18
- // Debug the URLs
19
- console.error(`[NMSGateway] Base URL: ${this.baseUrl}`);
20
- console.error(`[NMSGateway] SSE URL: ${this.sseUrl}`);
21
- console.error(`[NMSGateway] Message URL: ${this.messageUrl}`);
22
- }
23
- async connect() {
24
- if (this.eventSource) {
25
- console.error("Closing existing connection");
26
- this.eventSource.close();
27
- }
28
- return new Promise((resolve, reject) => {
29
- const headers = {
30
- Accept: "text/event-stream",
31
- };
32
- if (this.apiKey) {
33
- headers["Authorization"] = `Bearer ${this.apiKey}`;
34
- }
35
- this.eventSource = new EventSource(this.sseUrl, { headers });
36
- this.eventSource.onopen = () => {
37
- console.error("--- SSE backend connected");
38
- this.reconnectAttempts = 0;
39
- resolve();
40
- };
41
- this.eventSource.onerror = (error) => {
42
- console.error(`--- SSE backend error: ${error?.message}`);
43
- this.handleConnectionError(error);
44
- reject(error);
45
- };
46
- this.setupEventListeners();
47
- });
48
- }
49
- setupEventListeners() {
50
- if (!this.eventSource)
51
- return;
52
- this.eventSource.addEventListener("endpoint", (event) => {
53
- const match = event.data.match(/sessionId=([^&]+)/);
54
- if (match) {
55
- this.sessionId = match[1];
56
- this.isReady = true;
57
- console.error(`Session established: ${this.sessionId}`);
58
- this.processQueuedMessages();
59
- }
60
- });
61
- this.eventSource.addEventListener("message", (event) => {
62
- try {
63
- console.error(`<-- ${event.data}`);
64
- console.log(event.data);
65
- }
66
- catch (error) {
67
- console.error(`Error handling message: ${error}`);
68
- }
69
- });
70
- }
71
- async handleConnectionError(error) {
72
- console.error(`Connection error: ${error.message}`);
73
- if (this.eventSource?.readyState === EventSource.CLOSED) {
74
- console.error("EventSource connection closed");
75
- await this.reconnect();
76
- }
77
- }
78
- async reconnect() {
79
- if (this.reconnectAttempts >= this.maxReconnectAttempts) {
80
- console.error(`Max reconnection attempts (${this.maxReconnectAttempts}) reached, exiting...`);
81
- process.exit(1);
82
- }
83
- this.reconnectAttempts++;
84
- this.isReady = false;
85
- try {
86
- await new Promise((resolve) => setTimeout(resolve, this.reconnectDelay));
87
- await this.connect();
88
- }
89
- catch (error) {
90
- console.error(`Reconnection failed: ${error}`);
91
- }
92
- }
93
- async processMessage(input) {
94
- if (!this.isReady || !this.sessionId) {
95
- this.messageQueue.push(input);
96
- return;
97
- }
98
- const message = input.toString().trim();
99
- console.error(`--> ${message}`);
100
- try {
101
- const url = `${this.messageUrl}?sessionId=${this.sessionId}`;
102
- const headers = {
103
- "Content-Type": "application/json",
104
- };
105
- if (this.apiKey) {
106
- headers["Authorization"] = `Bearer ${this.apiKey}`;
107
- }
108
- const response = await fetch(url, {
109
- method: "POST",
110
- headers,
111
- body: message,
112
- });
113
- if (!response.ok) {
114
- if (response.status === 503) {
115
- await this.reconnect();
116
- }
117
- else {
118
- console.error(`Error from server: ${response.status} ${response.statusText}`);
119
- }
120
- }
121
- }
122
- catch (error) {
123
- console.error(`Request error: ${error}`);
124
- }
125
- }
126
- cleanup() {
127
- if (this.eventSource) {
128
- this.eventSource.close();
129
- }
130
- }
131
- }
package/build/setup.js DELETED
@@ -1,186 +0,0 @@
1
- // setup.ts
2
- import fs from "fs";
3
- import path from "path";
4
- import os from "os";
5
- import chalk from "chalk";
6
- export const setupCommand = {
7
- command: "setup <url>",
8
- describe: "Setup command for Natoma MCP Gateway integration",
9
- builder: (yargs) => {
10
- return yargs
11
- .positional("url", {
12
- type: "string",
13
- describe: "The Natoma MCP URL to use",
14
- demandOption: true,
15
- })
16
- .option("client", {
17
- type: "string",
18
- describe: "Client to use (claude, windsurf, cursor)",
19
- default: "claude",
20
- choices: ["claude", "windsurf", "cursor"],
21
- })
22
- .option("apiKey", {
23
- type: "string",
24
- describe: "API key for authentication",
25
- demandOption: true,
26
- });
27
- },
28
- handler: async (argv) => {
29
- const { url, client, apiKey } = argv;
30
- try {
31
- console.log(chalk.cyan("šŸ“ Configuration Details:"));
32
- console.log(` URL: ${chalk.green(url)}`);
33
- console.log(` Client: ${chalk.green(client)}`);
34
- if (apiKey) {
35
- console.log(` API Key: ${chalk.green("****" + apiKey.slice(-4))}`);
36
- }
37
- console.log("");
38
- console.log(chalk.cyan("šŸ’¾ Saving configurations..."));
39
- saveMcpConfig(url, client, apiKey);
40
- console.log(chalk.cyan(`\nšŸš€ All done! Please restart ${client} for changes to take effect\n`));
41
- }
42
- catch (error) {
43
- console.log(chalk.red("\nāŒ Error occurred while setting up Natoma MCP:"));
44
- console.log(chalk.red(` ${error.message}`));
45
- console.log(chalk.yellow("\nPlease try again or contact support if the issue persists.\n"));
46
- }
47
- },
48
- };
49
- function saveMcpConfig(url, clientType, apiKey) {
50
- // Create config object for the gateway
51
- const config = {
52
- command: "npx",
53
- args: ["@natomalabs/natoma-mcp-gateway@latest", "start", "--url", url],
54
- env: {
55
- npm_config_yes: "true",
56
- },
57
- };
58
- // If API key is provided, add it to the environment variables
59
- if (apiKey) {
60
- config.env["NATOMA_MCP_API_KEY"] = apiKey;
61
- // Also add it to the args so it's passed to the start command
62
- config.args.push("--apiKey", apiKey);
63
- }
64
- // Extract installation ID from URL for Cursor
65
- const urlParts = url.split("/");
66
- const installationId = urlParts[urlParts.length - 1];
67
- const sseConfig = {
68
- url: url,
69
- apiKey: apiKey,
70
- slug: installationId,
71
- };
72
- const homeDir = os.homedir();
73
- // Define platform-specific paths
74
- const platformPaths = {
75
- win32: {
76
- baseDir: process.env.APPDATA || path.join(homeDir, "AppData", "Roaming"),
77
- vscodePath: path.join("Code", "User", "globalStorage"),
78
- },
79
- darwin: {
80
- baseDir: path.join(homeDir, "Library", "Application Support"),
81
- vscodePath: path.join("Code", "User", "globalStorage"),
82
- },
83
- linux: {
84
- baseDir: process.env.XDG_CONFIG_HOME || path.join(homeDir, ".config"),
85
- vscodePath: path.join("Code/User/globalStorage"),
86
- },
87
- };
88
- const platform = process.platform;
89
- // Check if platform is supported
90
- if (!platformPaths[platform]) {
91
- console.log(chalk.yellow(`\nāš ļø Platform ${platform} is not supported.`));
92
- return;
93
- }
94
- const { baseDir } = platformPaths[platform];
95
- // Define client-specific paths
96
- const clientPaths = {
97
- claude: {
98
- configDir: path.join(baseDir, "Claude"),
99
- configPath: path.join(baseDir, "Claude", "claude_desktop_config.json"),
100
- },
101
- windsurf: {
102
- configDir: path.join(homeDir, ".codeium", "windsurf"),
103
- configPath: path.join(homeDir, ".codeium", "windsurf", "mcp_config.json"),
104
- },
105
- cursor: {
106
- configDir: path.join(homeDir, ".cursor"),
107
- configPath: path.join(homeDir, ".cursor", "mcp.json"),
108
- },
109
- };
110
- if (!clientPaths[clientType]) {
111
- console.log(chalk.yellow(`\nāš ļø Client ${clientType} is not supported.`));
112
- return;
113
- }
114
- const { configDir, configPath } = clientPaths[clientType];
115
- // Create config directory if it doesn't exist
116
- if (!fs.existsSync(configDir)) {
117
- fs.mkdirSync(configDir, { recursive: true });
118
- }
119
- // Handle client-specific configuration format
120
- if (clientType === "claude") {
121
- let claudeConfig = { mcpServers: {} };
122
- if (fs.existsSync(configPath)) {
123
- try {
124
- claudeConfig = JSON.parse(fs.readFileSync(configPath, "utf8"));
125
- }
126
- catch (error) {
127
- console.log(chalk.yellow("āš ļø Creating new config file"));
128
- }
129
- }
130
- // Ensure mcpServers exists
131
- if (!claudeConfig.mcpServers)
132
- claudeConfig.mcpServers = {};
133
- // Update only the mcpServers entry
134
- claudeConfig.mcpServers[url] = config;
135
- fs.writeFileSync(configPath, JSON.stringify(claudeConfig, null, 2));
136
- console.log(chalk.green(`āœ… Configuration saved to: ${configPath}`));
137
- }
138
- else if (clientType === "windsurf") {
139
- let windsurfConfig = { mcpServers: {} };
140
- if (fs.existsSync(configPath)) {
141
- try {
142
- windsurfConfig = JSON.parse(fs.readFileSync(configPath, "utf8"));
143
- }
144
- catch (error) {
145
- console.log(chalk.yellow("āš ļø Creating new config file"));
146
- }
147
- }
148
- // Ensure mcpServers exists
149
- if (!windsurfConfig.mcpServers)
150
- windsurfConfig.mcpServers = {};
151
- // Now TypeScript knows mcpServers exists
152
- windsurfConfig.mcpServers[url] = config;
153
- fs.writeFileSync(configPath, JSON.stringify(windsurfConfig, null, 2));
154
- console.log(chalk.green(`āœ… Configuration saved to: ${configPath}`));
155
- }
156
- else if (clientType === "cursor") {
157
- let cursorConfig = { mcpServers: {} };
158
- if (fs.existsSync(configPath)) {
159
- try {
160
- cursorConfig = JSON.parse(fs.readFileSync(configPath, "utf8"));
161
- }
162
- catch (error) {
163
- console.log(chalk.yellow("āš ļø Creating new config file"));
164
- }
165
- }
166
- // Ensure mcpServers exists
167
- if (!cursorConfig.mcpServers)
168
- cursorConfig.mcpServers = {};
169
- // Remove existing config if it exists
170
- if (cursorConfig.mcpServers[url]) {
171
- delete cursorConfig.mcpServers[url];
172
- }
173
- try {
174
- // Create a unique key for Cursor's configuration
175
- const newKey = `natoma_${installationId}`;
176
- cursorConfig.mcpServers[newKey] = sseConfig;
177
- fs.writeFileSync(configPath, JSON.stringify(cursorConfig, null, 2));
178
- console.log(chalk.green(`āœ… Configuration saved to: ${configPath}`));
179
- }
180
- catch (error) {
181
- console.log(chalk.red("āŒ Error occurred while setting up MCP:"));
182
- console.log(chalk.red(` ${error.message}`));
183
- console.log(chalk.yellow("\nPlease try again or contact support if the issue persists.\n"));
184
- }
185
- }
186
- }