ai-account-switch 1.9.0 → 1.12.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.
- package/.playwright-mcp/grid-view-before.png +0 -0
- package/.playwright-mcp/list-view.png +0 -0
- package/CLAUDE.md +338 -0
- package/README.md +3 -1
- package/package.json +45 -45
- package/src/accounts/base-account.js +39 -0
- package/src/accounts/ccr-account.js +118 -0
- package/src/accounts/claude-account.js +62 -0
- package/src/accounts/codex-account.js +192 -0
- package/src/accounts/droids-account.js +80 -0
- package/src/accounts/index.js +29 -0
- package/src/commands/account.js +68 -0
- package/src/commands/env.js +728 -0
- package/src/commands/helpers.js +32 -0
- package/src/commands/index.js +22 -1
- package/src/commands/mcp.js +71 -13
- package/src/config/global-config.js +266 -0
- package/src/config/project-config.js +255 -0
- package/src/config.js +129 -1300
- package/src/config.js.bak +1593 -0
- package/src/constants.js +86 -0
- package/src/generators/base-generator.js +124 -0
- package/src/generators/ccr-generator.js +113 -0
- package/src/generators/claude-generator.js +124 -0
- package/src/generators/codex-generator.js +207 -0
- package/src/generators/droids-generator.js +49 -0
- package/src/generators/index.js +29 -0
- package/src/index.js +63 -1
- package/src/mcp/mcp-manager.js +309 -0
- package/src/ui-server.js +1093 -9
package/src/commands/helpers.js
CHANGED
|
@@ -9,6 +9,37 @@ function maskApiKey(apiKey) {
|
|
|
9
9
|
return `${apiKey.substring(0, 4)}****${apiKey.substring(apiKey.length - 4)}`;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Mask sensitive value for display
|
|
14
|
+
* Shows first 2 chars + fixed 6 stars + last 2 chars for sensitive variables
|
|
15
|
+
* 用于显示敏感环境变量值,前2字符+固定6星号+后2字符
|
|
16
|
+
* @param {string} key - Variable name to check if sensitive
|
|
17
|
+
* @param {string} value - Value to mask
|
|
18
|
+
* @returns {string} Masked value or original value if not sensitive
|
|
19
|
+
*/
|
|
20
|
+
function maskEnvValue(key, value) {
|
|
21
|
+
if (!key || !value) return value;
|
|
22
|
+
|
|
23
|
+
// Check if variable name contains sensitive keywords
|
|
24
|
+
const isSensitive = key.includes('KEY') || key.includes('TOKEN') || key.includes('SECRET') || key.includes('PASSWORD');
|
|
25
|
+
|
|
26
|
+
if (!isSensitive) {
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// For sensitive values, show first 2 + fixed 6 stars + last 2
|
|
31
|
+
const strValue = String(value);
|
|
32
|
+
if (strValue.length <= 4) {
|
|
33
|
+
// If value is too short, show all stars
|
|
34
|
+
return '*'.repeat(strValue.length);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const firstTwo = strValue.substring(0, 2);
|
|
38
|
+
const lastTwo = strValue.substring(strValue.length - 2);
|
|
39
|
+
|
|
40
|
+
return firstTwo + '******' + lastTwo;
|
|
41
|
+
}
|
|
42
|
+
|
|
12
43
|
/**
|
|
13
44
|
* Validate account by testing API key
|
|
14
45
|
* 验证账号的 API key 是否有效
|
|
@@ -31,5 +62,6 @@ async function validateAccount(apiKey, apiUrl) {
|
|
|
31
62
|
|
|
32
63
|
module.exports = {
|
|
33
64
|
maskApiKey,
|
|
65
|
+
maskEnvValue,
|
|
34
66
|
validateAccount
|
|
35
67
|
};
|
package/src/commands/index.js
CHANGED
|
@@ -42,6 +42,17 @@ const {
|
|
|
42
42
|
testMcpServer
|
|
43
43
|
} = require('./mcp');
|
|
44
44
|
|
|
45
|
+
const {
|
|
46
|
+
listEnv,
|
|
47
|
+
addEnv,
|
|
48
|
+
setEnv,
|
|
49
|
+
removeEnv,
|
|
50
|
+
unsetEnv,
|
|
51
|
+
showEnv,
|
|
52
|
+
clearEnv,
|
|
53
|
+
editEnv
|
|
54
|
+
} = require('./env');
|
|
55
|
+
|
|
45
56
|
module.exports = {
|
|
46
57
|
// Account management commands
|
|
47
58
|
addAccount,
|
|
@@ -74,5 +85,15 @@ module.exports = {
|
|
|
74
85
|
disableMcpServer,
|
|
75
86
|
showEnabledMcpServers,
|
|
76
87
|
syncMcpConfig,
|
|
77
|
-
testMcpServer
|
|
88
|
+
testMcpServer,
|
|
89
|
+
|
|
90
|
+
// Environment variable management commands
|
|
91
|
+
listEnv,
|
|
92
|
+
addEnv,
|
|
93
|
+
setEnv,
|
|
94
|
+
removeEnv,
|
|
95
|
+
unsetEnv,
|
|
96
|
+
showEnv,
|
|
97
|
+
clearEnv,
|
|
98
|
+
editEnv
|
|
78
99
|
};
|
package/src/commands/mcp.js
CHANGED
|
@@ -10,6 +10,8 @@ const config = new ConfigManager();
|
|
|
10
10
|
*/
|
|
11
11
|
async function addMcpServer(name) {
|
|
12
12
|
try {
|
|
13
|
+
const { MCP_SCOPES, DEFAULT_MCP_SCOPE } = require('../config');
|
|
14
|
+
|
|
13
15
|
if (!name) {
|
|
14
16
|
const { serverName } = await inquirer.prompt([{
|
|
15
17
|
type: 'input',
|
|
@@ -79,8 +81,22 @@ async function addMcpServer(name) {
|
|
|
79
81
|
const { description } = await inquirer.prompt([{ type: 'input', name: 'description', message: 'Enter description:', default: '' }]);
|
|
80
82
|
serverData.description = description;
|
|
81
83
|
|
|
84
|
+
// Ask for default scope
|
|
85
|
+
const { scope } = await inquirer.prompt([{
|
|
86
|
+
type: 'list',
|
|
87
|
+
name: 'scope',
|
|
88
|
+
message: 'Select default scope (默认作用范围):',
|
|
89
|
+
choices: [
|
|
90
|
+
{ name: 'local - Only current project (仅当前项目)', value: MCP_SCOPES.LOCAL },
|
|
91
|
+
{ name: 'project - Share with project members (与项目成员共享)', value: MCP_SCOPES.PROJECT },
|
|
92
|
+
{ name: 'user - All projects for current user (当前用户所有项目)', value: MCP_SCOPES.USER }
|
|
93
|
+
],
|
|
94
|
+
default: DEFAULT_MCP_SCOPE
|
|
95
|
+
}]);
|
|
96
|
+
serverData.scope = scope;
|
|
97
|
+
|
|
82
98
|
config.addMcpServer(name, serverData);
|
|
83
|
-
console.log(chalk.green(`✓ MCP server '${name}' added successfully!`));
|
|
99
|
+
console.log(chalk.green(`✓ MCP server '${name}' added successfully with scope: ${scope}!`));
|
|
84
100
|
|
|
85
101
|
// Auto-test the server
|
|
86
102
|
console.log(chalk.cyan('\nTesting server availability...'));
|
|
@@ -101,7 +117,7 @@ async function addMcpServer(name) {
|
|
|
101
117
|
*/
|
|
102
118
|
async function listMcpServers() {
|
|
103
119
|
try {
|
|
104
|
-
const servers = config.
|
|
120
|
+
const servers = config.getAllAvailableMcpServers();
|
|
105
121
|
const projectServers = config.getEnabledMcpServers();
|
|
106
122
|
|
|
107
123
|
if (Object.keys(servers).length === 0) {
|
|
@@ -110,12 +126,16 @@ async function listMcpServers() {
|
|
|
110
126
|
}
|
|
111
127
|
|
|
112
128
|
console.log(chalk.bold.cyan('\n📋 Available MCP servers:\n'));
|
|
113
|
-
console.log(' Name Type Active Description');
|
|
114
|
-
console.log('
|
|
115
|
-
|
|
116
|
-
Object.
|
|
117
|
-
const
|
|
118
|
-
|
|
129
|
+
console.log(' Name Type Active Scope Description');
|
|
130
|
+
console.log(' ───────────────────────────────────────────────────────────────────────');
|
|
131
|
+
|
|
132
|
+
Object.entries(servers).forEach(([key, server]) => {
|
|
133
|
+
const name = server.name || key;
|
|
134
|
+
const type = server.type || 'unknown';
|
|
135
|
+
const isActive = projectServers.includes(name) ? chalk.green('✓') : ' ';
|
|
136
|
+
const scope = server.scope || 'local';
|
|
137
|
+
const scopeDisplay = scope.padEnd(10);
|
|
138
|
+
console.log(` ${name.padEnd(12)} ${type.padEnd(7)} ${isActive} ${scopeDisplay} ${server.description || ''}`);
|
|
119
139
|
});
|
|
120
140
|
|
|
121
141
|
const activeCount = projectServers.length;
|
|
@@ -133,7 +153,7 @@ async function listMcpServers() {
|
|
|
133
153
|
async function showMcpServer(name) {
|
|
134
154
|
try {
|
|
135
155
|
if (!name) {
|
|
136
|
-
const servers = config.
|
|
156
|
+
const servers = config.getAllAvailableMcpServers();
|
|
137
157
|
if (Object.keys(servers).length === 0) {
|
|
138
158
|
console.log(chalk.yellow('No MCP servers configured'));
|
|
139
159
|
return;
|
|
@@ -155,6 +175,7 @@ async function showMcpServer(name) {
|
|
|
155
175
|
|
|
156
176
|
console.log(chalk.bold.cyan(`\n📋 MCP Server: ${name}\n`));
|
|
157
177
|
console.log(chalk.bold('Type:'), server.type);
|
|
178
|
+
console.log(chalk.bold('Scope:'), server.scope || 'local');
|
|
158
179
|
console.log(chalk.bold('Description:'), server.description || 'N/A');
|
|
159
180
|
|
|
160
181
|
if (server.command) console.log(chalk.bold('Command:'), server.command);
|
|
@@ -322,8 +343,17 @@ async function removeMcpServer(name) {
|
|
|
322
343
|
/**
|
|
323
344
|
* Enable MCP server for current project
|
|
324
345
|
*/
|
|
325
|
-
async function enableMcpServer(name) {
|
|
346
|
+
async function enableMcpServer(name, options = {}) {
|
|
326
347
|
try {
|
|
348
|
+
const { MCP_SCOPES, DEFAULT_MCP_SCOPE } = require('../config');
|
|
349
|
+
let scope = options.scope || DEFAULT_MCP_SCOPE;
|
|
350
|
+
|
|
351
|
+
// Validate scope
|
|
352
|
+
if (!Object.values(MCP_SCOPES).includes(scope)) {
|
|
353
|
+
console.log(chalk.red(`✗ Invalid scope '${scope}'. Valid scopes: local, project, user`));
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
|
|
327
357
|
if (!name) {
|
|
328
358
|
const servers = config.getAllMcpServers();
|
|
329
359
|
const enabled = config.getEnabledMcpServers();
|
|
@@ -341,12 +371,38 @@ async function enableMcpServer(name) {
|
|
|
341
371
|
choices: available
|
|
342
372
|
}]);
|
|
343
373
|
name = serverName;
|
|
374
|
+
|
|
375
|
+
// Ask for scope if not provided
|
|
376
|
+
if (!options.scope) {
|
|
377
|
+
const { selectedScope } = await inquirer.prompt([{
|
|
378
|
+
type: 'list',
|
|
379
|
+
name: 'selectedScope',
|
|
380
|
+
message: 'Select scope (作用范围):',
|
|
381
|
+
choices: [
|
|
382
|
+
{ name: 'local - Only current project (仅当前项目)', value: MCP_SCOPES.LOCAL },
|
|
383
|
+
{ name: 'project - Share with project members via .mcp.json (通过 .mcp.json 与项目成员共享)', value: MCP_SCOPES.PROJECT },
|
|
384
|
+
{ name: 'user - All projects for current user (当前用户所有项目)', value: MCP_SCOPES.USER }
|
|
385
|
+
],
|
|
386
|
+
default: DEFAULT_MCP_SCOPE
|
|
387
|
+
}]);
|
|
388
|
+
scope = selectedScope;
|
|
389
|
+
}
|
|
344
390
|
}
|
|
345
391
|
|
|
346
|
-
if (config.enableProjectMcpServer(name)) {
|
|
392
|
+
if (config.enableProjectMcpServer(name, scope)) {
|
|
347
393
|
config.syncMcpConfig();
|
|
348
|
-
console.log(chalk.green(`✓ MCP server '${name}' activated for current project`));
|
|
394
|
+
console.log(chalk.green(`✓ MCP server '${name}' activated for current project with scope: ${scope}`));
|
|
349
395
|
console.log(chalk.green('✓ Claude configuration updated'));
|
|
396
|
+
|
|
397
|
+
// Show scope-specific information
|
|
398
|
+
if (scope === MCP_SCOPES.LOCAL) {
|
|
399
|
+
console.log(chalk.cyan(' Scope: local - Only available in this project'));
|
|
400
|
+
} else if (scope === MCP_SCOPES.PROJECT) {
|
|
401
|
+
console.log(chalk.cyan(' Scope: project - Configuration stored in project, shared with team members'));
|
|
402
|
+
console.log(chalk.gray(' Note: Make sure to commit .ais-project-config to share with your team'));
|
|
403
|
+
} else if (scope === MCP_SCOPES.USER) {
|
|
404
|
+
console.log(chalk.cyan(' Scope: user - Available to all your projects'));
|
|
405
|
+
}
|
|
350
406
|
} else {
|
|
351
407
|
console.log(chalk.red(`✗ MCP server '${name}' not found`));
|
|
352
408
|
}
|
|
@@ -408,7 +464,9 @@ async function showEnabledMcpServers() {
|
|
|
408
464
|
enabled.forEach(name => {
|
|
409
465
|
const server = servers[name];
|
|
410
466
|
if (server) {
|
|
411
|
-
|
|
467
|
+
const serverName = server.name || name;
|
|
468
|
+
const type = server.type || 'unknown';
|
|
469
|
+
console.log(` ${String(serverName).padEnd(12)} ${String(type).padEnd(7)} ${server.description || ''}`);
|
|
412
470
|
}
|
|
413
471
|
});
|
|
414
472
|
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global Configuration Manager
|
|
3
|
+
* Handles global configuration operations (accounts, MCP servers in home directory)
|
|
4
|
+
*/
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const os = require('os');
|
|
8
|
+
const { CONFIG_FILES } = require('../constants');
|
|
9
|
+
|
|
10
|
+
class GlobalConfigManager {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.globalConfigDir = path.join(os.homedir(), CONFIG_FILES.GLOBAL_DIR);
|
|
13
|
+
this.globalConfigFile = path.join(this.globalConfigDir, CONFIG_FILES.GLOBAL_CONFIG);
|
|
14
|
+
this.projectConfigFilename = '.ais-project-config';
|
|
15
|
+
this.ensureConfigExists();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Ensure configuration directories and files exist
|
|
20
|
+
*/
|
|
21
|
+
ensureConfigExists() {
|
|
22
|
+
if (!fs.existsSync(this.globalConfigDir)) {
|
|
23
|
+
fs.mkdirSync(this.globalConfigDir, { recursive: true });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!fs.existsSync(this.globalConfigFile)) {
|
|
27
|
+
this.save({ accounts: {}, mcpServers: {}, nextAccountId: 1 });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
this.migrateAccountIds();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Find project root by searching upwards for .ais-project-config file
|
|
35
|
+
*/
|
|
36
|
+
findProjectRoot(startDir = process.cwd()) {
|
|
37
|
+
let currentDir = path.resolve(startDir);
|
|
38
|
+
const rootDir = path.parse(currentDir).root;
|
|
39
|
+
|
|
40
|
+
while (currentDir !== rootDir) {
|
|
41
|
+
const configPath = path.join(currentDir, this.projectConfigFilename);
|
|
42
|
+
if (fs.existsSync(configPath)) {
|
|
43
|
+
return currentDir;
|
|
44
|
+
}
|
|
45
|
+
currentDir = path.dirname(currentDir);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const configPath = path.join(rootDir, this.projectConfigFilename);
|
|
49
|
+
if (fs.existsSync(configPath)) {
|
|
50
|
+
return rootDir;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Read global configuration
|
|
58
|
+
*/
|
|
59
|
+
read() {
|
|
60
|
+
try {
|
|
61
|
+
const data = fs.readFileSync(this.globalConfigFile, 'utf8');
|
|
62
|
+
const config = JSON.parse(data);
|
|
63
|
+
if (!config.nextAccountId) {
|
|
64
|
+
config.nextAccountId = 1;
|
|
65
|
+
}
|
|
66
|
+
return config;
|
|
67
|
+
} catch (error) {
|
|
68
|
+
return { accounts: {}, mcpServers: {}, nextAccountId: 1 };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Save global configuration
|
|
74
|
+
*/
|
|
75
|
+
save(config) {
|
|
76
|
+
fs.writeFileSync(this.globalConfigFile, JSON.stringify(config, null, 2), 'utf8');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Migrate existing accounts to have IDs
|
|
81
|
+
*/
|
|
82
|
+
migrateAccountIds() {
|
|
83
|
+
const config = this.read();
|
|
84
|
+
let needsSave = false;
|
|
85
|
+
|
|
86
|
+
if (!config.nextAccountId) {
|
|
87
|
+
config.nextAccountId = 1;
|
|
88
|
+
needsSave = true;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
Object.keys(config.accounts || {}).forEach(name => {
|
|
92
|
+
if (!config.accounts[name].id) {
|
|
93
|
+
config.accounts[name].id = config.nextAccountId;
|
|
94
|
+
config.nextAccountId++;
|
|
95
|
+
needsSave = true;
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
if (needsSave) {
|
|
100
|
+
this.save(config);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Get account by ID or name
|
|
106
|
+
*/
|
|
107
|
+
getAccountByIdOrName(idOrName) {
|
|
108
|
+
const accounts = this.getAllAccounts();
|
|
109
|
+
|
|
110
|
+
const id = parseInt(idOrName, 10);
|
|
111
|
+
if (!isNaN(id)) {
|
|
112
|
+
for (const [name, account] of Object.entries(accounts)) {
|
|
113
|
+
if (account.id === id) {
|
|
114
|
+
return { name, ...account };
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const account = accounts[idOrName];
|
|
120
|
+
if (account) {
|
|
121
|
+
return { name: idOrName, ...account };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Add or update an account
|
|
129
|
+
*/
|
|
130
|
+
addAccount(name, accountData) {
|
|
131
|
+
const config = this.read();
|
|
132
|
+
|
|
133
|
+
const isNewAccount = !config.accounts[name];
|
|
134
|
+
const accountId = isNewAccount ? config.nextAccountId : config.accounts[name].id;
|
|
135
|
+
|
|
136
|
+
config.accounts[name] = {
|
|
137
|
+
...accountData,
|
|
138
|
+
id: accountId,
|
|
139
|
+
createdAt: config.accounts[name]?.createdAt || new Date().toISOString(),
|
|
140
|
+
updatedAt: new Date().toISOString()
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
if (isNewAccount) {
|
|
144
|
+
config.nextAccountId++;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
this.save(config);
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Get all accounts
|
|
153
|
+
*/
|
|
154
|
+
getAllAccounts() {
|
|
155
|
+
const config = this.read();
|
|
156
|
+
return config.accounts || {};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Get a specific account
|
|
161
|
+
*/
|
|
162
|
+
getAccount(name) {
|
|
163
|
+
const accounts = this.getAllAccounts();
|
|
164
|
+
return accounts[name] || null;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Remove an account
|
|
169
|
+
*/
|
|
170
|
+
removeAccount(name) {
|
|
171
|
+
const config = this.read();
|
|
172
|
+
if (config.accounts[name]) {
|
|
173
|
+
delete config.accounts[name];
|
|
174
|
+
this.save(config);
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Check if an account exists
|
|
182
|
+
*/
|
|
183
|
+
accountExists(name) {
|
|
184
|
+
const accounts = this.getAllAccounts();
|
|
185
|
+
return !!accounts[name];
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// MCP Server methods
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Add or update an MCP server
|
|
192
|
+
*/
|
|
193
|
+
addMcpServer(name, serverData) {
|
|
194
|
+
const config = this.read();
|
|
195
|
+
if (!config.mcpServers) config.mcpServers = {};
|
|
196
|
+
|
|
197
|
+
const { DEFAULT_MCP_SCOPE } = require('../constants');
|
|
198
|
+
if (!serverData.scope) {
|
|
199
|
+
serverData.scope = DEFAULT_MCP_SCOPE;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
config.mcpServers[name] = {
|
|
203
|
+
...serverData,
|
|
204
|
+
createdAt: config.mcpServers[name]?.createdAt || new Date().toISOString(),
|
|
205
|
+
updatedAt: new Date().toISOString()
|
|
206
|
+
};
|
|
207
|
+
this.save(config);
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Get all MCP servers
|
|
213
|
+
*/
|
|
214
|
+
getAllMcpServers() {
|
|
215
|
+
const config = this.read();
|
|
216
|
+
return config.mcpServers || {};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Get a specific MCP server
|
|
221
|
+
*/
|
|
222
|
+
getMcpServer(name) {
|
|
223
|
+
const servers = this.getAllMcpServers();
|
|
224
|
+
return servers[name] || null;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Update an MCP server
|
|
229
|
+
*/
|
|
230
|
+
updateMcpServer(name, serverData) {
|
|
231
|
+
const config = this.read();
|
|
232
|
+
if (!config.mcpServers || !config.mcpServers[name]) return false;
|
|
233
|
+
config.mcpServers[name] = {
|
|
234
|
+
...serverData,
|
|
235
|
+
createdAt: config.mcpServers[name].createdAt,
|
|
236
|
+
updatedAt: new Date().toISOString()
|
|
237
|
+
};
|
|
238
|
+
this.save(config);
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Remove an MCP server
|
|
244
|
+
*/
|
|
245
|
+
removeMcpServer(name) {
|
|
246
|
+
const config = this.read();
|
|
247
|
+
if (config.mcpServers && config.mcpServers[name]) {
|
|
248
|
+
delete config.mcpServers[name];
|
|
249
|
+
this.save(config);
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Get configuration file paths
|
|
257
|
+
*/
|
|
258
|
+
getConfigPaths() {
|
|
259
|
+
return {
|
|
260
|
+
global: this.globalConfigFile,
|
|
261
|
+
globalDir: this.globalConfigDir
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
module.exports = GlobalConfigManager;
|