mcp-config-manager 1.0.7 → 1.0.9

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
@@ -149,11 +149,13 @@ This tool supports auto-detection of any client that follows the Model Context P
149
149
 
150
150
  - **Amazon Q Developer**: `~/.aws/amazonq/mcp.json`
151
151
  - **Claude Desktop**: `~/Library/Application Support/Claude/claude_desktop_config.json`
152
- - **Claude Code**: `.mcp.json` in project root
152
+ - **Claude Code**: `~/.claude.json` (global settings and MCP servers)
153
153
  - **Cline**: `~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json`
154
+ - **Codex**: `~/.codex/config.toml` (TOML with `[mcp_servers.<name>]` tables)
154
155
  - **Cursor**: `.cursor/mcp.json` (project-specific) or `~/.cursor/mcp.json` (global)
155
156
  - **Factory Bridge**: `~/Library/Application Support/Factory Bridge/mcp.json`
156
157
  - **Gemini**: `~/.gemini/settings.json`
158
+ - **Google AntiGravity**: `~/.gemini/antigravity/mcp_config.json`
157
159
  - **Roo Code**: `~/Library/Application Support/Code/User/globalStorage/rooveterinaryinc.roo-cline/settings/cline_mcp_settings.json`
158
160
  - **VS Code**: `.vscode/mcp.json`
159
161
  - **Windsurf**: `~/.codeium/windsurf/mcp_config.json` or `~/AppData/Roaming/WindSurf/mcp_settings.json` (Windows)
@@ -162,7 +164,7 @@ This tool supports auto-detection of any client that follows the Model Context P
162
164
 
163
165
  ## Configuration Format
164
166
 
165
- Standard MCP server configuration:
167
+ Standard MCP server configuration (JSON-based clients like Claude Desktop, Claude Code, Cursor, VS Code, etc.):
166
168
  ```json
167
169
  {
168
170
  "mcpServers": {
@@ -177,6 +179,18 @@ Standard MCP server configuration:
177
179
  }
178
180
  ```
179
181
 
182
+ Codex uses a TOML configuration file at `~/.codex/config.toml`, where MCP servers are defined under the `[mcp_servers.<server-name>]` tables. For example:
183
+
184
+ ```toml
185
+ [mcp_servers.context7]
186
+ command = "npx"
187
+ args = ["-y", "@upstash/context7-mcp"]
188
+
189
+ [mcp_servers.figma]
190
+ url = "https://mcp.figma.com/mcp"
191
+ bearer_token_env_var = "FIGMA_OAUTH_TOKEN"
192
+ ```
193
+
180
194
  ## Security Note
181
195
 
182
196
  Environment variables may contain sensitive data like API keys. The tool masks values containing "KEY" or "SECRET" in the display but stores them in plain text in config files.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-config-manager",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "Simple CLI and web UI to manage MCP configs across multiple AI clients",
5
5
  "main": "src/cli.js",
6
6
  "bin": {
@@ -40,6 +40,7 @@
40
40
  ],
41
41
  "type": "module",
42
42
  "dependencies": {
43
+ "@iarna/toml": "^3.0.0",
43
44
  "commander": "^14.0.1",
44
45
  "cors": "^2.8.5",
45
46
  "express": "^5.1.0"
@@ -0,0 +1,35 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ import os from 'os';
4
+
5
+ async function getProjectConfig(projectPath) {
6
+ const configPath = path.join(projectPath, '.mcp.json');
7
+ try {
8
+ const content = await fs.readFile(configPath, 'utf-8');
9
+ return JSON.parse(content);
10
+ } catch (error) {
11
+ if (error.code === 'ENOENT') {
12
+ return null; // File not found
13
+ }
14
+ throw error;
15
+ }
16
+ }
17
+
18
+ async function getUserConfig() {
19
+ const homeDir = os.homedir();
20
+ const configPath = path.join(homeDir, '.mcp.json');
21
+ try {
22
+ const content = await fs.readFile(configPath, 'utf-8');
23
+ return JSON.parse(content);
24
+ } catch (error) {
25
+ if (error.code === 'ENOENT') {
26
+ return null; // File not found
27
+ }
28
+ throw error;
29
+ }
30
+ }
31
+
32
+ export {
33
+ getProjectConfig,
34
+ getUserConfig,
35
+ };
package/src/clients.js CHANGED
@@ -14,9 +14,9 @@ export const CLIENTS = {
14
14
  'claude-code': {
15
15
  name: 'Claude Code',
16
16
  configPaths: {
17
- darwin: '.mcp.json',
18
- win32: '.mcp.json',
19
- linux: '.mcp.json'
17
+ darwin: path.join(os.homedir(), '.claude.json'),
18
+ win32: path.join(os.homedir(), '.claude.json'),
19
+ linux: path.join(os.homedir(), '.claude.json')
20
20
  },
21
21
  format: 'mcpServers'
22
22
  },
@@ -74,6 +74,15 @@ export const CLIENTS = {
74
74
  },
75
75
  format: 'mcpServers'
76
76
  },
77
+ codex: {
78
+ name: 'Codex',
79
+ configPaths: {
80
+ darwin: path.join(os.homedir(), '.codex/config.toml'),
81
+ win32: path.join(os.homedir(), '.codex/config.toml'),
82
+ linux: path.join(os.homedir(), '.codex/config.toml')
83
+ },
84
+ format: 'codex'
85
+ },
77
86
  '5ire': {
78
87
  name: '5ire',
79
88
  configPaths: {
@@ -109,5 +118,14 @@ export const CLIENTS = {
109
118
  linux: path.join(os.homedir(), '.config/Code/User/globalStorage/rooveterinaryinc.roo-cline/settings/cline_mcp_settings.json')
110
119
  },
111
120
  format: 'mcpServers'
121
+ },
122
+ 'google-antigravity': {
123
+ name: 'Google AntiGravity',
124
+ configPaths: {
125
+ darwin: path.join(os.homedir(), '.gemini/antigravity/mcp_config.json'),
126
+ win32: path.join(os.homedir(), '.gemini/antigravity/mcp_config.json'),
127
+ linux: path.join(os.homedir(), '.gemini/antigravity/mcp_config.json')
128
+ },
129
+ format: 'mcpServers'
112
130
  }
113
131
  };
@@ -1,6 +1,7 @@
1
1
  import * as fs from 'fs/promises';
2
2
  import path from 'path';
3
3
  import os from 'os';
4
+ import TOML from '@iarna/toml';
4
5
 
5
6
  import { CLIENTS as PROD_CLIENTS } from './clients.js';
6
7
 
@@ -223,11 +224,15 @@ export class MCPConfigManager {
223
224
  const configPath = await this.getConfigPath(client);
224
225
  let clientConfig = { servers: {} };
225
226
 
227
+ const clients = await this.getClients();
228
+ const clientInfo = clients[client];
229
+
226
230
  try {
227
231
  const content = await fs.readFile(configPath, 'utf-8');
228
- const parsedContent = JSON.parse(content);
229
- const clients = await this.getClients();
230
- clientConfig = this.normalizeConfig(parsedContent, clients[client].format);
232
+ const parsedContent = clientInfo.format === 'codex'
233
+ ? TOML.parse(content)
234
+ : JSON.parse(content);
235
+ clientConfig = this.normalizeConfig(parsedContent, clientInfo.format);
231
236
  } catch (error) {
232
237
  if (error.code !== 'ENOENT') {
233
238
  throw error;
@@ -251,6 +256,9 @@ export class MCPConfigManager {
251
256
  return { servers: config.mcpServers || {} };
252
257
  } else if (format === 'mcp.servers') {
253
258
  return { servers: config.mcp?.servers || {} };
259
+ } else if (format === 'codex') {
260
+ // Codex stores MCP servers under [mcp_servers.<server-name>] tables in config.toml
261
+ return { servers: config.mcp_servers || {} };
254
262
  }
255
263
  return { servers: {} };
256
264
  }
@@ -266,6 +274,15 @@ export class MCPConfigManager {
266
274
  servers: normalizedConfig.servers
267
275
  }
268
276
  };
277
+ } else if (format === 'codex') {
278
+ // Preserve other Codex settings and update only the mcp_servers table
279
+ return {
280
+ ...originalConfig,
281
+ mcp_servers: {
282
+ ...(originalConfig.mcp_servers || {}),
283
+ ...normalizedConfig.servers
284
+ }
285
+ };
269
286
  }
270
287
  return originalConfig;
271
288
  }
@@ -278,7 +295,9 @@ export class MCPConfigManager {
278
295
  let originalConfig = {};
279
296
  try {
280
297
  const content = await fs.readFile(configPath, 'utf-8');
281
- originalConfig = JSON.parse(content);
298
+ originalConfig = clientConfig.format === 'codex'
299
+ ? TOML.parse(content)
300
+ : JSON.parse(content);
282
301
  } catch (error) {
283
302
  // File doesn't exist, that's OK
284
303
  }
@@ -286,7 +305,12 @@ export class MCPConfigManager {
286
305
  const finalConfig = this.denormalizeConfig(config, clientConfig.format, originalConfig);
287
306
 
288
307
  await fs.mkdir(path.dirname(configPath), { recursive: true });
289
- await fs.writeFile(configPath, JSON.stringify(finalConfig, null, 2));
308
+
309
+ if (clientConfig.format === 'codex') {
310
+ await fs.writeFile(configPath, TOML.stringify(finalConfig));
311
+ } else {
312
+ await fs.writeFile(configPath, JSON.stringify(finalConfig, null, 2));
313
+ }
290
314
  }
291
315
 
292
316