@ai-ecoverse/mcpcat 0.14.4 → 0.14.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -22,7 +22,7 @@ Or via npm:
22
22
  npm install -g @ai-ecoverse/mcpcat
23
23
  ```
24
24
 
25
- mcpcat runs natively on macOS, Linux and Windows (Node ≥ 24), and inside Sliccy Seven as a kernel program, with the same flags, the same output and the same config file in both places. Orphan-free shutdown of stdio server trees in the kernel needs slicc-kernel ≥ 1.74.0; on older kernels only the direct child is signalled.
25
+ mcpcat runs natively on macOS, Linux and Windows (Node ≥ 24), and inside Sliccy Seven as a kernel program, with the same flags, the same output and the same config file in both places. Orphan-free shutdown of stdio server trees in the kernel needs slicc-kernel ≥ 1.74.0; on older kernels only the direct child is signalled. When the kernel sends SIGKILL to mcpcat's process group, no handler can run and the server tree survives; a kernel "parent death signal" spawn option (like Linux `PR_SET_PDEATHSIG`) would cover that case.
26
26
 
27
27
  ## Quick start
28
28
 
@@ -52,7 +52,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
52
52
  // src/config/lock.ts
53
53
  var lock_exports = {};
54
54
  __export(lock_exports, {
55
- acquireLock: () => acquireLock
55
+ acquireLock: () => acquireLock,
56
+ releaseAllLocks: () => releaseAllLocks,
57
+ releaseAllLocksSync: () => releaseAllLocksSync
56
58
  });
57
59
  function isEexist(err) {
58
60
  if (err instanceof Error && "code" in err)
@@ -88,6 +90,35 @@ async function removeStaleLockFile(fs, lockPath) {
88
90
  }
89
91
  return false;
90
92
  }
93
+ function releaseAllLocksSync() {
94
+ for (const lock of heldLocks) {
95
+ try {
96
+ if (lock.useFile && lock.fs.unlink) {
97
+ void lock.fs.unlink(lock.path).catch(() => {
98
+ });
99
+ } else {
100
+ void lock.fs.rmdir(lock.path).catch(() => {
101
+ });
102
+ }
103
+ } catch {
104
+ }
105
+ }
106
+ heldLocks.clear();
107
+ }
108
+ async function releaseAllLocks() {
109
+ const locks = [...heldLocks];
110
+ heldLocks.clear();
111
+ for (const lock of locks) {
112
+ try {
113
+ if (lock.useFile && lock.fs.unlink) {
114
+ await lock.fs.unlink(lock.path);
115
+ } else {
116
+ await lock.fs.rmdir(lock.path);
117
+ }
118
+ } catch {
119
+ }
120
+ }
121
+ }
91
122
  async function acquireLock(fs, configPath) {
92
123
  const useFile = typeof fs.createExclusive === "function";
93
124
  const lockPath = `${configPath}.lock`;
@@ -120,10 +151,13 @@ async function acquireLock(fs, configPath) {
120
151
  }
121
152
  await new Promise((r) => setTimeout(r, LOCK_POLL_MS));
122
153
  }
154
+ const entry = { path: lockPath, useFile, fs };
155
+ heldLocks.add(entry);
123
156
  let released = false;
124
157
  return async () => {
125
158
  if (released) return;
126
159
  released = true;
160
+ heldLocks.delete(entry);
127
161
  try {
128
162
  if (useFile && fs.unlink) {
129
163
  await fs.unlink(lockPath);
@@ -134,13 +168,14 @@ async function acquireLock(fs, configPath) {
134
168
  }
135
169
  };
136
170
  }
137
- var LOCK_STALE_MS, LOCK_POLL_MS, LOCK_MAX_WAIT_MS;
171
+ var LOCK_STALE_MS, LOCK_POLL_MS, LOCK_MAX_WAIT_MS, heldLocks;
138
172
  var init_lock = __esm({
139
173
  "src/config/lock.ts"() {
140
174
  "use strict";
141
175
  LOCK_STALE_MS = 1e4;
142
176
  LOCK_POLL_MS = 50;
143
177
  LOCK_MAX_WAIT_MS = 5e3;
178
+ heldLocks = /* @__PURE__ */ new Set();
144
179
  }
145
180
  });
146
181
 
@@ -6825,7 +6860,9 @@ function createMcpAuthProvider(options) {
6825
6860
  function createJerkAuthProvider(options) {
6826
6861
  const { name, serverUrl, source } = options;
6827
6862
  let currentToken;
6828
- const _fetched = false;
6863
+ function registerCredential(token) {
6864
+ if (token && options.onCredentialObtained) options.onCredentialObtained(token);
6865
+ }
6829
6866
  return {
6830
6867
  async token() {
6831
6868
  return currentToken;
@@ -6837,6 +6874,7 @@ function createJerkAuthProvider(options) {
6837
6874
  const result2 = await source.getToken(name, serverUrl, challenge.scope);
6838
6875
  if (result2) {
6839
6876
  currentToken = result2.accessToken;
6877
+ registerCredential(currentToken);
6840
6878
  return;
6841
6879
  }
6842
6880
  } catch (err) {
@@ -6850,6 +6888,7 @@ function createJerkAuthProvider(options) {
6850
6888
  const result = await source.getToken(name, serverUrl);
6851
6889
  if (result) {
6852
6890
  currentToken = result.accessToken;
6891
+ registerCredential(currentToken);
6853
6892
  return;
6854
6893
  }
6855
6894
  throw new McpOAuthAuthorizationRequiredError();
@@ -6860,6 +6899,9 @@ function createPiAuthProvider(options) {
6860
6899
  const { name, serverUrl, source, oauth, platform: platform2 } = options;
6861
6900
  const store = new SourceBackedStore(source, name, serverUrl, platform2);
6862
6901
  let refreshing;
6902
+ function registerCredential(token) {
6903
+ if (token && options.onCredentialObtained) options.onCredentialObtained(token);
6904
+ }
6863
6905
  const refresh = async (staleToken) => {
6864
6906
  refreshing ??= store.withRefreshLock(async () => {
6865
6907
  const state = await store.load();
@@ -6889,15 +6931,27 @@ function createPiAuthProvider(options) {
6889
6931
  });
6890
6932
  return refreshing;
6891
6933
  };
6934
+ let cachedToken;
6935
+ let tokenLoaded = false;
6892
6936
  return {
6893
6937
  async token() {
6894
6938
  await refreshing?.catch(() => void 0);
6939
+ if (tokenLoaded) return cachedToken;
6895
6940
  const state = await store.load();
6896
- const token = state?.tokens?.access_token;
6941
+ cachedToken = state?.tokens?.access_token;
6942
+ registerCredential(cachedToken);
6943
+ if (state?.tokens?.refresh_token) registerCredential(state.tokens.refresh_token);
6897
6944
  const expired = state?.tokensExpireAt !== void 0 && state.tokensExpireAt - REFRESH_SKEW_MS <= Date.now();
6898
- if (!expired || !state?.tokens?.refresh_token) return token;
6899
- await refresh(token).catch(() => void 0);
6900
- return (await store.load())?.tokens?.access_token;
6945
+ if (expired && state?.tokens?.refresh_token) {
6946
+ await refresh(cachedToken).catch(() => void 0);
6947
+ const refreshedState = await store.load();
6948
+ cachedToken = refreshedState?.tokens?.access_token;
6949
+ registerCredential(cachedToken);
6950
+ if (refreshedState?.tokens?.refresh_token)
6951
+ registerCredential(refreshedState.tokens.refresh_token);
6952
+ }
6953
+ tokenLoaded = true;
6954
+ return cachedToken;
6901
6955
  },
6902
6956
  async onUnauthorized(context) {
6903
6957
  const challenge = parseWwwAuthenticate(context.response.headers.get("www-authenticate"));
@@ -6905,6 +6959,11 @@ function createPiAuthProvider(options) {
6905
6959
  throw new AuthStepUpError(challenge.scope, options.name);
6906
6960
  }
6907
6961
  await refresh(context.token);
6962
+ const state = await store.load();
6963
+ cachedToken = state?.tokens?.access_token;
6964
+ tokenLoaded = true;
6965
+ registerCredential(cachedToken);
6966
+ if (state?.tokens?.refresh_token) registerCredential(state.tokens.refresh_token);
6908
6967
  }
6909
6968
  };
6910
6969
  }
@@ -9972,6 +10031,9 @@ var MergedConfigSource = class _MergedConfigSource {
9972
10031
  }
9973
10032
  };
9974
10033
 
10034
+ // src/cli/main.ts
10035
+ init_lock();
10036
+
9975
10037
  // src/config/edit.ts
9976
10038
  init_lock();
9977
10039
  function isRecord2(value) {
@@ -15343,6 +15405,8 @@ async function dispatchMultiTarget(platform2, parsed, version) {
15343
15405
  await Promise.race([killAllStdio(), new Promise((r) => setTimeout(r, 3e3))]);
15344
15406
  } catch {
15345
15407
  }
15408
+ await releaseAllLocks().catch(() => {
15409
+ });
15346
15410
  platform2.exit(exitCode);
15347
15411
  }
15348
15412
  platform2.onSignal?.("SIGTERM", () => void killTreeAndExit(143));
@@ -15393,6 +15457,8 @@ async function dispatchMultiTarget(platform2, parsed, version) {
15393
15457
  return 5;
15394
15458
  } finally {
15395
15459
  await cleanup();
15460
+ await killAllStdio().catch(() => {
15461
+ });
15396
15462
  }
15397
15463
  }
15398
15464
  if (parsed.verb === "grep") {
@@ -15417,6 +15483,8 @@ async function dispatchMultiTarget(platform2, parsed, version) {
15417
15483
  });
15418
15484
  } finally {
15419
15485
  await cleanup();
15486
+ await killAllStdio().catch(() => {
15487
+ });
15420
15488
  }
15421
15489
  }
15422
15490
  if (parsed.verb === "describe" && parsed.showTs) {
@@ -15433,6 +15501,8 @@ async function dispatchMultiTarget(platform2, parsed, version) {
15433
15501
  return await runDescribeTs(platform2, targets, parsed.tsBudget);
15434
15502
  } finally {
15435
15503
  await cleanup();
15504
+ await killAllStdio().catch(() => {
15505
+ });
15436
15506
  }
15437
15507
  }
15438
15508
  return 2;
@@ -15569,25 +15639,28 @@ function classifyError(err) {
15569
15639
  }
15570
15640
  return { code: EXIT_RPC_ERROR, kind: "rpc_error", msg };
15571
15641
  }
15572
- async function resolveAuthProvider(platform2, hasAuthHeader, url, target, config) {
15642
+ async function resolveAuthProvider(platform2, hasAuthHeader, url, target, config, onCredentialObtained) {
15573
15643
  if (hasAuthHeader || !url) return void 0;
15574
- const piSource = new PiFileTokenSource(platform2);
15644
+ const source = await createTokenSource(platform2);
15575
15645
  const entry = config.entry(target);
15576
15646
  const oauth = entry && "url" in entry.config ? entry.config.oauth : void 0;
15577
15647
  const name = entry ? target : `url:${new URL(url).origin}${new URL(url).pathname}`;
15578
15648
  const provider = createMcpAuthProvider({
15579
15649
  name,
15580
15650
  serverUrl: url,
15581
- source: piSource,
15651
+ source,
15582
15652
  oauth,
15583
- platform: platform2
15653
+ platform: platform2,
15654
+ onCredentialObtained
15584
15655
  });
15585
15656
  const credentialSecrets = [];
15586
- const state = await piSource.loadWithoutLock(name, url);
15587
- if (state?.tokens?.access_token) credentialSecrets.push(state.tokens.access_token);
15588
- if (state?.tokens?.refresh_token) credentialSecrets.push(state.tokens.refresh_token);
15589
- if (state?.clientInformation && "client_secret" in state.clientInformation && state.clientInformation.client_secret) {
15590
- credentialSecrets.push(state.clientInformation.client_secret);
15657
+ if (source instanceof PiFileTokenSource) {
15658
+ const state = await source.loadWithoutLock(name, url);
15659
+ if (state?.tokens?.access_token) credentialSecrets.push(state.tokens.access_token);
15660
+ if (state?.tokens?.refresh_token) credentialSecrets.push(state.tokens.refresh_token);
15661
+ if (state?.clientInformation && "client_secret" in state.clientInformation && state.clientInformation.client_secret) {
15662
+ credentialSecrets.push(state.clientInformation.client_secret);
15663
+ }
15591
15664
  }
15592
15665
  return { provider, credentialSecrets };
15593
15666
  }
@@ -15685,6 +15758,8 @@ async function runClientVerb(platform2, version, parsed) {
15685
15758
  await Promise.race([killAllStdio(), new Promise((r) => setTimeout(r, 3e3))]);
15686
15759
  } catch {
15687
15760
  }
15761
+ await releaseAllLocks().catch(() => {
15762
+ });
15688
15763
  platform2.exit(exitCode);
15689
15764
  }
15690
15765
  platform2.onSignal?.("SIGINT", () => {
@@ -15737,7 +15812,11 @@ async function runClientVerb(platform2, version, parsed) {
15737
15812
  hasAuthHeader,
15738
15813
  resolved.url,
15739
15814
  target,
15740
- config
15815
+ config,
15816
+ (secret) => {
15817
+ allSecrets.add(secret);
15818
+ verbose.secrets.add(secret);
15819
+ }
15741
15820
  );
15742
15821
  const authProvider = authResolved?.provider;
15743
15822
  if (authResolved?.credentialSecrets) {
@@ -15805,11 +15884,20 @@ async function runClientVerb(platform2, version, parsed) {
15805
15884
  await writeErrRedacted(platform2, parsed.jsonOutput, e.kind, e.msg, redact2);
15806
15885
  return e.code;
15807
15886
  } finally {
15808
- try {
15809
- await conn.close();
15810
- } catch {
15811
- }
15887
+ await closeAndKillStdio(conn);
15888
+ }
15889
+ }
15890
+ async function closeAndKillStdio(conn) {
15891
+ try {
15892
+ await conn.close();
15893
+ } catch {
15812
15894
  }
15895
+ try {
15896
+ await killAllStdio();
15897
+ } catch {
15898
+ }
15899
+ await releaseAllLocks().catch(() => {
15900
+ });
15813
15901
  }
15814
15902
  async function writeErr(p, json, kind, msg) {
15815
15903
  if (json) await renderErrorJson(p, kind, msg);
@@ -16082,5 +16170,5 @@ try {
16082
16170
  });
16083
16171
  } catch {
16084
16172
  }
16085
- var code = await run(platform, "0.14.4", args);
16173
+ var code = await run(platform, "0.14.6", args);
16086
16174
  process.exit(code);
@@ -170,7 +170,9 @@ var init_node_stub = __esm({
170
170
  // src/config/lock.ts
171
171
  var lock_exports = {};
172
172
  __export(lock_exports, {
173
- acquireLock: () => acquireLock
173
+ acquireLock: () => acquireLock,
174
+ releaseAllLocks: () => releaseAllLocks,
175
+ releaseAllLocksSync: () => releaseAllLocksSync
174
176
  });
175
177
  function isEexist(err) {
176
178
  if (err instanceof Error && "code" in err)
@@ -206,6 +208,35 @@ async function removeStaleLockFile(fs, lockPath) {
206
208
  }
207
209
  return false;
208
210
  }
211
+ function releaseAllLocksSync() {
212
+ for (const lock of heldLocks) {
213
+ try {
214
+ if (lock.useFile && lock.fs.unlink) {
215
+ void lock.fs.unlink(lock.path).catch(() => {
216
+ });
217
+ } else {
218
+ void lock.fs.rmdir(lock.path).catch(() => {
219
+ });
220
+ }
221
+ } catch {
222
+ }
223
+ }
224
+ heldLocks.clear();
225
+ }
226
+ async function releaseAllLocks() {
227
+ const locks = [...heldLocks];
228
+ heldLocks.clear();
229
+ for (const lock of locks) {
230
+ try {
231
+ if (lock.useFile && lock.fs.unlink) {
232
+ await lock.fs.unlink(lock.path);
233
+ } else {
234
+ await lock.fs.rmdir(lock.path);
235
+ }
236
+ } catch {
237
+ }
238
+ }
239
+ }
209
240
  async function acquireLock(fs, configPath) {
210
241
  const useFile = typeof fs.createExclusive === "function";
211
242
  const lockPath = `${configPath}.lock`;
@@ -238,10 +269,13 @@ async function acquireLock(fs, configPath) {
238
269
  }
239
270
  await new Promise((r) => setTimeout(r, LOCK_POLL_MS));
240
271
  }
272
+ const entry = { path: lockPath, useFile, fs };
273
+ heldLocks.add(entry);
241
274
  let released = false;
242
275
  return async () => {
243
276
  if (released) return;
244
277
  released = true;
278
+ heldLocks.delete(entry);
245
279
  try {
246
280
  if (useFile && fs.unlink) {
247
281
  await fs.unlink(lockPath);
@@ -252,13 +286,14 @@ async function acquireLock(fs, configPath) {
252
286
  }
253
287
  };
254
288
  }
255
- var LOCK_STALE_MS, LOCK_POLL_MS, LOCK_MAX_WAIT_MS;
289
+ var LOCK_STALE_MS, LOCK_POLL_MS, LOCK_MAX_WAIT_MS, heldLocks;
256
290
  var init_lock = __esm({
257
291
  "src/config/lock.ts"() {
258
292
  "use strict";
259
293
  LOCK_STALE_MS = 1e4;
260
294
  LOCK_POLL_MS = 50;
261
295
  LOCK_MAX_WAIT_MS = 5e3;
296
+ heldLocks = /* @__PURE__ */ new Set();
262
297
  }
263
298
  });
264
299
 
@@ -6446,7 +6481,9 @@ function createMcpAuthProvider(options) {
6446
6481
  function createJerkAuthProvider(options) {
6447
6482
  const { name, serverUrl, source } = options;
6448
6483
  let currentToken;
6449
- const _fetched = false;
6484
+ function registerCredential(token) {
6485
+ if (token && options.onCredentialObtained) options.onCredentialObtained(token);
6486
+ }
6450
6487
  return {
6451
6488
  async token() {
6452
6489
  return currentToken;
@@ -6458,6 +6495,7 @@ function createJerkAuthProvider(options) {
6458
6495
  const result2 = await source.getToken(name, serverUrl, challenge.scope);
6459
6496
  if (result2) {
6460
6497
  currentToken = result2.accessToken;
6498
+ registerCredential(currentToken);
6461
6499
  return;
6462
6500
  }
6463
6501
  } catch (err) {
@@ -6471,6 +6509,7 @@ function createJerkAuthProvider(options) {
6471
6509
  const result = await source.getToken(name, serverUrl);
6472
6510
  if (result) {
6473
6511
  currentToken = result.accessToken;
6512
+ registerCredential(currentToken);
6474
6513
  return;
6475
6514
  }
6476
6515
  throw new McpOAuthAuthorizationRequiredError();
@@ -6481,6 +6520,9 @@ function createPiAuthProvider(options) {
6481
6520
  const { name, serverUrl, source, oauth, platform: platform2 } = options;
6482
6521
  const store = new SourceBackedStore(source, name, serverUrl, platform2);
6483
6522
  let refreshing;
6523
+ function registerCredential(token) {
6524
+ if (token && options.onCredentialObtained) options.onCredentialObtained(token);
6525
+ }
6484
6526
  const refresh = async (staleToken) => {
6485
6527
  refreshing ??= store.withRefreshLock(async () => {
6486
6528
  const state = await store.load();
@@ -6510,15 +6552,27 @@ function createPiAuthProvider(options) {
6510
6552
  });
6511
6553
  return refreshing;
6512
6554
  };
6555
+ let cachedToken;
6556
+ let tokenLoaded = false;
6513
6557
  return {
6514
6558
  async token() {
6515
6559
  await refreshing?.catch(() => void 0);
6560
+ if (tokenLoaded) return cachedToken;
6516
6561
  const state = await store.load();
6517
- const token = state?.tokens?.access_token;
6562
+ cachedToken = state?.tokens?.access_token;
6563
+ registerCredential(cachedToken);
6564
+ if (state?.tokens?.refresh_token) registerCredential(state.tokens.refresh_token);
6518
6565
  const expired = state?.tokensExpireAt !== void 0 && state.tokensExpireAt - REFRESH_SKEW_MS <= Date.now();
6519
- if (!expired || !state?.tokens?.refresh_token) return token;
6520
- await refresh(token).catch(() => void 0);
6521
- return (await store.load())?.tokens?.access_token;
6566
+ if (expired && state?.tokens?.refresh_token) {
6567
+ await refresh(cachedToken).catch(() => void 0);
6568
+ const refreshedState = await store.load();
6569
+ cachedToken = refreshedState?.tokens?.access_token;
6570
+ registerCredential(cachedToken);
6571
+ if (refreshedState?.tokens?.refresh_token)
6572
+ registerCredential(refreshedState.tokens.refresh_token);
6573
+ }
6574
+ tokenLoaded = true;
6575
+ return cachedToken;
6522
6576
  },
6523
6577
  async onUnauthorized(context) {
6524
6578
  const challenge = parseWwwAuthenticate(context.response.headers.get("www-authenticate"));
@@ -6526,6 +6580,11 @@ function createPiAuthProvider(options) {
6526
6580
  throw new AuthStepUpError(challenge.scope, options.name);
6527
6581
  }
6528
6582
  await refresh(context.token);
6583
+ const state = await store.load();
6584
+ cachedToken = state?.tokens?.access_token;
6585
+ tokenLoaded = true;
6586
+ registerCredential(cachedToken);
6587
+ if (state?.tokens?.refresh_token) registerCredential(state.tokens.refresh_token);
6529
6588
  }
6530
6589
  };
6531
6590
  }
@@ -9593,6 +9652,9 @@ var MergedConfigSource = class _MergedConfigSource {
9593
9652
  }
9594
9653
  };
9595
9654
 
9655
+ // src/cli/main.ts
9656
+ init_lock();
9657
+
9596
9658
  // src/config/edit.ts
9597
9659
  init_lock();
9598
9660
  function isRecord2(value) {
@@ -14964,6 +15026,8 @@ async function dispatchMultiTarget(platform2, parsed, version) {
14964
15026
  await Promise.race([killAllStdio(), new Promise((r) => setTimeout(r, 3e3))]);
14965
15027
  } catch {
14966
15028
  }
15029
+ await releaseAllLocks().catch(() => {
15030
+ });
14967
15031
  platform2.exit(exitCode);
14968
15032
  }
14969
15033
  platform2.onSignal?.("SIGTERM", () => void killTreeAndExit(143));
@@ -15014,6 +15078,8 @@ async function dispatchMultiTarget(platform2, parsed, version) {
15014
15078
  return 5;
15015
15079
  } finally {
15016
15080
  await cleanup();
15081
+ await killAllStdio().catch(() => {
15082
+ });
15017
15083
  }
15018
15084
  }
15019
15085
  if (parsed.verb === "grep") {
@@ -15038,6 +15104,8 @@ async function dispatchMultiTarget(platform2, parsed, version) {
15038
15104
  });
15039
15105
  } finally {
15040
15106
  await cleanup();
15107
+ await killAllStdio().catch(() => {
15108
+ });
15041
15109
  }
15042
15110
  }
15043
15111
  if (parsed.verb === "describe" && parsed.showTs) {
@@ -15054,6 +15122,8 @@ async function dispatchMultiTarget(platform2, parsed, version) {
15054
15122
  return await runDescribeTs(platform2, targets, parsed.tsBudget);
15055
15123
  } finally {
15056
15124
  await cleanup();
15125
+ await killAllStdio().catch(() => {
15126
+ });
15057
15127
  }
15058
15128
  }
15059
15129
  return 2;
@@ -15190,25 +15260,28 @@ function classifyError(err) {
15190
15260
  }
15191
15261
  return { code: EXIT_RPC_ERROR, kind: "rpc_error", msg };
15192
15262
  }
15193
- async function resolveAuthProvider(platform2, hasAuthHeader, url, target, config) {
15263
+ async function resolveAuthProvider(platform2, hasAuthHeader, url, target, config, onCredentialObtained) {
15194
15264
  if (hasAuthHeader || !url) return void 0;
15195
- const piSource = new PiFileTokenSource(platform2);
15265
+ const source = await createTokenSource(platform2);
15196
15266
  const entry = config.entry(target);
15197
15267
  const oauth = entry && "url" in entry.config ? entry.config.oauth : void 0;
15198
15268
  const name = entry ? target : `url:${new URL(url).origin}${new URL(url).pathname}`;
15199
15269
  const provider = createMcpAuthProvider({
15200
15270
  name,
15201
15271
  serverUrl: url,
15202
- source: piSource,
15272
+ source,
15203
15273
  oauth,
15204
- platform: platform2
15274
+ platform: platform2,
15275
+ onCredentialObtained
15205
15276
  });
15206
15277
  const credentialSecrets = [];
15207
- const state = await piSource.loadWithoutLock(name, url);
15208
- if (state?.tokens?.access_token) credentialSecrets.push(state.tokens.access_token);
15209
- if (state?.tokens?.refresh_token) credentialSecrets.push(state.tokens.refresh_token);
15210
- if (state?.clientInformation && "client_secret" in state.clientInformation && state.clientInformation.client_secret) {
15211
- credentialSecrets.push(state.clientInformation.client_secret);
15278
+ if (source instanceof PiFileTokenSource) {
15279
+ const state = await source.loadWithoutLock(name, url);
15280
+ if (state?.tokens?.access_token) credentialSecrets.push(state.tokens.access_token);
15281
+ if (state?.tokens?.refresh_token) credentialSecrets.push(state.tokens.refresh_token);
15282
+ if (state?.clientInformation && "client_secret" in state.clientInformation && state.clientInformation.client_secret) {
15283
+ credentialSecrets.push(state.clientInformation.client_secret);
15284
+ }
15212
15285
  }
15213
15286
  return { provider, credentialSecrets };
15214
15287
  }
@@ -15306,6 +15379,8 @@ async function runClientVerb(platform2, version, parsed) {
15306
15379
  await Promise.race([killAllStdio(), new Promise((r) => setTimeout(r, 3e3))]);
15307
15380
  } catch {
15308
15381
  }
15382
+ await releaseAllLocks().catch(() => {
15383
+ });
15309
15384
  platform2.exit(exitCode);
15310
15385
  }
15311
15386
  platform2.onSignal?.("SIGINT", () => {
@@ -15358,7 +15433,11 @@ async function runClientVerb(platform2, version, parsed) {
15358
15433
  hasAuthHeader,
15359
15434
  resolved.url,
15360
15435
  target,
15361
- config
15436
+ config,
15437
+ (secret) => {
15438
+ allSecrets.add(secret);
15439
+ verbose.secrets.add(secret);
15440
+ }
15362
15441
  );
15363
15442
  const authProvider = authResolved?.provider;
15364
15443
  if (authResolved?.credentialSecrets) {
@@ -15426,11 +15505,20 @@ async function runClientVerb(platform2, version, parsed) {
15426
15505
  await writeErrRedacted(platform2, parsed.jsonOutput, e.kind, e.msg, redact2);
15427
15506
  return e.code;
15428
15507
  } finally {
15429
- try {
15430
- await conn.close();
15431
- } catch {
15432
- }
15508
+ await closeAndKillStdio(conn);
15509
+ }
15510
+ }
15511
+ async function closeAndKillStdio(conn) {
15512
+ try {
15513
+ await conn.close();
15514
+ } catch {
15433
15515
  }
15516
+ try {
15517
+ await killAllStdio();
15518
+ } catch {
15519
+ }
15520
+ await releaseAllLocks().catch(() => {
15521
+ });
15434
15522
  }
15435
15523
  async function writeErr(p, json, kind, msg) {
15436
15524
  if (json) await renderErrorJson(p, kind, msg);
@@ -15746,7 +15834,7 @@ async function main(ctx) {
15746
15834
  packageDir: "/node_modules/@ai-ecoverse/mcpcat"
15747
15835
  });
15748
15836
  const args = ctx.argv.slice(1);
15749
- return run(platform2, "0.14.4", args);
15837
+ return run(platform2, "0.14.6", args);
15750
15838
  }
15751
15839
  export {
15752
15840
  main as default
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-ecoverse/mcpcat",
3
- "version": "0.14.4",
3
+ "version": "0.14.6",
4
4
  "description": "A curl for the Model Context Protocol",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",