@mcp-s/cli 0.0.10 → 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/dist/daemon.js CHANGED
@@ -414,7 +414,7 @@ import { join as join2 } from "path";
414
414
  import { fileURLToPath } from "url";
415
415
 
416
416
  // src/version.ts
417
- var VERSION = "0.0.10";
417
+ var VERSION = "0.0.11";
418
418
 
419
419
  // src/client.ts
420
420
  function getRetryConfig(settings) {
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 mkdirSync5 } from "fs";
5
- import { homedir as homedir6 } from "os";
6
- import { join as join7 } from "path";
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";
@@ -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((resolve4, reject) => {
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
- resolve4(code);
224
+ resolve5(code);
225
225
  return;
226
226
  }
227
227
  res.writeHead(400, { "Content-Type": "text/html" });
@@ -764,6 +764,7 @@ async function loadConfig(explicitPath) {
764
764
  throw new Error(formatCliError(configMissingFieldError(configPath)));
765
765
  }
766
766
  const knownFields = [
767
+ "enabled",
767
768
  "org",
768
769
  "baseUrl",
769
770
  "mcp",
@@ -1017,7 +1018,7 @@ async function runDaemon(serverName, config, settings) {
1017
1018
  };
1018
1019
  }
1019
1020
  };
1020
- await new Promise((resolve4, reject) => {
1021
+ await new Promise((resolve5, reject) => {
1021
1022
  server = createServer((socket) => {
1022
1023
  activeConnections.add(socket);
1023
1024
  debug(`[daemon:${serverName}] Client connected`);
@@ -1049,7 +1050,7 @@ async function runDaemon(serverName, config, settings) {
1049
1050
  writeFileSync(getReadyPath(), String(process.pid), {
1050
1051
  mode: 384
1051
1052
  });
1052
- resolve4();
1053
+ resolve5();
1053
1054
  });
1054
1055
  }).catch(async (error) => {
1055
1056
  console.error(
@@ -1097,7 +1098,7 @@ function generateRequestId() {
1097
1098
  return `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
1098
1099
  }
1099
1100
  async function sendRequest(socketPath, request) {
1100
- return new Promise((resolve4, reject) => {
1101
+ return new Promise((resolve5, reject) => {
1101
1102
  const socket = createConnection(socketPath);
1102
1103
  let settled = false;
1103
1104
  const settle = (fn) => {
@@ -1125,7 +1126,7 @@ async function sendRequest(socketPath, request) {
1125
1126
  const response = JSON.parse(line);
1126
1127
  clearTimeout(timer);
1127
1128
  socket.end();
1128
- settle(() => resolve4(response));
1129
+ settle(() => resolve5(response));
1129
1130
  } catch {
1130
1131
  clearTimeout(timer);
1131
1132
  socket.end();
@@ -1297,7 +1298,7 @@ async function cleanupOrphanedDaemons() {
1297
1298
  }
1298
1299
 
1299
1300
  // src/version.ts
1300
- var VERSION = "0.0.10";
1301
+ var VERSION = "0.0.11";
1301
1302
 
1302
1303
  // src/client.ts
1303
1304
  function getRetryConfig(settings) {
@@ -1349,7 +1350,7 @@ function calculateDelay(attempt, config) {
1349
1350
  return Math.round(cappedDelay + jitter);
1350
1351
  }
1351
1352
  function sleep(ms) {
1352
- return new Promise((resolve4) => setTimeout(resolve4, ms));
1353
+ return new Promise((resolve5) => setTimeout(resolve5, ms));
1353
1354
  }
1354
1355
  async function withRetry(fn, operationName, config = getRetryConfig()) {
1355
1356
  let lastError;
@@ -1940,6 +1941,247 @@ function clearHistoryCommand() {
1940
1941
  console.log(`Cleared history from ${HISTORY_PATH}`);
1941
1942
  }
1942
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
+
1943
2185
  // src/commands/grep.ts
1944
2186
  function globToRegex(pattern) {
1945
2187
  let escaped = "";
@@ -2068,97 +2310,97 @@ async function infoCommand(options) {
2068
2310
  }
2069
2311
 
2070
2312
  // src/commands/init.ts
2071
- import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
2072
- import { homedir as homedir4 } from "os";
2073
- import { dirname as dirname4, join as join5 } from "path";
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";
2074
2316
  import * as readline from "readline";
2075
2317
 
2076
2318
  // src/commands/install-skill.ts
2077
2319
  import {
2078
- existsSync as existsSync5,
2320
+ existsSync as existsSync6,
2079
2321
  lstatSync,
2080
- mkdirSync as mkdirSync3,
2081
- readFileSync as readFileSync3,
2322
+ mkdirSync as mkdirSync4,
2323
+ readFileSync as readFileSync4,
2082
2324
  readlinkSync,
2083
2325
  rmSync as rmSync2,
2084
2326
  symlinkSync,
2085
- writeFileSync as writeFileSync3
2327
+ writeFileSync as writeFileSync4
2086
2328
  } from "fs";
2087
- import { homedir as homedir3, platform } from "os";
2088
- import { dirname as dirname3, join as join4, normalize, relative, resolve as resolve2, sep } from "path";
2329
+ import { homedir as homedir4, platform } from "os";
2330
+ import { dirname as dirname4, join as join5, normalize, relative, resolve as resolve3, sep } from "path";
2089
2331
  import { fileURLToPath as fileURLToPath2 } from "url";
2090
- var home = homedir3();
2332
+ var home = homedir4();
2091
2333
  var AGENTS = {
2092
2334
  cursor: {
2093
2335
  displayName: "Cursor",
2094
- globalSkillsDir: join4(home, ".cursor", "skills"),
2095
- detect: () => existsSync5(join4(home, ".cursor"))
2336
+ globalSkillsDir: join5(home, ".cursor", "skills"),
2337
+ detect: () => existsSync6(join5(home, ".cursor"))
2096
2338
  },
2097
2339
  codex: {
2098
2340
  displayName: "Codex",
2099
- globalSkillsDir: join4(
2100
- process.env.CODEX_HOME?.trim() || join4(home, ".codex"),
2341
+ globalSkillsDir: join5(
2342
+ process.env.CODEX_HOME?.trim() || join5(home, ".codex"),
2101
2343
  "skills"
2102
2344
  ),
2103
- detect: () => existsSync5(process.env.CODEX_HOME?.trim() || join4(home, ".codex")) || existsSync5("/etc/codex")
2345
+ detect: () => existsSync6(process.env.CODEX_HOME?.trim() || join5(home, ".codex")) || existsSync6("/etc/codex")
2104
2346
  },
2105
2347
  "claude-code": {
2106
2348
  displayName: "Claude Code",
2107
- globalSkillsDir: join4(
2108
- process.env.CLAUDE_CONFIG_DIR?.trim() || join4(home, ".claude"),
2349
+ globalSkillsDir: join5(
2350
+ process.env.CLAUDE_CONFIG_DIR?.trim() || join5(home, ".claude"),
2109
2351
  "skills"
2110
2352
  ),
2111
- detect: () => existsSync5(
2112
- process.env.CLAUDE_CONFIG_DIR?.trim() || join4(home, ".claude")
2353
+ detect: () => existsSync6(
2354
+ process.env.CLAUDE_CONFIG_DIR?.trim() || join5(home, ".claude")
2113
2355
  )
2114
2356
  },
2115
2357
  windsurf: {
2116
2358
  displayName: "Windsurf",
2117
- globalSkillsDir: join4(home, ".codeium", "windsurf", "skills"),
2118
- detect: () => existsSync5(join4(home, ".codeium", "windsurf"))
2359
+ globalSkillsDir: join5(home, ".codeium", "windsurf", "skills"),
2360
+ detect: () => existsSync6(join5(home, ".codeium", "windsurf"))
2119
2361
  },
2120
2362
  "github-copilot": {
2121
2363
  displayName: "GitHub Copilot",
2122
- globalSkillsDir: join4(home, ".copilot", "skills"),
2123
- detect: () => existsSync5(join4(home, ".copilot"))
2364
+ globalSkillsDir: join5(home, ".copilot", "skills"),
2365
+ detect: () => existsSync6(join5(home, ".copilot"))
2124
2366
  },
2125
2367
  cline: {
2126
2368
  displayName: "Cline",
2127
- globalSkillsDir: join4(home, ".cline", "skills"),
2128
- detect: () => existsSync5(join4(home, ".cline"))
2369
+ globalSkillsDir: join5(home, ".cline", "skills"),
2370
+ detect: () => existsSync6(join5(home, ".cline"))
2129
2371
  },
2130
2372
  roo: {
2131
2373
  displayName: "Roo Code",
2132
- globalSkillsDir: join4(home, ".roo", "skills"),
2133
- detect: () => existsSync5(join4(home, ".roo"))
2374
+ globalSkillsDir: join5(home, ".roo", "skills"),
2375
+ detect: () => existsSync6(join5(home, ".roo"))
2134
2376
  },
2135
2377
  continue: {
2136
2378
  displayName: "Continue",
2137
- globalSkillsDir: join4(home, ".continue", "skills"),
2138
- detect: () => existsSync5(join4(home, ".continue")) || existsSync5(join4(process.cwd(), ".continue"))
2379
+ globalSkillsDir: join5(home, ".continue", "skills"),
2380
+ detect: () => existsSync6(join5(home, ".continue")) || existsSync6(join5(process.cwd(), ".continue"))
2139
2381
  }
2140
2382
  };
2141
2383
  function getCanonicalSkillDir(skillName) {
2142
- return join4(home, ".agents", "skills", skillName);
2384
+ return join5(home, ".agents", "skills", skillName);
2143
2385
  }
2144
2386
  function getCanonicalSkillPath() {
2145
2387
  return getCanonicalSkillDir(SKILL_NAME);
2146
2388
  }
2147
2389
  function isPathSafe(base, target) {
2148
- const normalizedBase = normalize(resolve2(base));
2149
- const normalizedTarget = normalize(resolve2(target));
2390
+ const normalizedBase = normalize(resolve3(base));
2391
+ const normalizedTarget = normalize(resolve3(target));
2150
2392
  return normalizedTarget.startsWith(normalizedBase + sep) || normalizedTarget === normalizedBase;
2151
2393
  }
2152
2394
  function createSymlinkSync(target, linkPath) {
2153
2395
  try {
2154
- const resolvedTarget = resolve2(target);
2155
- const resolvedLinkPath = resolve2(linkPath);
2396
+ const resolvedTarget = resolve3(target);
2397
+ const resolvedLinkPath = resolve3(linkPath);
2156
2398
  if (resolvedTarget === resolvedLinkPath) return true;
2157
2399
  try {
2158
2400
  const stats = lstatSync(linkPath);
2159
2401
  if (stats.isSymbolicLink()) {
2160
2402
  const existing = readlinkSync(linkPath);
2161
- const resolvedExisting = resolve2(dirname3(linkPath), existing);
2403
+ const resolvedExisting = resolve3(dirname4(linkPath), existing);
2162
2404
  if (resolvedExisting === resolvedTarget) return true;
2163
2405
  rmSync2(linkPath);
2164
2406
  } else {
@@ -2172,8 +2414,8 @@ function createSymlinkSync(target, linkPath) {
2172
2414
  }
2173
2415
  }
2174
2416
  }
2175
- const linkDir = dirname3(linkPath);
2176
- mkdirSync3(linkDir, { recursive: true });
2417
+ const linkDir = dirname4(linkPath);
2418
+ mkdirSync4(linkDir, { recursive: true });
2177
2419
  const relativePath = relative(linkDir, target);
2178
2420
  symlinkSync(
2179
2421
  relativePath,
@@ -2188,15 +2430,15 @@ function createSymlinkSync(target, linkPath) {
2188
2430
  var SKILL_NAME = "mcp-s-cli";
2189
2431
  function getSkillMdContent() {
2190
2432
  const __filename = fileURLToPath2(import.meta.url);
2191
- const __dirname = dirname3(__filename);
2433
+ const __dirname = dirname4(__filename);
2192
2434
  const candidates = [
2193
- join4(__dirname, "SKILL.md"),
2194
- join4(__dirname, "..", "SKILL.md"),
2195
- join4(__dirname, "..", "..", "SKILL.md")
2435
+ join5(__dirname, "SKILL.md"),
2436
+ join5(__dirname, "..", "SKILL.md"),
2437
+ join5(__dirname, "..", "..", "SKILL.md")
2196
2438
  ];
2197
2439
  for (const candidate of candidates) {
2198
- if (existsSync5(candidate)) {
2199
- return readFileSync3(candidate, "utf-8");
2440
+ if (existsSync6(candidate)) {
2441
+ return readFileSync4(candidate, "utf-8");
2200
2442
  }
2201
2443
  }
2202
2444
  throw new Error(
@@ -2206,12 +2448,12 @@ function getSkillMdContent() {
2206
2448
  function installSkill() {
2207
2449
  const content = getSkillMdContent();
2208
2450
  const canonicalDir = getCanonicalSkillDir(SKILL_NAME);
2209
- if (!isPathSafe(join4(home, ".agents", "skills"), canonicalDir)) {
2451
+ if (!isPathSafe(join5(home, ".agents", "skills"), canonicalDir)) {
2210
2452
  throw new Error("Invalid skill name: potential path traversal detected");
2211
2453
  }
2212
2454
  rmSync2(canonicalDir, { recursive: true, force: true });
2213
- mkdirSync3(canonicalDir, { recursive: true });
2214
- writeFileSync3(join4(canonicalDir, "SKILL.md"), content, "utf-8");
2455
+ mkdirSync4(canonicalDir, { recursive: true });
2456
+ writeFileSync4(join5(canonicalDir, "SKILL.md"), content, "utf-8");
2215
2457
  const result = {
2216
2458
  installed: [],
2217
2459
  skipped: [],
@@ -2223,7 +2465,7 @@ function installSkill() {
2223
2465
  result.skipped.push(agentName);
2224
2466
  continue;
2225
2467
  }
2226
- const agentSkillDir = join4(agent.globalSkillsDir, SKILL_NAME);
2468
+ const agentSkillDir = join5(agent.globalSkillsDir, SKILL_NAME);
2227
2469
  if (!isPathSafe(agent.globalSkillsDir, agentSkillDir)) {
2228
2470
  result.failed.push({
2229
2471
  agent: agentName,
@@ -2235,8 +2477,8 @@ function installSkill() {
2235
2477
  const symlinkOk = createSymlinkSync(canonicalDir, agentSkillDir);
2236
2478
  if (!symlinkOk) {
2237
2479
  rmSync2(agentSkillDir, { recursive: true, force: true });
2238
- mkdirSync3(agentSkillDir, { recursive: true });
2239
- writeFileSync3(join4(agentSkillDir, "SKILL.md"), content, "utf-8");
2480
+ mkdirSync4(agentSkillDir, { recursive: true });
2481
+ writeFileSync4(join5(agentSkillDir, "SKILL.md"), content, "utf-8");
2240
2482
  }
2241
2483
  result.installed.push(agentName);
2242
2484
  } catch (err) {
@@ -2256,8 +2498,8 @@ function clearSkill() {
2256
2498
  canonicalRemoved: false
2257
2499
  };
2258
2500
  for (const [agentName, agent] of Object.entries(AGENTS)) {
2259
- const agentSkillDir = join4(agent.globalSkillsDir, SKILL_NAME);
2260
- if (!existsSync5(agentSkillDir)) {
2501
+ const agentSkillDir = join5(agent.globalSkillsDir, SKILL_NAME);
2502
+ if (!existsSync6(agentSkillDir)) {
2261
2503
  result.skipped.push(agentName);
2262
2504
  continue;
2263
2505
  }
@@ -2272,7 +2514,7 @@ function clearSkill() {
2272
2514
  }
2273
2515
  }
2274
2516
  const canonicalDir = getCanonicalSkillDir(SKILL_NAME);
2275
- if (existsSync5(canonicalDir)) {
2517
+ if (existsSync6(canonicalDir)) {
2276
2518
  try {
2277
2519
  rmSync2(canonicalDir, { recursive: true, force: true });
2278
2520
  result.canonicalRemoved = true;
@@ -2283,12 +2525,12 @@ function clearSkill() {
2283
2525
  }
2284
2526
  function getSkillInstallInfo() {
2285
2527
  return Object.entries(AGENTS).filter(([, agent]) => agent.detect()).map(([agentName, agent]) => {
2286
- const agentSkillDir = join4(agent.globalSkillsDir, SKILL_NAME);
2528
+ const agentSkillDir = join5(agent.globalSkillsDir, SKILL_NAME);
2287
2529
  return {
2288
2530
  agent: agentName,
2289
2531
  displayName: agent.displayName,
2290
2532
  path: agentSkillDir,
2291
- installed: existsSync5(join4(agentSkillDir, "SKILL.md"))
2533
+ installed: existsSync6(join5(agentSkillDir, "SKILL.md"))
2292
2534
  };
2293
2535
  });
2294
2536
  }
@@ -2358,7 +2600,7 @@ function cancel(msg) {
2358
2600
  `);
2359
2601
  }
2360
2602
  function readLine(prompt) {
2361
- return new Promise((resolve4) => {
2603
+ return new Promise((resolve5) => {
2362
2604
  const rl = readline.createInterface({
2363
2605
  input: process.stdin,
2364
2606
  output: process.stdout,
@@ -2367,16 +2609,16 @@ function readLine(prompt) {
2367
2609
  process.stdout.write(prompt);
2368
2610
  rl.once("line", (line) => {
2369
2611
  rl.close();
2370
- resolve4(line);
2612
+ resolve5(line);
2371
2613
  });
2372
2614
  rl.once("SIGINT", () => {
2373
2615
  rl.close();
2374
2616
  process.stdout.write("\n");
2375
- resolve4(CANCEL);
2617
+ resolve5(CANCEL);
2376
2618
  });
2377
2619
  process.stdin.once("end", () => {
2378
2620
  rl.close();
2379
- resolve4(CANCEL);
2621
+ resolve5(CANCEL);
2380
2622
  });
2381
2623
  });
2382
2624
  }
@@ -2409,14 +2651,14 @@ async function select(opts) {
2409
2651
  `);
2410
2652
  });
2411
2653
  };
2412
- return new Promise((resolve4) => {
2654
+ return new Promise((resolve5) => {
2413
2655
  readline.emitKeypressEvents(process.stdin);
2414
2656
  process.stdin.setRawMode(true);
2415
2657
  process.stdin.resume();
2416
2658
  const onKey = (_, key) => {
2417
2659
  if (key.ctrl && key.name === "c") {
2418
2660
  cleanup();
2419
- resolve4(CANCEL);
2661
+ resolve5(CANCEL);
2420
2662
  return;
2421
2663
  }
2422
2664
  if (key.name === "up") {
@@ -2429,7 +2671,7 @@ async function select(opts) {
2429
2671
  }
2430
2672
  if (key.name === "return") {
2431
2673
  cleanup();
2432
- resolve4(options[idx].value);
2674
+ resolve5(options[idx].value);
2433
2675
  }
2434
2676
  };
2435
2677
  const cleanup = () => {
@@ -2480,24 +2722,24 @@ ${BAR} ${c(A.cyan, "\u25C6")} `
2480
2722
  }
2481
2723
  }
2482
2724
  var p = { intro, outro, cancel, isCancel, select, text };
2483
- var GLOBAL_CONFIG_PATH2 = join5(
2484
- homedir4(),
2725
+ var GLOBAL_CONFIG_PATH2 = join6(
2726
+ homedir5(),
2485
2727
  ".config",
2486
2728
  "mcp-s-cli",
2487
2729
  "config.json"
2488
2730
  );
2489
2731
  function readExistingConfig() {
2490
2732
  try {
2491
- if (existsSync6(GLOBAL_CONFIG_PATH2)) {
2492
- return JSON.parse(readFileSync4(GLOBAL_CONFIG_PATH2, "utf-8"));
2733
+ if (existsSync7(GLOBAL_CONFIG_PATH2)) {
2734
+ return JSON.parse(readFileSync5(GLOBAL_CONFIG_PATH2, "utf-8"));
2493
2735
  }
2494
2736
  } catch {
2495
2737
  }
2496
2738
  return {};
2497
2739
  }
2498
2740
  function writeConfig(config) {
2499
- mkdirSync4(dirname4(GLOBAL_CONFIG_PATH2), { recursive: true });
2500
- writeFileSync4(
2741
+ mkdirSync5(dirname5(GLOBAL_CONFIG_PATH2), { recursive: true });
2742
+ writeFileSync5(
2501
2743
  GLOBAL_CONFIG_PATH2,
2502
2744
  `${JSON.stringify(config, null, 2)}
2503
2745
  `,
@@ -2618,10 +2860,10 @@ async function initInteractive() {
2618
2860
  }
2619
2861
 
2620
2862
  // src/commands/kill-daemon.ts
2621
- import { existsSync as existsSync7, readdirSync as readdirSync2 } from "fs";
2863
+ import { existsSync as existsSync8, readdirSync as readdirSync2 } from "fs";
2622
2864
  function killDaemonCommand() {
2623
2865
  const socketDir = getSocketDir();
2624
- if (!existsSync7(socketDir)) {
2866
+ if (!existsSync8(socketDir)) {
2625
2867
  console.log("No daemons running.");
2626
2868
  return;
2627
2869
  }
@@ -2720,18 +2962,18 @@ async function logoutCommand(options) {
2720
2962
  }
2721
2963
 
2722
2964
  // src/commands/whoami.ts
2723
- import { existsSync as existsSync8, readFileSync as readFileSync5, statSync } from "fs";
2724
- import { homedir as homedir5 } from "os";
2725
- import { join as join6, resolve as resolve3 } from "path";
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";
2726
2968
  function getResolvedConfigPath(explicitPath) {
2727
2969
  if (explicitPath) {
2728
- return resolve3(explicitPath);
2970
+ return resolve4(explicitPath);
2729
2971
  }
2730
2972
  if (process.env.MCP_S_CLI_CONFIG_PATH) {
2731
- return resolve3(process.env.MCP_S_CLI_CONFIG_PATH);
2973
+ return resolve4(process.env.MCP_S_CLI_CONFIG_PATH);
2732
2974
  }
2733
- const defaultPath = join6(homedir5(), ".config", "mcp-s-cli", "config.json");
2734
- if (existsSync8(defaultPath)) {
2975
+ const defaultPath = join7(homedir6(), ".config", "mcp-s-cli", "config.json");
2976
+ if (existsSync9(defaultPath)) {
2735
2977
  return defaultPath;
2736
2978
  }
2737
2979
  return null;
@@ -2759,15 +3001,15 @@ async function whoamiCommand(options) {
2759
3001
  console.log(` Error loading config: ${err.message}`);
2760
3002
  return;
2761
3003
  }
2762
- const authFilePath = join6(homedir5(), ".config", "mcp-s-cli", "auth.json");
3004
+ const authFilePath = join7(homedir6(), ".config", "mcp-s-cli", "auth.json");
2763
3005
  console.log("");
2764
3006
  console.log("OAuth Tokens");
2765
3007
  console.log(` Path: ${authFilePath}`);
2766
- if (!existsSync8(authFilePath)) {
3008
+ if (!existsSync9(authFilePath)) {
2767
3009
  console.log(" (no tokens stored)");
2768
3010
  } else {
2769
3011
  try {
2770
- const raw2 = readFileSync5(authFilePath, "utf-8");
3012
+ const raw2 = readFileSync6(authFilePath, "utf-8");
2771
3013
  const data = JSON.parse(raw2);
2772
3014
  const tokenEntries = Object.entries(data.tokens ?? {});
2773
3015
  if (tokenEntries.length === 0) {
@@ -2777,9 +3019,9 @@ async function whoamiCommand(options) {
2777
3019
  console.log(" (could not read auth file)");
2778
3020
  }
2779
3021
  }
2780
- const historyPath = join6(homedir5(), ".config", "mcp-s-cli", "history.jsonl");
2781
- if (existsSync8(historyPath)) {
2782
- const lines = readFileSync5(historyPath, "utf-8").split("\n").filter(Boolean);
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);
2783
3025
  const size = statSync(historyPath).size;
2784
3026
  const sizeStr = size >= 1024 * 1024 ? `${(size / (1024 * 1024)).toFixed(1)} MB` : size >= 1024 ? `${(size / 1024).toFixed(1)} KB` : `${size} B`;
2785
3027
  console.log("");
@@ -2841,6 +3083,10 @@ function parseArgs2(args) {
2841
3083
  switch (arg) {
2842
3084
  case "-h":
2843
3085
  case "--help":
3086
+ if (positional[0] === "config") {
3087
+ positional.push(arg);
3088
+ break;
3089
+ }
2844
3090
  result.command = "help";
2845
3091
  return result;
2846
3092
  case "-v":
@@ -3004,6 +3250,38 @@ function parseArgs2(args) {
3004
3250
  result.command = "kill-daemon";
3005
3251
  return result;
3006
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
+ }
3007
3285
  if (firstArg === "init") {
3008
3286
  result.command = "init";
3009
3287
  if (result.baseUrl && result.org) {
@@ -3043,10 +3321,16 @@ Usage:
3043
3321
  mcp-s-cli whoami Show config location and auth state
3044
3322
  mcp-s-cli login Log in to the configured server via OAuth
3045
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
3046
3328
  mcp-s-cli clear Clear server config (resets config.json to {})
3047
3329
  mcp-s-cli clear-auth Clear all stored auth data (sets auth.json to {})
3048
3330
  mcp-s-cli clear-history Delete the history file (~/.config/mcp-s-cli/history.jsonl)
3049
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
3050
3334
 
3051
3335
  Options:
3052
3336
  -h, --help Show this help message
@@ -3078,10 +3362,13 @@ Examples:
3078
3362
  mcp-s-cli whoami # Show config and auth state
3079
3363
  mcp-s-cli login # Authenticate via OAuth
3080
3364
  mcp-s-cli logout # Remove stored OAuth tokens
3365
+ mcp-s-cli config set settings.timeout 30 # Set request timeout to 30s
3081
3366
  mcp-s-cli clear # Reset server config
3082
3367
  mcp-s-cli clear-auth # Clear stored auth data
3083
3368
  mcp-s-cli clear-skill # Remove installed skill from all agents
3084
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
3085
3372
 
3086
3373
  Environment Variables:
3087
3374
  MCP_S_CLI_DEBUG=1 Enable debug output
@@ -3098,10 +3385,10 @@ Config File:
3098
3385
  function appendHistory(argv, history) {
3099
3386
  if (!history) return;
3100
3387
  try {
3101
- const dir = join7(homedir6(), ".config", "mcp-s-cli");
3102
- mkdirSync5(dir, { recursive: true });
3388
+ const dir = join8(homedir7(), ".config", "mcp-s-cli");
3389
+ mkdirSync6(dir, { recursive: true });
3103
3390
  const entry = JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), args: argv });
3104
- appendFileSync(join7(dir, "history.jsonl"), `${entry}
3391
+ appendFileSync(join8(dir, "history.jsonl"), `${entry}
3105
3392
  `, "utf8");
3106
3393
  } catch (err) {
3107
3394
  const msg = err instanceof Error ? err.message : String(err);
@@ -3115,12 +3402,26 @@ async function main() {
3115
3402
  const argv = process.argv.slice(2);
3116
3403
  const args = parseArgs2(argv);
3117
3404
  let settings;
3405
+ let enabled;
3118
3406
  try {
3119
3407
  const loaded = await loadConfig(args.configPath);
3120
3408
  settings = loaded.settings;
3409
+ enabled = loaded.raw.enabled;
3121
3410
  } catch {
3122
3411
  }
3123
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
+ }
3124
3425
  switch (args.command) {
3125
3426
  case "help":
3126
3427
  printHelp();
@@ -3155,6 +3456,14 @@ async function main() {
3155
3456
  configPath: args.configPath
3156
3457
  });
3157
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;
3158
3467
  case "init":
3159
3468
  if (args.baseUrl || args.org) {
3160
3469
  await initCommand({
@@ -3208,6 +3517,22 @@ async function main() {
3208
3517
  }
3209
3518
  break;
3210
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;
3211
3536
  }
3212
3537
  }
3213
3538
  process.on("SIGINT", () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcp-s/cli",
3
- "version": "0.0.10",
3
+ "version": "0.0.11",
4
4
  "description": "A lightweight CLI for connecting AI agents to the Webrix MCP Gateway",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",