@phidiassj/aiyoperps-mcp-installer 0.6.8 → 0.7.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/bin/aiyoperps-mcp-installer.js +152 -58
- package/package.json +1 -1
|
@@ -147,13 +147,11 @@ async function detectClaudeCode(url) {
|
|
|
147
147
|
|
|
148
148
|
async function detectClaudeDesktop(url) {
|
|
149
149
|
const candidates = getClaudeDesktopCandidates();
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const
|
|
154
|
-
const
|
|
155
|
-
const baseConfigRoot = path.dirname(path.dirname(configPath));
|
|
156
|
-
const baseRootExists = fs.existsSync(baseConfigRoot);
|
|
150
|
+
const configPaths = selectClaudeDesktopConfigPaths(candidates);
|
|
151
|
+
const primaryPath = configPaths[0];
|
|
152
|
+
const exists = configPaths.some(fileExists);
|
|
153
|
+
const parentExists = configPaths.some(configPath => fs.existsSync(path.dirname(configPath)));
|
|
154
|
+
const baseRootExists = configPaths.some(configPath => fs.existsSync(path.dirname(path.dirname(configPath))));
|
|
157
155
|
const detected = exists || parentExists || baseRootExists;
|
|
158
156
|
let supported = baseRootExists;
|
|
159
157
|
let installed = false;
|
|
@@ -167,8 +165,12 @@ async function detectClaudeDesktop(url) {
|
|
|
167
165
|
|
|
168
166
|
if (exists) {
|
|
169
167
|
try {
|
|
170
|
-
|
|
171
|
-
|
|
168
|
+
installed = configPaths
|
|
169
|
+
.filter(fileExists)
|
|
170
|
+
.some(configPath => {
|
|
171
|
+
const parsed = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
172
|
+
return Boolean(parsed?.mcpServers?.[SERVER_NAME]);
|
|
173
|
+
});
|
|
172
174
|
reason = installed ? 'installed' : 'config parsed successfully';
|
|
173
175
|
} catch (error) {
|
|
174
176
|
supported = false;
|
|
@@ -184,27 +186,37 @@ async function detectClaudeDesktop(url) {
|
|
|
184
186
|
supported,
|
|
185
187
|
installed,
|
|
186
188
|
reason,
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
189
|
+
configPaths,
|
|
190
|
+
path: configPaths.join(' | '),
|
|
191
|
+
install: () => installClaudeDesktop(configPaths, url),
|
|
192
|
+
uninstall: () => uninstallClaudeDesktop(configPaths)
|
|
190
193
|
};
|
|
191
194
|
}
|
|
192
195
|
|
|
193
196
|
async function detectOpenClaw(url) {
|
|
194
|
-
const
|
|
195
|
-
const
|
|
196
|
-
const
|
|
197
|
+
const openclawCli = runCommand('openclaw', ['--version']);
|
|
198
|
+
const mcporterCli = runCommand('mcporter', ['--version']);
|
|
199
|
+
const configPath = resolveMcporterHomeConfigPath();
|
|
200
|
+
const detected = openclawCli.ok || fileExists(resolveOpenClawConfigPath());
|
|
201
|
+
const supported = openclawCli.ok && (mcporterCli.ok || Boolean(resolveExecutablePath(process.platform === 'win32' ? 'npx.cmd' : 'npx')));
|
|
197
202
|
|
|
198
203
|
let installed = false;
|
|
199
|
-
let reason =
|
|
200
|
-
? '
|
|
201
|
-
:
|
|
202
|
-
? 'config
|
|
203
|
-
:
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
204
|
+
let reason = !openclawCli.ok
|
|
205
|
+
? 'openclaw not detected'
|
|
206
|
+
: mcporterCli.ok
|
|
207
|
+
? 'mcporter config helpers available'
|
|
208
|
+
: supported
|
|
209
|
+
? 'mcporter will be used via npx'
|
|
210
|
+
: 'mcporter runtime is unavailable';
|
|
211
|
+
|
|
212
|
+
if (fileExists(configPath)) {
|
|
213
|
+
try {
|
|
214
|
+
const payload = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
215
|
+
installed = Boolean(payload?.mcpServers?.[SERVER_NAME]);
|
|
216
|
+
} catch {
|
|
217
|
+
installed = false;
|
|
218
|
+
}
|
|
219
|
+
|
|
208
220
|
if (installed) {
|
|
209
221
|
reason = 'installed';
|
|
210
222
|
}
|
|
@@ -215,10 +227,10 @@ async function detectOpenClaw(url) {
|
|
|
215
227
|
name: 'OpenClaw',
|
|
216
228
|
kind: 'cli',
|
|
217
229
|
detected,
|
|
218
|
-
supported
|
|
230
|
+
supported,
|
|
219
231
|
installed,
|
|
220
232
|
reason,
|
|
221
|
-
path:
|
|
233
|
+
path: '~/.mcporter/mcporter.json (mcporter home config)',
|
|
222
234
|
install: () => installOpenClaw(url),
|
|
223
235
|
uninstall: () => uninstallOpenClaw()
|
|
224
236
|
};
|
|
@@ -412,7 +424,7 @@ function createInstallAction(host, url) {
|
|
|
412
424
|
case 'claude-code':
|
|
413
425
|
return () => installClaudeCode(url);
|
|
414
426
|
case 'claude-desktop':
|
|
415
|
-
return () => installClaudeDesktop(host.
|
|
427
|
+
return () => installClaudeDesktop(host.configPaths, url);
|
|
416
428
|
case 'openclaw':
|
|
417
429
|
return () => installOpenClaw(url);
|
|
418
430
|
default:
|
|
@@ -463,37 +475,46 @@ function uninstallCodex(configPath) {
|
|
|
463
475
|
fs.writeFileSync(configPath, next.trim() ? `${next.replace(/\s*$/, '')}\n` : '', 'utf8');
|
|
464
476
|
}
|
|
465
477
|
|
|
466
|
-
function installClaudeDesktop(
|
|
467
|
-
|
|
478
|
+
function installClaudeDesktop(configPaths, url) {
|
|
479
|
+
const targets = configPaths.filter(fileExists);
|
|
480
|
+
if (targets.length === 0) {
|
|
481
|
+
targets.push(configPaths[0]);
|
|
482
|
+
}
|
|
468
483
|
|
|
469
|
-
const
|
|
470
|
-
|
|
471
|
-
: {};
|
|
484
|
+
for (const configPath of targets) {
|
|
485
|
+
ensureParentDir(configPath);
|
|
472
486
|
|
|
473
|
-
|
|
474
|
-
|
|
487
|
+
const payload = fileExists(configPath)
|
|
488
|
+
? JSON.parse(fs.readFileSync(configPath, 'utf8'))
|
|
489
|
+
: {};
|
|
475
490
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
}
|
|
491
|
+
payload.mcpServers ??= {};
|
|
492
|
+
payload.mcpServers[SERVER_NAME] = buildJsonServerConfig(url);
|
|
479
493
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
return;
|
|
494
|
+
backupIfExists(configPath);
|
|
495
|
+
fs.writeFileSync(configPath, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
|
|
483
496
|
}
|
|
497
|
+
}
|
|
484
498
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
499
|
+
function uninstallClaudeDesktop(configPaths) {
|
|
500
|
+
for (const configPath of configPaths) {
|
|
501
|
+
if (!fileExists(configPath)) {
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
489
504
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
505
|
+
const payload = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
506
|
+
if (!payload?.mcpServers?.[SERVER_NAME]) {
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
494
509
|
|
|
495
|
-
|
|
496
|
-
|
|
510
|
+
delete payload.mcpServers[SERVER_NAME];
|
|
511
|
+
if (Object.keys(payload.mcpServers).length === 0) {
|
|
512
|
+
delete payload.mcpServers;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
backupIfExists(configPath);
|
|
516
|
+
fs.writeFileSync(configPath, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
|
|
517
|
+
}
|
|
497
518
|
}
|
|
498
519
|
|
|
499
520
|
function installClaudeCode(url) {
|
|
@@ -529,17 +550,37 @@ function uninstallClaudeCode() {
|
|
|
529
550
|
}
|
|
530
551
|
|
|
531
552
|
function installOpenClaw(url) {
|
|
532
|
-
const
|
|
533
|
-
|
|
553
|
+
const result = runMcporterCommand([
|
|
554
|
+
'config',
|
|
555
|
+
'add',
|
|
556
|
+
SERVER_NAME,
|
|
557
|
+
url,
|
|
558
|
+
'--scope',
|
|
559
|
+
'home'
|
|
560
|
+
]);
|
|
534
561
|
if (!result.ok) {
|
|
535
|
-
throw new Error(result.stderr || '
|
|
562
|
+
throw new Error(result.stderr || 'mcporter config add failed');
|
|
536
563
|
}
|
|
537
564
|
}
|
|
538
565
|
|
|
539
566
|
function uninstallOpenClaw() {
|
|
540
|
-
|
|
567
|
+
if (!fileExists(resolveMcporterHomeConfigPath())) {
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
const result = runMcporterCommand([
|
|
572
|
+
'--config',
|
|
573
|
+
resolveMcporterHomeConfigPath(),
|
|
574
|
+
'config',
|
|
575
|
+
'remove',
|
|
576
|
+
SERVER_NAME
|
|
577
|
+
]);
|
|
578
|
+
if (result.stderr && /does not exist/i.test(result.stderr)) {
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
|
|
541
582
|
if (!result.ok) {
|
|
542
|
-
throw new Error(result.stderr || '
|
|
583
|
+
throw new Error(result.stderr || 'mcporter config remove failed');
|
|
543
584
|
}
|
|
544
585
|
}
|
|
545
586
|
|
|
@@ -1004,7 +1045,8 @@ function getClaudeDesktopCandidates() {
|
|
|
1004
1045
|
if (process.platform === 'win32') {
|
|
1005
1046
|
const appData = env.APPDATA || path.join(env.USERPROFILE || os.homedir(), 'AppData', 'Roaming');
|
|
1006
1047
|
const localAppData = env.LOCALAPPDATA || path.join(env.USERPROFILE || os.homedir(), 'AppData', 'Local');
|
|
1007
|
-
const
|
|
1048
|
+
const storeCandidates = [];
|
|
1049
|
+
const roamingCandidates = [
|
|
1008
1050
|
path.join(appData, 'Claude', 'claude_desktop_config.json'),
|
|
1009
1051
|
path.join(appData, 'Claude', 'config.json')
|
|
1010
1052
|
];
|
|
@@ -1018,7 +1060,7 @@ function getClaudeDesktopCandidates() {
|
|
|
1018
1060
|
.filter(name => name.toLowerCase().startsWith('claude_'));
|
|
1019
1061
|
|
|
1020
1062
|
for (const packageDir of packageDirs) {
|
|
1021
|
-
|
|
1063
|
+
storeCandidates.push(
|
|
1022
1064
|
path.join(packagesRoot, packageDir, 'LocalCache', 'Roaming', 'Claude', 'claude_desktop_config.json'),
|
|
1023
1065
|
path.join(packagesRoot, packageDir, 'LocalCache', 'Roaming', 'Claude', 'config.json'));
|
|
1024
1066
|
}
|
|
@@ -1027,7 +1069,7 @@ function getClaudeDesktopCandidates() {
|
|
|
1027
1069
|
}
|
|
1028
1070
|
}
|
|
1029
1071
|
|
|
1030
|
-
return [...new Set(
|
|
1072
|
+
return [...new Set([...storeCandidates, ...roamingCandidates])];
|
|
1031
1073
|
}
|
|
1032
1074
|
|
|
1033
1075
|
if (process.platform === 'darwin') {
|
|
@@ -1043,6 +1085,34 @@ function getClaudeDesktopCandidates() {
|
|
|
1043
1085
|
];
|
|
1044
1086
|
}
|
|
1045
1087
|
|
|
1088
|
+
function selectClaudeDesktopConfigPaths(candidates) {
|
|
1089
|
+
const existingPrimary = candidates.filter(candidate =>
|
|
1090
|
+
fileExists(candidate) &&
|
|
1091
|
+
path.basename(candidate).toLowerCase() === 'claude_desktop_config.json');
|
|
1092
|
+
if (existingPrimary.length > 0) {
|
|
1093
|
+
return existingPrimary;
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
const existingAny = candidates.filter(fileExists);
|
|
1097
|
+
if (existingAny.length > 0) {
|
|
1098
|
+
return existingAny;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
const creatablePrimary = candidates.find(candidate =>
|
|
1102
|
+
path.basename(candidate).toLowerCase() === 'claude_desktop_config.json' &&
|
|
1103
|
+
fs.existsSync(path.dirname(candidate)));
|
|
1104
|
+
if (creatablePrimary) {
|
|
1105
|
+
return [creatablePrimary];
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
const creatableAny = candidates.find(candidate => fs.existsSync(path.dirname(candidate)));
|
|
1109
|
+
if (creatableAny) {
|
|
1110
|
+
return [creatableAny];
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
return [candidates[0]];
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1046
1116
|
function resolveOpenClawConfigPath() {
|
|
1047
1117
|
const explicit = env.OPENCLAW_CONFIG_PATH;
|
|
1048
1118
|
if (explicit) {
|
|
@@ -1053,6 +1123,30 @@ function resolveOpenClawConfigPath() {
|
|
|
1053
1123
|
return path.join(stateDir, 'openclaw.json');
|
|
1054
1124
|
}
|
|
1055
1125
|
|
|
1126
|
+
function resolveMcporterHomeConfigPath() {
|
|
1127
|
+
return path.join(os.homedir(), '.mcporter', 'mcporter.json');
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
function runMcporterCommand(args) {
|
|
1131
|
+
const mcporter = resolveExecutablePath(process.platform === 'win32' ? 'mcporter.cmd' : 'mcporter');
|
|
1132
|
+
if (mcporter) {
|
|
1133
|
+
return runCommand(mcporter, args);
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
const npx = resolveExecutablePath(process.platform === 'win32' ? 'npx.cmd' : 'npx');
|
|
1137
|
+
if (!npx) {
|
|
1138
|
+
return {
|
|
1139
|
+
ok: false,
|
|
1140
|
+
status: null,
|
|
1141
|
+
stdout: '',
|
|
1142
|
+
stderr: 'mcporter and npx were not found in PATH',
|
|
1143
|
+
error: null
|
|
1144
|
+
};
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
return runCommand(npx, ['-y', 'mcporter', ...args]);
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1056
1150
|
function runCommand(command, args) {
|
|
1057
1151
|
const result = spawnSync(command, args, {
|
|
1058
1152
|
encoding: 'utf8',
|