@mcp-s/cli 0.0.9 → 0.0.11
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 +37 -14
- package/SKILL.md +42 -34
- package/dist/SKILL.md +42 -34
- package/dist/daemon.js +52 -52
- package/dist/index.js +531 -182
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { appendFileSync, mkdirSync as
|
|
5
|
-
import { homedir as
|
|
6
|
-
import { join as
|
|
4
|
+
import { appendFileSync, mkdirSync as mkdirSync6 } from "fs";
|
|
5
|
+
import { homedir as homedir7 } from "os";
|
|
6
|
+
import { join as join8 } from "path";
|
|
7
7
|
|
|
8
8
|
// src/client.ts
|
|
9
9
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
@@ -60,7 +60,7 @@ async function saveAuthData() {
|
|
|
60
60
|
mode: 384
|
|
61
61
|
});
|
|
62
62
|
} catch (err) {
|
|
63
|
-
if (process.env.
|
|
63
|
+
if (process.env.MCP_S_CLI_DEBUG) {
|
|
64
64
|
console.error(
|
|
65
65
|
`[mcp-s-cli] Failed to save auth data: ${err.message}`
|
|
66
66
|
);
|
|
@@ -190,7 +190,7 @@ async function exchangeAuthorizationCode(tokenEndpoint, clientId, code, codeVeri
|
|
|
190
190
|
}
|
|
191
191
|
async function startCallbackServer(port) {
|
|
192
192
|
const http = await import("http");
|
|
193
|
-
return new Promise((
|
|
193
|
+
return new Promise((resolve5, reject) => {
|
|
194
194
|
const server = http.createServer((req, res) => {
|
|
195
195
|
const url = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
196
196
|
const code = url.searchParams.get("code");
|
|
@@ -221,7 +221,7 @@ async function startCallbackServer(port) {
|
|
|
221
221
|
</html>
|
|
222
222
|
`);
|
|
223
223
|
server.close();
|
|
224
|
-
|
|
224
|
+
resolve5(code);
|
|
225
225
|
return;
|
|
226
226
|
}
|
|
227
227
|
res.writeHead(400, { "Content-Type": "text/html" });
|
|
@@ -583,51 +583,35 @@ var DEFAULT_MAX_RETRIES = 3;
|
|
|
583
583
|
var DEFAULT_RETRY_DELAY_MS = 1e3;
|
|
584
584
|
var DEFAULT_DAEMON_TIMEOUT_SECONDS = 300;
|
|
585
585
|
function debug(message) {
|
|
586
|
-
if (process.env.
|
|
586
|
+
if (process.env.MCP_S_CLI_DEBUG) {
|
|
587
587
|
console.error(`[mcp-s-cli] ${message}`);
|
|
588
588
|
}
|
|
589
589
|
}
|
|
590
|
-
function getTimeoutMs() {
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
const seconds = Number.parseInt(envTimeout, 10);
|
|
594
|
-
if (!Number.isNaN(seconds) && seconds > 0) {
|
|
595
|
-
return seconds * 1e3;
|
|
596
|
-
}
|
|
590
|
+
function getTimeoutMs(settings) {
|
|
591
|
+
if (settings?.timeout != null && settings.timeout > 0) {
|
|
592
|
+
return settings.timeout * 1e3;
|
|
597
593
|
}
|
|
598
594
|
return DEFAULT_TIMEOUT_MS;
|
|
599
595
|
}
|
|
600
|
-
function getMaxRetries() {
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
const retries = Number.parseInt(envRetries, 10);
|
|
604
|
-
if (!Number.isNaN(retries) && retries >= 0) {
|
|
605
|
-
return retries;
|
|
606
|
-
}
|
|
596
|
+
function getMaxRetries(settings) {
|
|
597
|
+
if (settings?.maxRetries != null && settings.maxRetries >= 0) {
|
|
598
|
+
return settings.maxRetries;
|
|
607
599
|
}
|
|
608
600
|
return DEFAULT_MAX_RETRIES;
|
|
609
601
|
}
|
|
610
|
-
function getRetryDelayMs() {
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
const delay = Number.parseInt(envDelay, 10);
|
|
614
|
-
if (!Number.isNaN(delay) && delay > 0) {
|
|
615
|
-
return delay;
|
|
616
|
-
}
|
|
602
|
+
function getRetryDelayMs(settings) {
|
|
603
|
+
if (settings?.retryDelay != null && settings.retryDelay > 0) {
|
|
604
|
+
return settings.retryDelay;
|
|
617
605
|
}
|
|
618
606
|
return DEFAULT_RETRY_DELAY_MS;
|
|
619
607
|
}
|
|
620
608
|
var DAEMON_SERVER_NAME = "mcp-s-cli";
|
|
621
|
-
function isDaemonEnabled() {
|
|
622
|
-
return
|
|
609
|
+
function isDaemonEnabled(settings) {
|
|
610
|
+
return settings?.daemon !== false;
|
|
623
611
|
}
|
|
624
|
-
function getDaemonTimeoutMs() {
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
const seconds = Number.parseInt(envTimeout, 10);
|
|
628
|
-
if (!Number.isNaN(seconds) && seconds > 0) {
|
|
629
|
-
return seconds * 1e3;
|
|
630
|
-
}
|
|
612
|
+
function getDaemonTimeoutMs(settings) {
|
|
613
|
+
if (settings?.daemonTimeout != null && settings.daemonTimeout > 0) {
|
|
614
|
+
return settings.daemonTimeout * 1e3;
|
|
631
615
|
}
|
|
632
616
|
return DEFAULT_DAEMON_TIMEOUT_SECONDS * 1e3;
|
|
633
617
|
}
|
|
@@ -650,7 +634,7 @@ function getConfigHash(config) {
|
|
|
650
634
|
return createHash("sha256").update(str).digest("hex").slice(0, 16);
|
|
651
635
|
}
|
|
652
636
|
function isStrictEnvMode() {
|
|
653
|
-
const value = process.env.
|
|
637
|
+
const value = process.env.MCP_S_CLI_STRICT_ENV?.toLowerCase();
|
|
654
638
|
return value !== "false" && value !== "0";
|
|
655
639
|
}
|
|
656
640
|
function substituteEnvVars(value) {
|
|
@@ -673,7 +657,7 @@ function substituteEnvVars(value) {
|
|
|
673
657
|
type: "MISSING_ENV_VAR",
|
|
674
658
|
message,
|
|
675
659
|
details: "Referenced in config but not set in environment",
|
|
676
|
-
suggestion: `Set the variable(s) before running: export ${missingVars[0]}="value" or set
|
|
660
|
+
suggestion: `Set the variable(s) before running: export ${missingVars[0]}="value" or set MCP_S_CLI_STRICT_ENV=false to use empty values`
|
|
677
661
|
})
|
|
678
662
|
);
|
|
679
663
|
}
|
|
@@ -748,8 +732,8 @@ async function loadConfig(explicitPath) {
|
|
|
748
732
|
let configPath;
|
|
749
733
|
if (explicitPath) {
|
|
750
734
|
configPath = resolve(explicitPath);
|
|
751
|
-
} else if (process.env.
|
|
752
|
-
configPath = resolve(process.env.
|
|
735
|
+
} else if (process.env.MCP_S_CLI_CONFIG_PATH) {
|
|
736
|
+
configPath = resolve(process.env.MCP_S_CLI_CONFIG_PATH);
|
|
753
737
|
}
|
|
754
738
|
if (configPath) {
|
|
755
739
|
if (!existsSync(configPath)) {
|
|
@@ -780,6 +764,7 @@ async function loadConfig(explicitPath) {
|
|
|
780
764
|
throw new Error(formatCliError(configMissingFieldError(configPath)));
|
|
781
765
|
}
|
|
782
766
|
const knownFields = [
|
|
767
|
+
"enabled",
|
|
783
768
|
"org",
|
|
784
769
|
"baseUrl",
|
|
785
770
|
"mcp",
|
|
@@ -787,7 +772,8 @@ async function loadConfig(explicitPath) {
|
|
|
787
772
|
"userAccessKey",
|
|
788
773
|
"token",
|
|
789
774
|
"allowedTools",
|
|
790
|
-
"disabledTools"
|
|
775
|
+
"disabledTools",
|
|
776
|
+
"settings"
|
|
791
777
|
];
|
|
792
778
|
const hasKnownField = knownFields.some((f) => f in raw);
|
|
793
779
|
if (!hasKnownField) {
|
|
@@ -795,7 +781,7 @@ async function loadConfig(explicitPath) {
|
|
|
795
781
|
}
|
|
796
782
|
raw = substituteEnvVarsInObject(raw);
|
|
797
783
|
const serverConfig = deriveServerConfig(raw);
|
|
798
|
-
return { raw, serverConfig };
|
|
784
|
+
return { raw, serverConfig, settings: raw.settings ?? {} };
|
|
799
785
|
}
|
|
800
786
|
|
|
801
787
|
// src/daemon-client.ts
|
|
@@ -883,10 +869,10 @@ function killProcess(pid) {
|
|
|
883
869
|
return false;
|
|
884
870
|
}
|
|
885
871
|
}
|
|
886
|
-
async function runDaemon(serverName, config) {
|
|
872
|
+
async function runDaemon(serverName, config, settings) {
|
|
887
873
|
const socketPath = getSocketPath();
|
|
888
874
|
const configHash = getConfigHash(config);
|
|
889
|
-
const timeoutMs = getDaemonTimeoutMs();
|
|
875
|
+
const timeoutMs = getDaemonTimeoutMs(settings);
|
|
890
876
|
let idleTimer = null;
|
|
891
877
|
let mcpClient = null;
|
|
892
878
|
let server = null;
|
|
@@ -1032,7 +1018,7 @@ async function runDaemon(serverName, config) {
|
|
|
1032
1018
|
};
|
|
1033
1019
|
}
|
|
1034
1020
|
};
|
|
1035
|
-
await new Promise((
|
|
1021
|
+
await new Promise((resolve5, reject) => {
|
|
1036
1022
|
server = createServer((socket) => {
|
|
1037
1023
|
activeConnections.add(socket);
|
|
1038
1024
|
debug(`[daemon:${serverName}] Client connected`);
|
|
@@ -1064,7 +1050,7 @@ async function runDaemon(serverName, config) {
|
|
|
1064
1050
|
writeFileSync(getReadyPath(), String(process.pid), {
|
|
1065
1051
|
mode: 384
|
|
1066
1052
|
});
|
|
1067
|
-
|
|
1053
|
+
resolve5();
|
|
1068
1054
|
});
|
|
1069
1055
|
}).catch(async (error) => {
|
|
1070
1056
|
console.error(
|
|
@@ -1078,8 +1064,11 @@ async function runDaemon(serverName, config) {
|
|
|
1078
1064
|
if (process.argv[2] === "--daemon") {
|
|
1079
1065
|
const serverName = process.argv[3];
|
|
1080
1066
|
const configJson = process.argv[4];
|
|
1067
|
+
const settingsJson = process.argv[5];
|
|
1081
1068
|
if (!serverName || !configJson) {
|
|
1082
|
-
console.error(
|
|
1069
|
+
console.error(
|
|
1070
|
+
"Usage: daemon.ts --daemon <serverName> <configJson> [settingsJson]"
|
|
1071
|
+
);
|
|
1083
1072
|
process.exit(1);
|
|
1084
1073
|
}
|
|
1085
1074
|
let config;
|
|
@@ -1089,7 +1078,16 @@ if (process.argv[2] === "--daemon") {
|
|
|
1089
1078
|
console.error("Invalid config JSON");
|
|
1090
1079
|
process.exit(1);
|
|
1091
1080
|
}
|
|
1092
|
-
|
|
1081
|
+
let settings;
|
|
1082
|
+
if (settingsJson) {
|
|
1083
|
+
try {
|
|
1084
|
+
settings = JSON.parse(settingsJson);
|
|
1085
|
+
} catch {
|
|
1086
|
+
console.error("Invalid settings JSON");
|
|
1087
|
+
process.exit(1);
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
runDaemon(serverName, config, settings).catch((error) => {
|
|
1093
1091
|
console.error("Daemon failed:", error);
|
|
1094
1092
|
process.exit(1);
|
|
1095
1093
|
});
|
|
@@ -1100,7 +1098,7 @@ function generateRequestId() {
|
|
|
1100
1098
|
return `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
1101
1099
|
}
|
|
1102
1100
|
async function sendRequest(socketPath, request) {
|
|
1103
|
-
return new Promise((
|
|
1101
|
+
return new Promise((resolve5, reject) => {
|
|
1104
1102
|
const socket = createConnection(socketPath);
|
|
1105
1103
|
let settled = false;
|
|
1106
1104
|
const settle = (fn) => {
|
|
@@ -1128,7 +1126,7 @@ async function sendRequest(socketPath, request) {
|
|
|
1128
1126
|
const response = JSON.parse(line);
|
|
1129
1127
|
clearTimeout(timer);
|
|
1130
1128
|
socket.end();
|
|
1131
|
-
settle(() =>
|
|
1129
|
+
settle(() => resolve5(response));
|
|
1132
1130
|
} catch {
|
|
1133
1131
|
clearTimeout(timer);
|
|
1134
1132
|
socket.end();
|
|
@@ -1175,17 +1173,18 @@ function isDaemonValid(serverName, config) {
|
|
|
1175
1173
|
}
|
|
1176
1174
|
return true;
|
|
1177
1175
|
}
|
|
1178
|
-
async function spawnDaemon(serverName, config) {
|
|
1176
|
+
async function spawnDaemon(serverName, config, settings) {
|
|
1179
1177
|
debug(`[daemon-client] Spawning daemon for ${serverName}`);
|
|
1180
1178
|
const __dirname = join2(fileURLToPath(import.meta.url), "..");
|
|
1181
1179
|
const daemonScript = join2(__dirname, "daemon.js");
|
|
1182
1180
|
const configJson = JSON.stringify(config);
|
|
1181
|
+
const settingsJson = JSON.stringify(settings ?? {});
|
|
1183
1182
|
const proc = spawn(
|
|
1184
1183
|
"node",
|
|
1185
|
-
[daemonScript, "--daemon", serverName, configJson],
|
|
1184
|
+
[daemonScript, "--daemon", serverName, configJson, settingsJson],
|
|
1186
1185
|
{
|
|
1187
1186
|
stdio: "ignore",
|
|
1188
|
-
env: { ...process.env,
|
|
1187
|
+
env: { ...process.env, MCP_S_CLI_NO_OAUTH: "1" },
|
|
1189
1188
|
detached: true
|
|
1190
1189
|
}
|
|
1191
1190
|
);
|
|
@@ -1208,10 +1207,10 @@ async function spawnDaemon(serverName, config) {
|
|
|
1208
1207
|
debug(`[daemon-client] Daemon spawn timeout for ${serverName}`);
|
|
1209
1208
|
return false;
|
|
1210
1209
|
}
|
|
1211
|
-
async function getDaemonConnection(serverName, config) {
|
|
1210
|
+
async function getDaemonConnection(serverName, config, settings) {
|
|
1212
1211
|
const socketPath = getSocketPath();
|
|
1213
1212
|
if (!isDaemonValid(serverName, config)) {
|
|
1214
|
-
const spawned = await spawnDaemon(serverName, config);
|
|
1213
|
+
const spawned = await spawnDaemon(serverName, config, settings);
|
|
1215
1214
|
if (!spawned) {
|
|
1216
1215
|
debug(`[daemon-client] Failed to spawn daemon for ${serverName}`);
|
|
1217
1216
|
return null;
|
|
@@ -1299,13 +1298,13 @@ async function cleanupOrphanedDaemons() {
|
|
|
1299
1298
|
}
|
|
1300
1299
|
|
|
1301
1300
|
// src/version.ts
|
|
1302
|
-
var VERSION = "0.0.
|
|
1301
|
+
var VERSION = "0.0.11";
|
|
1303
1302
|
|
|
1304
1303
|
// src/client.ts
|
|
1305
|
-
function getRetryConfig() {
|
|
1306
|
-
const totalBudgetMs = getTimeoutMs();
|
|
1307
|
-
const maxRetries = getMaxRetries();
|
|
1308
|
-
const baseDelayMs = getRetryDelayMs();
|
|
1304
|
+
function getRetryConfig(settings) {
|
|
1305
|
+
const totalBudgetMs = getTimeoutMs(settings);
|
|
1306
|
+
const maxRetries = getMaxRetries(settings);
|
|
1307
|
+
const baseDelayMs = getRetryDelayMs(settings);
|
|
1309
1308
|
const retryBudgetMs = Math.max(0, totalBudgetMs - 5e3);
|
|
1310
1309
|
return {
|
|
1311
1310
|
maxRetries,
|
|
@@ -1351,7 +1350,7 @@ function calculateDelay(attempt, config) {
|
|
|
1351
1350
|
return Math.round(cappedDelay + jitter);
|
|
1352
1351
|
}
|
|
1353
1352
|
function sleep(ms) {
|
|
1354
|
-
return new Promise((
|
|
1353
|
+
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
1355
1354
|
}
|
|
1356
1355
|
async function withRetry(fn, operationName, config = getRetryConfig()) {
|
|
1357
1356
|
let lastError;
|
|
@@ -1443,7 +1442,7 @@ ${stderrOutput}`;
|
|
|
1443
1442
|
}, `connect to ${serverName}`);
|
|
1444
1443
|
}
|
|
1445
1444
|
async function connectToHttpServer(serverName, config) {
|
|
1446
|
-
const oauthEnabled = process.env.
|
|
1445
|
+
const oauthEnabled = process.env.MCP_S_CLI_NO_OAUTH !== "1";
|
|
1447
1446
|
return withRetry(async () => {
|
|
1448
1447
|
const configuredAuth = config.headers?.Authorization || config.headers?.authorization;
|
|
1449
1448
|
let headers = { ...config.headers };
|
|
@@ -1593,24 +1592,32 @@ async function listTools(client) {
|
|
|
1593
1592
|
}));
|
|
1594
1593
|
}, "list tools");
|
|
1595
1594
|
}
|
|
1596
|
-
async function callTool(client, toolName, args) {
|
|
1597
|
-
return withRetry(
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1595
|
+
async function callTool(client, toolName, args, settings) {
|
|
1596
|
+
return withRetry(
|
|
1597
|
+
async () => {
|
|
1598
|
+
const result = await client.callTool(
|
|
1599
|
+
{
|
|
1600
|
+
name: toolName,
|
|
1601
|
+
arguments: args
|
|
1602
|
+
},
|
|
1603
|
+
void 0,
|
|
1604
|
+
{ timeout: getTimeoutMs(settings) }
|
|
1605
|
+
);
|
|
1606
|
+
return result;
|
|
1607
|
+
},
|
|
1608
|
+
`call tool ${toolName}`,
|
|
1609
|
+
getRetryConfig(settings)
|
|
1610
|
+
);
|
|
1608
1611
|
}
|
|
1609
|
-
async function getConnection(serverName, config) {
|
|
1612
|
+
async function getConnection(serverName, config, settings) {
|
|
1610
1613
|
await cleanupOrphanedDaemons();
|
|
1611
|
-
if (isDaemonEnabled()) {
|
|
1614
|
+
if (isDaemonEnabled(settings)) {
|
|
1612
1615
|
try {
|
|
1613
|
-
const daemonConn = await getDaemonConnection(
|
|
1616
|
+
const daemonConn = await getDaemonConnection(
|
|
1617
|
+
serverName,
|
|
1618
|
+
config,
|
|
1619
|
+
settings
|
|
1620
|
+
);
|
|
1614
1621
|
if (daemonConn) {
|
|
1615
1622
|
debug(`Using daemon connection for ${serverName}`);
|
|
1616
1623
|
return {
|
|
@@ -1653,7 +1660,7 @@ async function getConnection(serverName, config) {
|
|
|
1653
1660
|
if (!isToolAllowed(toolName, config)) {
|
|
1654
1661
|
throw new Error(`Tool "${toolName}" is disabled by configuration`);
|
|
1655
1662
|
}
|
|
1656
|
-
return callTool(client, toolName, args);
|
|
1663
|
+
return callTool(client, toolName, args, settings);
|
|
1657
1664
|
},
|
|
1658
1665
|
async getInstructions() {
|
|
1659
1666
|
return client.getInstructions();
|
|
@@ -1794,12 +1801,12 @@ function formatToolResult(result) {
|
|
|
1794
1801
|
}
|
|
1795
1802
|
|
|
1796
1803
|
// src/commands/call.ts
|
|
1797
|
-
async function parseArgs(argsString) {
|
|
1804
|
+
async function parseArgs(argsString, settings) {
|
|
1798
1805
|
let jsonString;
|
|
1799
1806
|
if (argsString) {
|
|
1800
1807
|
jsonString = argsString;
|
|
1801
1808
|
} else if (!process.stdin.isTTY) {
|
|
1802
|
-
const timeoutMs = getTimeoutMs();
|
|
1809
|
+
const timeoutMs = getTimeoutMs(settings);
|
|
1803
1810
|
const chunks = [];
|
|
1804
1811
|
let timeoutId;
|
|
1805
1812
|
const readPromise = (async () => {
|
|
@@ -1841,11 +1848,11 @@ async function callCommand(options) {
|
|
|
1841
1848
|
console.error(error.message);
|
|
1842
1849
|
process.exit(1 /* CLIENT_ERROR */);
|
|
1843
1850
|
}
|
|
1844
|
-
const { serverConfig } = loaded;
|
|
1851
|
+
const { serverConfig, settings } = loaded;
|
|
1845
1852
|
const serverLabel = "server";
|
|
1846
1853
|
if (options.args !== void 0) {
|
|
1847
1854
|
try {
|
|
1848
|
-
await parseArgs(options.args);
|
|
1855
|
+
await parseArgs(options.args, settings);
|
|
1849
1856
|
} catch (error) {
|
|
1850
1857
|
console.error(error.message);
|
|
1851
1858
|
process.exit(1 /* CLIENT_ERROR */);
|
|
@@ -1853,14 +1860,14 @@ async function callCommand(options) {
|
|
|
1853
1860
|
}
|
|
1854
1861
|
let args;
|
|
1855
1862
|
try {
|
|
1856
|
-
args = await parseArgs(options.args);
|
|
1863
|
+
args = await parseArgs(options.args, settings);
|
|
1857
1864
|
} catch (error) {
|
|
1858
1865
|
console.error(error.message);
|
|
1859
1866
|
process.exit(1 /* CLIENT_ERROR */);
|
|
1860
1867
|
}
|
|
1861
1868
|
let connection;
|
|
1862
1869
|
try {
|
|
1863
|
-
connection = await getConnection(serverLabel, serverConfig);
|
|
1870
|
+
connection = await getConnection(serverLabel, serverConfig, settings);
|
|
1864
1871
|
} catch (error) {
|
|
1865
1872
|
console.error(
|
|
1866
1873
|
formatCliError(
|
|
@@ -1934,6 +1941,247 @@ function clearHistoryCommand() {
|
|
|
1934
1941
|
console.log(`Cleared history from ${HISTORY_PATH}`);
|
|
1935
1942
|
}
|
|
1936
1943
|
|
|
1944
|
+
// src/commands/config.ts
|
|
1945
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
1946
|
+
import { homedir as homedir3 } from "os";
|
|
1947
|
+
import { dirname as dirname3, join as join4, resolve as resolve2 } from "path";
|
|
1948
|
+
var TOP_LEVEL_KEYS = [
|
|
1949
|
+
"enabled",
|
|
1950
|
+
"org",
|
|
1951
|
+
"baseUrl",
|
|
1952
|
+
"mcp",
|
|
1953
|
+
"toolkit",
|
|
1954
|
+
"userAccessKey",
|
|
1955
|
+
"token",
|
|
1956
|
+
"allowedTools",
|
|
1957
|
+
"disabledTools",
|
|
1958
|
+
"settings"
|
|
1959
|
+
];
|
|
1960
|
+
var SETTINGS_KEYS = [
|
|
1961
|
+
"settings.timeout",
|
|
1962
|
+
"settings.maxRetries",
|
|
1963
|
+
"settings.retryDelay",
|
|
1964
|
+
"settings.daemon",
|
|
1965
|
+
"settings.daemonTimeout",
|
|
1966
|
+
"settings.history"
|
|
1967
|
+
];
|
|
1968
|
+
var ALL_KNOWN_KEYS = [...TOP_LEVEL_KEYS, ...SETTINGS_KEYS];
|
|
1969
|
+
function getDefaultConfigPath() {
|
|
1970
|
+
return join4(homedir3(), ".config", "mcp-s-cli", "config.json");
|
|
1971
|
+
}
|
|
1972
|
+
function resolveConfigPath(explicitPath) {
|
|
1973
|
+
if (explicitPath) return resolve2(explicitPath);
|
|
1974
|
+
if (process.env.MCP_S_CLI_CONFIG_PATH)
|
|
1975
|
+
return resolve2(process.env.MCP_S_CLI_CONFIG_PATH);
|
|
1976
|
+
return getDefaultConfigPath();
|
|
1977
|
+
}
|
|
1978
|
+
function readConfigFile(configPath) {
|
|
1979
|
+
if (!existsSync5(configPath)) return {};
|
|
1980
|
+
const content = readFileSync3(configPath, "utf-8").trim();
|
|
1981
|
+
if (!content) return {};
|
|
1982
|
+
try {
|
|
1983
|
+
const parsed = JSON.parse(content);
|
|
1984
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
1985
|
+
return parsed;
|
|
1986
|
+
}
|
|
1987
|
+
return {};
|
|
1988
|
+
} catch {
|
|
1989
|
+
console.error(
|
|
1990
|
+
formatCliError({
|
|
1991
|
+
code: 1 /* CLIENT_ERROR */,
|
|
1992
|
+
type: "CONFIG_INVALID_JSON",
|
|
1993
|
+
message: `Cannot parse config file: ${configPath}`,
|
|
1994
|
+
suggestion: "Fix or delete the file, then run mcp-s-cli init"
|
|
1995
|
+
})
|
|
1996
|
+
);
|
|
1997
|
+
process.exit(1 /* CLIENT_ERROR */);
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
function writeConfigFile(configPath, config) {
|
|
2001
|
+
mkdirSync3(dirname3(configPath), { recursive: true });
|
|
2002
|
+
writeFileSync3(configPath, `${JSON.stringify(config, null, 2)}
|
|
2003
|
+
`, "utf-8");
|
|
2004
|
+
}
|
|
2005
|
+
function parseValue(raw) {
|
|
2006
|
+
if (raw === "true") return true;
|
|
2007
|
+
if (raw === "false") return false;
|
|
2008
|
+
const n = Number(raw);
|
|
2009
|
+
if (!Number.isNaN(n) && raw.trim() !== "") return n;
|
|
2010
|
+
return raw;
|
|
2011
|
+
}
|
|
2012
|
+
function setNestedKey(obj, parts, value) {
|
|
2013
|
+
let current = obj;
|
|
2014
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
2015
|
+
const part = parts[i];
|
|
2016
|
+
if (current[part] === void 0 || current[part] === null || typeof current[part] !== "object" || Array.isArray(current[part])) {
|
|
2017
|
+
current[part] = {};
|
|
2018
|
+
}
|
|
2019
|
+
current = current[part];
|
|
2020
|
+
}
|
|
2021
|
+
current[parts[parts.length - 1]] = value;
|
|
2022
|
+
}
|
|
2023
|
+
function getNestedKey(obj, parts) {
|
|
2024
|
+
let current = obj;
|
|
2025
|
+
for (const part of parts) {
|
|
2026
|
+
if (current === null || typeof current !== "object") return void 0;
|
|
2027
|
+
current = current[part];
|
|
2028
|
+
}
|
|
2029
|
+
return current;
|
|
2030
|
+
}
|
|
2031
|
+
function validateKey(key) {
|
|
2032
|
+
const known = ALL_KNOWN_KEYS;
|
|
2033
|
+
if (!known.includes(key)) {
|
|
2034
|
+
console.error(
|
|
2035
|
+
formatCliError({
|
|
2036
|
+
code: 1 /* CLIENT_ERROR */,
|
|
2037
|
+
type: "UNKNOWN_CONFIG_KEY",
|
|
2038
|
+
message: `Unknown config key: "${key}"`,
|
|
2039
|
+
details: `Known keys: ${ALL_KNOWN_KEYS.join(", ")}`,
|
|
2040
|
+
suggestion: "Use dot-notation for nested keys, e.g. settings.timeout, settings.daemon"
|
|
2041
|
+
})
|
|
2042
|
+
);
|
|
2043
|
+
process.exit(1 /* CLIENT_ERROR */);
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
2046
|
+
function configSetCommand(opts) {
|
|
2047
|
+
const { key, value, configPath: explicitPath } = opts;
|
|
2048
|
+
validateKey(key);
|
|
2049
|
+
const configPath = resolveConfigPath(explicitPath);
|
|
2050
|
+
const config = readConfigFile(configPath);
|
|
2051
|
+
const parts = key.split(".");
|
|
2052
|
+
const parsed = parseValue(value);
|
|
2053
|
+
setNestedKey(config, parts, parsed);
|
|
2054
|
+
writeConfigFile(configPath, config);
|
|
2055
|
+
console.log(`Set ${key} = ${JSON.stringify(parsed)} in ${configPath}`);
|
|
2056
|
+
}
|
|
2057
|
+
function configGetCommand(opts) {
|
|
2058
|
+
const { key, configPath: explicitPath } = opts;
|
|
2059
|
+
validateKey(key);
|
|
2060
|
+
const configPath = resolveConfigPath(explicitPath);
|
|
2061
|
+
if (!existsSync5(configPath)) {
|
|
2062
|
+
console.error(
|
|
2063
|
+
formatCliError({
|
|
2064
|
+
code: 1 /* CLIENT_ERROR */,
|
|
2065
|
+
type: "CONFIG_NOT_FOUND",
|
|
2066
|
+
message: `Config file not found: ${configPath}`,
|
|
2067
|
+
suggestion: "Run mcp-s-cli init or mcp-s-cli config set <key> <value>"
|
|
2068
|
+
})
|
|
2069
|
+
);
|
|
2070
|
+
process.exit(1 /* CLIENT_ERROR */);
|
|
2071
|
+
}
|
|
2072
|
+
const config = readConfigFile(configPath);
|
|
2073
|
+
const parts = key.split(".");
|
|
2074
|
+
const value = getNestedKey(config, parts);
|
|
2075
|
+
if (value === void 0) {
|
|
2076
|
+
console.error(
|
|
2077
|
+
formatCliError({
|
|
2078
|
+
code: 1 /* CLIENT_ERROR */,
|
|
2079
|
+
type: "CONFIG_KEY_NOT_SET",
|
|
2080
|
+
message: `Key "${key}" is not set in ${configPath}`,
|
|
2081
|
+
suggestion: `Set it with: mcp-s-cli config set ${key} <value>`
|
|
2082
|
+
})
|
|
2083
|
+
);
|
|
2084
|
+
process.exit(1 /* CLIENT_ERROR */);
|
|
2085
|
+
}
|
|
2086
|
+
console.log(JSON.stringify(value));
|
|
2087
|
+
}
|
|
2088
|
+
function configShowCommand(opts) {
|
|
2089
|
+
const configPath = resolveConfigPath(opts.configPath);
|
|
2090
|
+
if (!existsSync5(configPath)) {
|
|
2091
|
+
console.error(
|
|
2092
|
+
formatCliError({
|
|
2093
|
+
code: 1 /* CLIENT_ERROR */,
|
|
2094
|
+
type: "CONFIG_NOT_FOUND",
|
|
2095
|
+
message: `Config file not found: ${configPath}`,
|
|
2096
|
+
suggestion: "Run mcp-s-cli init or mcp-s-cli config set <key> <value>"
|
|
2097
|
+
})
|
|
2098
|
+
);
|
|
2099
|
+
process.exit(1 /* CLIENT_ERROR */);
|
|
2100
|
+
}
|
|
2101
|
+
const config = readConfigFile(configPath);
|
|
2102
|
+
console.log(JSON.stringify(config, null, 2));
|
|
2103
|
+
}
|
|
2104
|
+
function printConfigHelp() {
|
|
2105
|
+
console.log(`
|
|
2106
|
+
mcp-s-cli config - Read and write config.json settings
|
|
2107
|
+
|
|
2108
|
+
Usage:
|
|
2109
|
+
mcp-s-cli config set <key> <value> Set a config value
|
|
2110
|
+
mcp-s-cli config get <key> Print a single config value
|
|
2111
|
+
mcp-s-cli config show Print the full config as JSON
|
|
2112
|
+
|
|
2113
|
+
Keys (dot-notation for nested values):
|
|
2114
|
+
|
|
2115
|
+
General
|
|
2116
|
+
enabled boolean Whether mcp-s-cli is enabled (default: true)
|
|
2117
|
+
|
|
2118
|
+
Connection
|
|
2119
|
+
org string Org name \u2014 derives URL as https://<org>.mcp-s.com/mcp
|
|
2120
|
+
baseUrl string Custom server base URL (used when org is not set)
|
|
2121
|
+
mcp string MCP identifier sent as x-mcp header
|
|
2122
|
+
toolkit string Toolkit name sent as x-toolkit header
|
|
2123
|
+
token string Static Bearer token for HTTP auth
|
|
2124
|
+
userAccessKey string User access key \u2014 triggers stdio mode when present
|
|
2125
|
+
|
|
2126
|
+
Tool filtering
|
|
2127
|
+
allowedTools array Glob patterns for tools to allow (JSON array)
|
|
2128
|
+
disabledTools array Glob patterns to exclude (takes precedence over allowedTools)
|
|
2129
|
+
|
|
2130
|
+
Behaviour (settings.*)
|
|
2131
|
+
settings.timeout number Request timeout in seconds (default: 1800)
|
|
2132
|
+
settings.maxRetries number Max retry attempts; 0 = disable (default: 3)
|
|
2133
|
+
settings.retryDelay number Base retry delay in milliseconds (default: 1000)
|
|
2134
|
+
settings.daemon boolean Enable daemon connection caching (default: true)
|
|
2135
|
+
settings.daemonTimeout number Daemon idle timeout in seconds (default: 300)
|
|
2136
|
+
settings.history boolean Append invocations to history.jsonl (default: false)
|
|
2137
|
+
|
|
2138
|
+
Examples:
|
|
2139
|
+
mcp-s-cli config set org my-org
|
|
2140
|
+
mcp-s-cli config set settings.timeout 30
|
|
2141
|
+
mcp-s-cli config set settings.daemon false
|
|
2142
|
+
mcp-s-cli config get settings.timeout
|
|
2143
|
+
mcp-s-cli config show
|
|
2144
|
+
`);
|
|
2145
|
+
}
|
|
2146
|
+
function configCommand(opts) {
|
|
2147
|
+
switch (opts.subcommand) {
|
|
2148
|
+
case "set": {
|
|
2149
|
+
if (!opts.key) {
|
|
2150
|
+
console.error(
|
|
2151
|
+
formatCliError(missingArgumentError("config set", "key"))
|
|
2152
|
+
);
|
|
2153
|
+
process.exit(1 /* CLIENT_ERROR */);
|
|
2154
|
+
}
|
|
2155
|
+
if (opts.value === void 0) {
|
|
2156
|
+
console.error(
|
|
2157
|
+
formatCliError(missingArgumentError("config set", "value"))
|
|
2158
|
+
);
|
|
2159
|
+
process.exit(1 /* CLIENT_ERROR */);
|
|
2160
|
+
}
|
|
2161
|
+
configSetCommand({
|
|
2162
|
+
key: opts.key,
|
|
2163
|
+
value: opts.value,
|
|
2164
|
+
configPath: opts.configPath
|
|
2165
|
+
});
|
|
2166
|
+
break;
|
|
2167
|
+
}
|
|
2168
|
+
case "get": {
|
|
2169
|
+
if (!opts.key) {
|
|
2170
|
+
console.error(
|
|
2171
|
+
formatCliError(missingArgumentError("config get", "key"))
|
|
2172
|
+
);
|
|
2173
|
+
process.exit(1 /* CLIENT_ERROR */);
|
|
2174
|
+
}
|
|
2175
|
+
configGetCommand({ key: opts.key, configPath: opts.configPath });
|
|
2176
|
+
break;
|
|
2177
|
+
}
|
|
2178
|
+
case "show": {
|
|
2179
|
+
configShowCommand({ configPath: opts.configPath });
|
|
2180
|
+
break;
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
|
|
1937
2185
|
// src/commands/grep.ts
|
|
1938
2186
|
function globToRegex(pattern) {
|
|
1939
2187
|
let escaped = "";
|
|
@@ -1970,7 +2218,7 @@ async function grepCommand(options) {
|
|
|
1970
2218
|
console.error(error.message);
|
|
1971
2219
|
process.exit(1 /* CLIENT_ERROR */);
|
|
1972
2220
|
}
|
|
1973
|
-
const { serverConfig } = loaded;
|
|
2221
|
+
const { serverConfig, settings } = loaded;
|
|
1974
2222
|
const serverLabel = "server";
|
|
1975
2223
|
const pattern = globToRegex(options.pattern);
|
|
1976
2224
|
debug(`Searching for pattern "${options.pattern}"`);
|
|
@@ -1978,7 +2226,7 @@ async function grepCommand(options) {
|
|
|
1978
2226
|
const allResults = [];
|
|
1979
2227
|
let searchError;
|
|
1980
2228
|
try {
|
|
1981
|
-
connection = await getConnection(serverLabel, serverConfig);
|
|
2229
|
+
connection = await getConnection(serverLabel, serverConfig, settings);
|
|
1982
2230
|
const tools = await connection.listTools();
|
|
1983
2231
|
for (const tool of tools) {
|
|
1984
2232
|
if (pattern.test(tool.name)) {
|
|
@@ -2016,11 +2264,11 @@ async function infoCommand(options) {
|
|
|
2016
2264
|
console.error(error.message);
|
|
2017
2265
|
process.exit(1 /* CLIENT_ERROR */);
|
|
2018
2266
|
}
|
|
2019
|
-
const { serverConfig } = loaded;
|
|
2267
|
+
const { serverConfig, settings } = loaded;
|
|
2020
2268
|
const serverLabel = "server";
|
|
2021
2269
|
let connection;
|
|
2022
2270
|
try {
|
|
2023
|
-
connection = await getConnection(serverLabel, serverConfig);
|
|
2271
|
+
connection = await getConnection(serverLabel, serverConfig, settings);
|
|
2024
2272
|
} catch (error) {
|
|
2025
2273
|
console.error(
|
|
2026
2274
|
formatCliError(
|
|
@@ -2062,97 +2310,97 @@ async function infoCommand(options) {
|
|
|
2062
2310
|
}
|
|
2063
2311
|
|
|
2064
2312
|
// src/commands/init.ts
|
|
2065
|
-
import { mkdirSync as
|
|
2066
|
-
import { homedir as
|
|
2067
|
-
import { dirname as
|
|
2313
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
|
|
2314
|
+
import { homedir as homedir5 } from "os";
|
|
2315
|
+
import { dirname as dirname5, join as join6 } from "path";
|
|
2068
2316
|
import * as readline from "readline";
|
|
2069
2317
|
|
|
2070
2318
|
// src/commands/install-skill.ts
|
|
2071
2319
|
import {
|
|
2072
|
-
existsSync as
|
|
2320
|
+
existsSync as existsSync6,
|
|
2073
2321
|
lstatSync,
|
|
2074
|
-
mkdirSync as
|
|
2075
|
-
readFileSync as
|
|
2322
|
+
mkdirSync as mkdirSync4,
|
|
2323
|
+
readFileSync as readFileSync4,
|
|
2076
2324
|
readlinkSync,
|
|
2077
2325
|
rmSync as rmSync2,
|
|
2078
2326
|
symlinkSync,
|
|
2079
|
-
writeFileSync as
|
|
2327
|
+
writeFileSync as writeFileSync4
|
|
2080
2328
|
} from "fs";
|
|
2081
|
-
import { homedir as
|
|
2082
|
-
import { dirname as
|
|
2329
|
+
import { homedir as homedir4, platform } from "os";
|
|
2330
|
+
import { dirname as dirname4, join as join5, normalize, relative, resolve as resolve3, sep } from "path";
|
|
2083
2331
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2084
|
-
var home =
|
|
2332
|
+
var home = homedir4();
|
|
2085
2333
|
var AGENTS = {
|
|
2086
2334
|
cursor: {
|
|
2087
2335
|
displayName: "Cursor",
|
|
2088
|
-
globalSkillsDir:
|
|
2089
|
-
detect: () =>
|
|
2336
|
+
globalSkillsDir: join5(home, ".cursor", "skills"),
|
|
2337
|
+
detect: () => existsSync6(join5(home, ".cursor"))
|
|
2090
2338
|
},
|
|
2091
2339
|
codex: {
|
|
2092
2340
|
displayName: "Codex",
|
|
2093
|
-
globalSkillsDir:
|
|
2094
|
-
process.env.CODEX_HOME?.trim() ||
|
|
2341
|
+
globalSkillsDir: join5(
|
|
2342
|
+
process.env.CODEX_HOME?.trim() || join5(home, ".codex"),
|
|
2095
2343
|
"skills"
|
|
2096
2344
|
),
|
|
2097
|
-
detect: () =>
|
|
2345
|
+
detect: () => existsSync6(process.env.CODEX_HOME?.trim() || join5(home, ".codex")) || existsSync6("/etc/codex")
|
|
2098
2346
|
},
|
|
2099
2347
|
"claude-code": {
|
|
2100
2348
|
displayName: "Claude Code",
|
|
2101
|
-
globalSkillsDir:
|
|
2102
|
-
process.env.CLAUDE_CONFIG_DIR?.trim() ||
|
|
2349
|
+
globalSkillsDir: join5(
|
|
2350
|
+
process.env.CLAUDE_CONFIG_DIR?.trim() || join5(home, ".claude"),
|
|
2103
2351
|
"skills"
|
|
2104
2352
|
),
|
|
2105
|
-
detect: () =>
|
|
2106
|
-
process.env.CLAUDE_CONFIG_DIR?.trim() ||
|
|
2353
|
+
detect: () => existsSync6(
|
|
2354
|
+
process.env.CLAUDE_CONFIG_DIR?.trim() || join5(home, ".claude")
|
|
2107
2355
|
)
|
|
2108
2356
|
},
|
|
2109
2357
|
windsurf: {
|
|
2110
2358
|
displayName: "Windsurf",
|
|
2111
|
-
globalSkillsDir:
|
|
2112
|
-
detect: () =>
|
|
2359
|
+
globalSkillsDir: join5(home, ".codeium", "windsurf", "skills"),
|
|
2360
|
+
detect: () => existsSync6(join5(home, ".codeium", "windsurf"))
|
|
2113
2361
|
},
|
|
2114
2362
|
"github-copilot": {
|
|
2115
2363
|
displayName: "GitHub Copilot",
|
|
2116
|
-
globalSkillsDir:
|
|
2117
|
-
detect: () =>
|
|
2364
|
+
globalSkillsDir: join5(home, ".copilot", "skills"),
|
|
2365
|
+
detect: () => existsSync6(join5(home, ".copilot"))
|
|
2118
2366
|
},
|
|
2119
2367
|
cline: {
|
|
2120
2368
|
displayName: "Cline",
|
|
2121
|
-
globalSkillsDir:
|
|
2122
|
-
detect: () =>
|
|
2369
|
+
globalSkillsDir: join5(home, ".cline", "skills"),
|
|
2370
|
+
detect: () => existsSync6(join5(home, ".cline"))
|
|
2123
2371
|
},
|
|
2124
2372
|
roo: {
|
|
2125
2373
|
displayName: "Roo Code",
|
|
2126
|
-
globalSkillsDir:
|
|
2127
|
-
detect: () =>
|
|
2374
|
+
globalSkillsDir: join5(home, ".roo", "skills"),
|
|
2375
|
+
detect: () => existsSync6(join5(home, ".roo"))
|
|
2128
2376
|
},
|
|
2129
2377
|
continue: {
|
|
2130
2378
|
displayName: "Continue",
|
|
2131
|
-
globalSkillsDir:
|
|
2132
|
-
detect: () =>
|
|
2379
|
+
globalSkillsDir: join5(home, ".continue", "skills"),
|
|
2380
|
+
detect: () => existsSync6(join5(home, ".continue")) || existsSync6(join5(process.cwd(), ".continue"))
|
|
2133
2381
|
}
|
|
2134
2382
|
};
|
|
2135
2383
|
function getCanonicalSkillDir(skillName) {
|
|
2136
|
-
return
|
|
2384
|
+
return join5(home, ".agents", "skills", skillName);
|
|
2137
2385
|
}
|
|
2138
2386
|
function getCanonicalSkillPath() {
|
|
2139
2387
|
return getCanonicalSkillDir(SKILL_NAME);
|
|
2140
2388
|
}
|
|
2141
2389
|
function isPathSafe(base, target) {
|
|
2142
|
-
const normalizedBase = normalize(
|
|
2143
|
-
const normalizedTarget = normalize(
|
|
2390
|
+
const normalizedBase = normalize(resolve3(base));
|
|
2391
|
+
const normalizedTarget = normalize(resolve3(target));
|
|
2144
2392
|
return normalizedTarget.startsWith(normalizedBase + sep) || normalizedTarget === normalizedBase;
|
|
2145
2393
|
}
|
|
2146
2394
|
function createSymlinkSync(target, linkPath) {
|
|
2147
2395
|
try {
|
|
2148
|
-
const resolvedTarget =
|
|
2149
|
-
const resolvedLinkPath =
|
|
2396
|
+
const resolvedTarget = resolve3(target);
|
|
2397
|
+
const resolvedLinkPath = resolve3(linkPath);
|
|
2150
2398
|
if (resolvedTarget === resolvedLinkPath) return true;
|
|
2151
2399
|
try {
|
|
2152
2400
|
const stats = lstatSync(linkPath);
|
|
2153
2401
|
if (stats.isSymbolicLink()) {
|
|
2154
2402
|
const existing = readlinkSync(linkPath);
|
|
2155
|
-
const resolvedExisting =
|
|
2403
|
+
const resolvedExisting = resolve3(dirname4(linkPath), existing);
|
|
2156
2404
|
if (resolvedExisting === resolvedTarget) return true;
|
|
2157
2405
|
rmSync2(linkPath);
|
|
2158
2406
|
} else {
|
|
@@ -2166,8 +2414,8 @@ function createSymlinkSync(target, linkPath) {
|
|
|
2166
2414
|
}
|
|
2167
2415
|
}
|
|
2168
2416
|
}
|
|
2169
|
-
const linkDir =
|
|
2170
|
-
|
|
2417
|
+
const linkDir = dirname4(linkPath);
|
|
2418
|
+
mkdirSync4(linkDir, { recursive: true });
|
|
2171
2419
|
const relativePath = relative(linkDir, target);
|
|
2172
2420
|
symlinkSync(
|
|
2173
2421
|
relativePath,
|
|
@@ -2182,15 +2430,15 @@ function createSymlinkSync(target, linkPath) {
|
|
|
2182
2430
|
var SKILL_NAME = "mcp-s-cli";
|
|
2183
2431
|
function getSkillMdContent() {
|
|
2184
2432
|
const __filename = fileURLToPath2(import.meta.url);
|
|
2185
|
-
const __dirname =
|
|
2433
|
+
const __dirname = dirname4(__filename);
|
|
2186
2434
|
const candidates = [
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2435
|
+
join5(__dirname, "SKILL.md"),
|
|
2436
|
+
join5(__dirname, "..", "SKILL.md"),
|
|
2437
|
+
join5(__dirname, "..", "..", "SKILL.md")
|
|
2190
2438
|
];
|
|
2191
2439
|
for (const candidate of candidates) {
|
|
2192
|
-
if (
|
|
2193
|
-
return
|
|
2440
|
+
if (existsSync6(candidate)) {
|
|
2441
|
+
return readFileSync4(candidate, "utf-8");
|
|
2194
2442
|
}
|
|
2195
2443
|
}
|
|
2196
2444
|
throw new Error(
|
|
@@ -2200,12 +2448,12 @@ function getSkillMdContent() {
|
|
|
2200
2448
|
function installSkill() {
|
|
2201
2449
|
const content = getSkillMdContent();
|
|
2202
2450
|
const canonicalDir = getCanonicalSkillDir(SKILL_NAME);
|
|
2203
|
-
if (!isPathSafe(
|
|
2451
|
+
if (!isPathSafe(join5(home, ".agents", "skills"), canonicalDir)) {
|
|
2204
2452
|
throw new Error("Invalid skill name: potential path traversal detected");
|
|
2205
2453
|
}
|
|
2206
2454
|
rmSync2(canonicalDir, { recursive: true, force: true });
|
|
2207
|
-
|
|
2208
|
-
|
|
2455
|
+
mkdirSync4(canonicalDir, { recursive: true });
|
|
2456
|
+
writeFileSync4(join5(canonicalDir, "SKILL.md"), content, "utf-8");
|
|
2209
2457
|
const result = {
|
|
2210
2458
|
installed: [],
|
|
2211
2459
|
skipped: [],
|
|
@@ -2217,7 +2465,7 @@ function installSkill() {
|
|
|
2217
2465
|
result.skipped.push(agentName);
|
|
2218
2466
|
continue;
|
|
2219
2467
|
}
|
|
2220
|
-
const agentSkillDir =
|
|
2468
|
+
const agentSkillDir = join5(agent.globalSkillsDir, SKILL_NAME);
|
|
2221
2469
|
if (!isPathSafe(agent.globalSkillsDir, agentSkillDir)) {
|
|
2222
2470
|
result.failed.push({
|
|
2223
2471
|
agent: agentName,
|
|
@@ -2229,8 +2477,8 @@ function installSkill() {
|
|
|
2229
2477
|
const symlinkOk = createSymlinkSync(canonicalDir, agentSkillDir);
|
|
2230
2478
|
if (!symlinkOk) {
|
|
2231
2479
|
rmSync2(agentSkillDir, { recursive: true, force: true });
|
|
2232
|
-
|
|
2233
|
-
|
|
2480
|
+
mkdirSync4(agentSkillDir, { recursive: true });
|
|
2481
|
+
writeFileSync4(join5(agentSkillDir, "SKILL.md"), content, "utf-8");
|
|
2234
2482
|
}
|
|
2235
2483
|
result.installed.push(agentName);
|
|
2236
2484
|
} catch (err) {
|
|
@@ -2250,8 +2498,8 @@ function clearSkill() {
|
|
|
2250
2498
|
canonicalRemoved: false
|
|
2251
2499
|
};
|
|
2252
2500
|
for (const [agentName, agent] of Object.entries(AGENTS)) {
|
|
2253
|
-
const agentSkillDir =
|
|
2254
|
-
if (!
|
|
2501
|
+
const agentSkillDir = join5(agent.globalSkillsDir, SKILL_NAME);
|
|
2502
|
+
if (!existsSync6(agentSkillDir)) {
|
|
2255
2503
|
result.skipped.push(agentName);
|
|
2256
2504
|
continue;
|
|
2257
2505
|
}
|
|
@@ -2266,7 +2514,7 @@ function clearSkill() {
|
|
|
2266
2514
|
}
|
|
2267
2515
|
}
|
|
2268
2516
|
const canonicalDir = getCanonicalSkillDir(SKILL_NAME);
|
|
2269
|
-
if (
|
|
2517
|
+
if (existsSync6(canonicalDir)) {
|
|
2270
2518
|
try {
|
|
2271
2519
|
rmSync2(canonicalDir, { recursive: true, force: true });
|
|
2272
2520
|
result.canonicalRemoved = true;
|
|
@@ -2277,12 +2525,12 @@ function clearSkill() {
|
|
|
2277
2525
|
}
|
|
2278
2526
|
function getSkillInstallInfo() {
|
|
2279
2527
|
return Object.entries(AGENTS).filter(([, agent]) => agent.detect()).map(([agentName, agent]) => {
|
|
2280
|
-
const agentSkillDir =
|
|
2528
|
+
const agentSkillDir = join5(agent.globalSkillsDir, SKILL_NAME);
|
|
2281
2529
|
return {
|
|
2282
2530
|
agent: agentName,
|
|
2283
2531
|
displayName: agent.displayName,
|
|
2284
2532
|
path: agentSkillDir,
|
|
2285
|
-
installed:
|
|
2533
|
+
installed: existsSync6(join5(agentSkillDir, "SKILL.md"))
|
|
2286
2534
|
};
|
|
2287
2535
|
});
|
|
2288
2536
|
}
|
|
@@ -2352,7 +2600,7 @@ function cancel(msg) {
|
|
|
2352
2600
|
`);
|
|
2353
2601
|
}
|
|
2354
2602
|
function readLine(prompt) {
|
|
2355
|
-
return new Promise((
|
|
2603
|
+
return new Promise((resolve5) => {
|
|
2356
2604
|
const rl = readline.createInterface({
|
|
2357
2605
|
input: process.stdin,
|
|
2358
2606
|
output: process.stdout,
|
|
@@ -2361,16 +2609,16 @@ function readLine(prompt) {
|
|
|
2361
2609
|
process.stdout.write(prompt);
|
|
2362
2610
|
rl.once("line", (line) => {
|
|
2363
2611
|
rl.close();
|
|
2364
|
-
|
|
2612
|
+
resolve5(line);
|
|
2365
2613
|
});
|
|
2366
2614
|
rl.once("SIGINT", () => {
|
|
2367
2615
|
rl.close();
|
|
2368
2616
|
process.stdout.write("\n");
|
|
2369
|
-
|
|
2617
|
+
resolve5(CANCEL);
|
|
2370
2618
|
});
|
|
2371
2619
|
process.stdin.once("end", () => {
|
|
2372
2620
|
rl.close();
|
|
2373
|
-
|
|
2621
|
+
resolve5(CANCEL);
|
|
2374
2622
|
});
|
|
2375
2623
|
});
|
|
2376
2624
|
}
|
|
@@ -2403,14 +2651,14 @@ async function select(opts) {
|
|
|
2403
2651
|
`);
|
|
2404
2652
|
});
|
|
2405
2653
|
};
|
|
2406
|
-
return new Promise((
|
|
2654
|
+
return new Promise((resolve5) => {
|
|
2407
2655
|
readline.emitKeypressEvents(process.stdin);
|
|
2408
2656
|
process.stdin.setRawMode(true);
|
|
2409
2657
|
process.stdin.resume();
|
|
2410
2658
|
const onKey = (_, key) => {
|
|
2411
2659
|
if (key.ctrl && key.name === "c") {
|
|
2412
2660
|
cleanup();
|
|
2413
|
-
|
|
2661
|
+
resolve5(CANCEL);
|
|
2414
2662
|
return;
|
|
2415
2663
|
}
|
|
2416
2664
|
if (key.name === "up") {
|
|
@@ -2423,7 +2671,7 @@ async function select(opts) {
|
|
|
2423
2671
|
}
|
|
2424
2672
|
if (key.name === "return") {
|
|
2425
2673
|
cleanup();
|
|
2426
|
-
|
|
2674
|
+
resolve5(options[idx].value);
|
|
2427
2675
|
}
|
|
2428
2676
|
};
|
|
2429
2677
|
const cleanup = () => {
|
|
@@ -2474,15 +2722,24 @@ ${BAR} ${c(A.cyan, "\u25C6")} `
|
|
|
2474
2722
|
}
|
|
2475
2723
|
}
|
|
2476
2724
|
var p = { intro, outro, cancel, isCancel, select, text };
|
|
2477
|
-
var GLOBAL_CONFIG_PATH2 =
|
|
2478
|
-
|
|
2725
|
+
var GLOBAL_CONFIG_PATH2 = join6(
|
|
2726
|
+
homedir5(),
|
|
2479
2727
|
".config",
|
|
2480
2728
|
"mcp-s-cli",
|
|
2481
2729
|
"config.json"
|
|
2482
2730
|
);
|
|
2731
|
+
function readExistingConfig() {
|
|
2732
|
+
try {
|
|
2733
|
+
if (existsSync7(GLOBAL_CONFIG_PATH2)) {
|
|
2734
|
+
return JSON.parse(readFileSync5(GLOBAL_CONFIG_PATH2, "utf-8"));
|
|
2735
|
+
}
|
|
2736
|
+
} catch {
|
|
2737
|
+
}
|
|
2738
|
+
return {};
|
|
2739
|
+
}
|
|
2483
2740
|
function writeConfig(config) {
|
|
2484
|
-
|
|
2485
|
-
|
|
2741
|
+
mkdirSync5(dirname5(GLOBAL_CONFIG_PATH2), { recursive: true });
|
|
2742
|
+
writeFileSync5(
|
|
2486
2743
|
GLOBAL_CONFIG_PATH2,
|
|
2487
2744
|
`${JSON.stringify(config, null, 2)}
|
|
2488
2745
|
`,
|
|
@@ -2491,7 +2748,9 @@ function writeConfig(config) {
|
|
|
2491
2748
|
}
|
|
2492
2749
|
async function initCommand(options) {
|
|
2493
2750
|
const { baseUrl, org, mcp, toolkit, userAccessKey, token } = options;
|
|
2751
|
+
const existing = readExistingConfig();
|
|
2494
2752
|
const config = {};
|
|
2753
|
+
if (existing.settings) config.settings = existing.settings;
|
|
2495
2754
|
if (org) {
|
|
2496
2755
|
config.org = org;
|
|
2497
2756
|
} else if (baseUrl) {
|
|
@@ -2601,10 +2860,10 @@ async function initInteractive() {
|
|
|
2601
2860
|
}
|
|
2602
2861
|
|
|
2603
2862
|
// src/commands/kill-daemon.ts
|
|
2604
|
-
import { existsSync as
|
|
2863
|
+
import { existsSync as existsSync8, readdirSync as readdirSync2 } from "fs";
|
|
2605
2864
|
function killDaemonCommand() {
|
|
2606
2865
|
const socketDir = getSocketDir();
|
|
2607
|
-
if (!
|
|
2866
|
+
if (!existsSync8(socketDir)) {
|
|
2608
2867
|
console.log("No daemons running.");
|
|
2609
2868
|
return;
|
|
2610
2869
|
}
|
|
@@ -2654,14 +2913,14 @@ async function listCommand(options) {
|
|
|
2654
2913
|
console.error(error.message);
|
|
2655
2914
|
process.exit(1 /* CLIENT_ERROR */);
|
|
2656
2915
|
}
|
|
2657
|
-
const { serverConfig } = loaded;
|
|
2916
|
+
const { serverConfig, settings } = loaded;
|
|
2658
2917
|
const serverLabel = "server";
|
|
2659
2918
|
let connection = null;
|
|
2660
2919
|
let tools = [];
|
|
2661
2920
|
let instructions;
|
|
2662
2921
|
let errorMsg;
|
|
2663
2922
|
try {
|
|
2664
|
-
connection = await getConnection(serverLabel, serverConfig);
|
|
2923
|
+
connection = await getConnection(serverLabel, serverConfig, settings);
|
|
2665
2924
|
tools = await connection.listTools();
|
|
2666
2925
|
instructions = await connection.getInstructions();
|
|
2667
2926
|
debug(`${serverLabel}: loaded ${tools.length} tools`);
|
|
@@ -2703,18 +2962,18 @@ async function logoutCommand(options) {
|
|
|
2703
2962
|
}
|
|
2704
2963
|
|
|
2705
2964
|
// src/commands/whoami.ts
|
|
2706
|
-
import { existsSync as
|
|
2707
|
-
import { homedir as
|
|
2708
|
-
import { join as
|
|
2965
|
+
import { existsSync as existsSync9, readFileSync as readFileSync6, statSync } from "fs";
|
|
2966
|
+
import { homedir as homedir6 } from "os";
|
|
2967
|
+
import { join as join7, resolve as resolve4 } from "path";
|
|
2709
2968
|
function getResolvedConfigPath(explicitPath) {
|
|
2710
2969
|
if (explicitPath) {
|
|
2711
|
-
return
|
|
2970
|
+
return resolve4(explicitPath);
|
|
2712
2971
|
}
|
|
2713
|
-
if (process.env.
|
|
2714
|
-
return
|
|
2972
|
+
if (process.env.MCP_S_CLI_CONFIG_PATH) {
|
|
2973
|
+
return resolve4(process.env.MCP_S_CLI_CONFIG_PATH);
|
|
2715
2974
|
}
|
|
2716
|
-
const defaultPath =
|
|
2717
|
-
if (
|
|
2975
|
+
const defaultPath = join7(homedir6(), ".config", "mcp-s-cli", "config.json");
|
|
2976
|
+
if (existsSync9(defaultPath)) {
|
|
2718
2977
|
return defaultPath;
|
|
2719
2978
|
}
|
|
2720
2979
|
return null;
|
|
@@ -2742,15 +3001,15 @@ async function whoamiCommand(options) {
|
|
|
2742
3001
|
console.log(` Error loading config: ${err.message}`);
|
|
2743
3002
|
return;
|
|
2744
3003
|
}
|
|
2745
|
-
const authFilePath =
|
|
3004
|
+
const authFilePath = join7(homedir6(), ".config", "mcp-s-cli", "auth.json");
|
|
2746
3005
|
console.log("");
|
|
2747
3006
|
console.log("OAuth Tokens");
|
|
2748
3007
|
console.log(` Path: ${authFilePath}`);
|
|
2749
|
-
if (!
|
|
3008
|
+
if (!existsSync9(authFilePath)) {
|
|
2750
3009
|
console.log(" (no tokens stored)");
|
|
2751
3010
|
} else {
|
|
2752
3011
|
try {
|
|
2753
|
-
const raw2 =
|
|
3012
|
+
const raw2 = readFileSync6(authFilePath, "utf-8");
|
|
2754
3013
|
const data = JSON.parse(raw2);
|
|
2755
3014
|
const tokenEntries = Object.entries(data.tokens ?? {});
|
|
2756
3015
|
if (tokenEntries.length === 0) {
|
|
@@ -2760,9 +3019,9 @@ async function whoamiCommand(options) {
|
|
|
2760
3019
|
console.log(" (could not read auth file)");
|
|
2761
3020
|
}
|
|
2762
3021
|
}
|
|
2763
|
-
const historyPath =
|
|
2764
|
-
if (
|
|
2765
|
-
const lines =
|
|
3022
|
+
const historyPath = join7(homedir6(), ".config", "mcp-s-cli", "history.jsonl");
|
|
3023
|
+
if (existsSync9(historyPath)) {
|
|
3024
|
+
const lines = readFileSync6(historyPath, "utf-8").split("\n").filter(Boolean);
|
|
2766
3025
|
const size = statSync(historyPath).size;
|
|
2767
3026
|
const sizeStr = size >= 1024 * 1024 ? `${(size / (1024 * 1024)).toFixed(1)} MB` : size >= 1024 ? `${(size / 1024).toFixed(1)} KB` : `${size} B`;
|
|
2768
3027
|
console.log("");
|
|
@@ -2824,6 +3083,10 @@ function parseArgs2(args) {
|
|
|
2824
3083
|
switch (arg) {
|
|
2825
3084
|
case "-h":
|
|
2826
3085
|
case "--help":
|
|
3086
|
+
if (positional[0] === "config") {
|
|
3087
|
+
positional.push(arg);
|
|
3088
|
+
break;
|
|
3089
|
+
}
|
|
2827
3090
|
result.command = "help";
|
|
2828
3091
|
return result;
|
|
2829
3092
|
case "-v":
|
|
@@ -2987,6 +3250,38 @@ function parseArgs2(args) {
|
|
|
2987
3250
|
result.command = "kill-daemon";
|
|
2988
3251
|
return result;
|
|
2989
3252
|
}
|
|
3253
|
+
if (firstArg === "enable") {
|
|
3254
|
+
result.command = "enable";
|
|
3255
|
+
return result;
|
|
3256
|
+
}
|
|
3257
|
+
if (firstArg === "disable") {
|
|
3258
|
+
result.command = "disable";
|
|
3259
|
+
return result;
|
|
3260
|
+
}
|
|
3261
|
+
if (firstArg === "config") {
|
|
3262
|
+
result.command = "config";
|
|
3263
|
+
const sub = positional[1];
|
|
3264
|
+
if (!sub || sub === "--help" || sub === "-h" || sub === "help") {
|
|
3265
|
+
printConfigHelp();
|
|
3266
|
+
process.exit(0);
|
|
3267
|
+
}
|
|
3268
|
+
if (sub !== "set" && sub !== "get" && sub !== "show") {
|
|
3269
|
+
console.error(
|
|
3270
|
+
formatCliError({
|
|
3271
|
+
code: 1 /* CLIENT_ERROR */,
|
|
3272
|
+
type: "UNKNOWN_SUBCOMMAND",
|
|
3273
|
+
message: `Unknown config subcommand: "${sub}"`,
|
|
3274
|
+
details: "Valid subcommands: set, get, show",
|
|
3275
|
+
suggestion: "Run mcp-s-cli config --help to see usage and valid keys"
|
|
3276
|
+
})
|
|
3277
|
+
);
|
|
3278
|
+
process.exit(1 /* CLIENT_ERROR */);
|
|
3279
|
+
}
|
|
3280
|
+
result.configSubcommand = sub;
|
|
3281
|
+
result.configKey = positional[2];
|
|
3282
|
+
result.configValue = positional[3];
|
|
3283
|
+
return result;
|
|
3284
|
+
}
|
|
2990
3285
|
if (firstArg === "init") {
|
|
2991
3286
|
result.command = "init";
|
|
2992
3287
|
if (result.baseUrl && result.org) {
|
|
@@ -3026,10 +3321,16 @@ Usage:
|
|
|
3026
3321
|
mcp-s-cli whoami Show config location and auth state
|
|
3027
3322
|
mcp-s-cli login Log in to the configured server via OAuth
|
|
3028
3323
|
mcp-s-cli logout Log out (remove stored OAuth tokens)
|
|
3324
|
+
mcp-s-cli config set <key> <value> Set a value in config.json
|
|
3325
|
+
mcp-s-cli config get <key> Get a value from config.json
|
|
3326
|
+
mcp-s-cli config show Print full config.json
|
|
3327
|
+
mcp-s-cli config --help List all config keys with types and defaults
|
|
3029
3328
|
mcp-s-cli clear Clear server config (resets config.json to {})
|
|
3030
3329
|
mcp-s-cli clear-auth Clear all stored auth data (sets auth.json to {})
|
|
3031
3330
|
mcp-s-cli clear-history Delete the history file (~/.config/mcp-s-cli/history.jsonl)
|
|
3032
3331
|
mcp-s-cli clear-skill Remove the mcp-s-cli skill from all agent skill directories
|
|
3332
|
+
mcp-s-cli enable Enable mcp-s-cli
|
|
3333
|
+
mcp-s-cli disable Disable mcp-s-cli
|
|
3033
3334
|
|
|
3034
3335
|
Options:
|
|
3035
3336
|
-h, --help Show this help message
|
|
@@ -3061,30 +3362,33 @@ Examples:
|
|
|
3061
3362
|
mcp-s-cli whoami # Show config and auth state
|
|
3062
3363
|
mcp-s-cli login # Authenticate via OAuth
|
|
3063
3364
|
mcp-s-cli logout # Remove stored OAuth tokens
|
|
3365
|
+
mcp-s-cli config set settings.timeout 30 # Set request timeout to 30s
|
|
3064
3366
|
mcp-s-cli clear # Reset server config
|
|
3065
3367
|
mcp-s-cli clear-auth # Clear stored auth data
|
|
3066
3368
|
mcp-s-cli clear-skill # Remove installed skill from all agents
|
|
3067
3369
|
mcp-s-cli kill-daemon # Kill the running daemon process
|
|
3370
|
+
mcp-s-cli enable # Enable mcp-s-cli
|
|
3371
|
+
mcp-s-cli disable # Disable mcp-s-cli
|
|
3068
3372
|
|
|
3069
3373
|
Environment Variables:
|
|
3070
|
-
|
|
3071
|
-
|
|
3374
|
+
MCP_S_CLI_DEBUG=1 Enable debug output
|
|
3375
|
+
MCP_S_CLI_STRICT_ENV=false Warn (instead of error) on missing \${VAR} in config
|
|
3072
3376
|
|
|
3073
3377
|
Config File:
|
|
3074
3378
|
The CLI looks for config.json in:
|
|
3075
|
-
1. Path specified by
|
|
3379
|
+
1. Path specified by MCP_S_CLI_CONFIG_PATH or -c/--config
|
|
3076
3380
|
2. ~/.config/mcp-s-cli/config.json
|
|
3077
3381
|
|
|
3078
3382
|
'mcp-s-cli init' always writes to ~/.config/mcp-s-cli/config.json
|
|
3079
3383
|
`);
|
|
3080
3384
|
}
|
|
3081
|
-
function appendHistory(argv) {
|
|
3082
|
-
if (
|
|
3385
|
+
function appendHistory(argv, history) {
|
|
3386
|
+
if (!history) return;
|
|
3083
3387
|
try {
|
|
3084
|
-
const dir =
|
|
3085
|
-
|
|
3388
|
+
const dir = join8(homedir7(), ".config", "mcp-s-cli");
|
|
3389
|
+
mkdirSync6(dir, { recursive: true });
|
|
3086
3390
|
const entry = JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), args: argv });
|
|
3087
|
-
appendFileSync(
|
|
3391
|
+
appendFileSync(join8(dir, "history.jsonl"), `${entry}
|
|
3088
3392
|
`, "utf8");
|
|
3089
3393
|
} catch (err) {
|
|
3090
3394
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -3095,8 +3399,29 @@ function appendHistory(argv) {
|
|
|
3095
3399
|
}
|
|
3096
3400
|
}
|
|
3097
3401
|
async function main() {
|
|
3098
|
-
|
|
3099
|
-
const args = parseArgs2(
|
|
3402
|
+
const argv = process.argv.slice(2);
|
|
3403
|
+
const args = parseArgs2(argv);
|
|
3404
|
+
let settings;
|
|
3405
|
+
let enabled;
|
|
3406
|
+
try {
|
|
3407
|
+
const loaded = await loadConfig(args.configPath);
|
|
3408
|
+
settings = loaded.settings;
|
|
3409
|
+
enabled = loaded.raw.enabled;
|
|
3410
|
+
} catch {
|
|
3411
|
+
}
|
|
3412
|
+
appendHistory(argv, settings?.history);
|
|
3413
|
+
const META_COMMANDS = /* @__PURE__ */ new Set([
|
|
3414
|
+
"enable",
|
|
3415
|
+
"disable",
|
|
3416
|
+
"config",
|
|
3417
|
+
"help",
|
|
3418
|
+
"version",
|
|
3419
|
+
"init"
|
|
3420
|
+
]);
|
|
3421
|
+
if (!(enabled ?? true) && !META_COMMANDS.has(args.command)) {
|
|
3422
|
+
console.error("mcp-s-cli is disabled. To enable, run: mcp-s-cli enable");
|
|
3423
|
+
process.exit(1);
|
|
3424
|
+
}
|
|
3100
3425
|
switch (args.command) {
|
|
3101
3426
|
case "help":
|
|
3102
3427
|
printHelp();
|
|
@@ -3131,6 +3456,14 @@ async function main() {
|
|
|
3131
3456
|
configPath: args.configPath
|
|
3132
3457
|
});
|
|
3133
3458
|
break;
|
|
3459
|
+
case "config":
|
|
3460
|
+
configCommand({
|
|
3461
|
+
subcommand: args.configSubcommand ?? "show",
|
|
3462
|
+
key: args.configKey,
|
|
3463
|
+
value: args.configValue,
|
|
3464
|
+
configPath: args.configPath
|
|
3465
|
+
});
|
|
3466
|
+
break;
|
|
3134
3467
|
case "init":
|
|
3135
3468
|
if (args.baseUrl || args.org) {
|
|
3136
3469
|
await initCommand({
|
|
@@ -3184,6 +3517,22 @@ async function main() {
|
|
|
3184
3517
|
}
|
|
3185
3518
|
break;
|
|
3186
3519
|
}
|
|
3520
|
+
case "enable":
|
|
3521
|
+
configSetCommand({
|
|
3522
|
+
key: "enabled",
|
|
3523
|
+
value: "true",
|
|
3524
|
+
configPath: args.configPath
|
|
3525
|
+
});
|
|
3526
|
+
console.log("mcp-s-cli is now enabled.");
|
|
3527
|
+
break;
|
|
3528
|
+
case "disable":
|
|
3529
|
+
configSetCommand({
|
|
3530
|
+
key: "enabled",
|
|
3531
|
+
value: "false",
|
|
3532
|
+
configPath: args.configPath
|
|
3533
|
+
});
|
|
3534
|
+
console.log("mcp-s-cli is now disabled.");
|
|
3535
|
+
break;
|
|
3187
3536
|
}
|
|
3188
3537
|
}
|
|
3189
3538
|
process.on("SIGINT", () => {
|