@ai-ecoverse/mcpcat 0.14.0 → 0.14.2
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/THIRD_PARTY_NOTICES +77 -1
- package/dist/host/mcpcat.mjs +361 -211
- package/dist/kernel/mcpcat.mjs +348 -211
- package/package.json +2 -2
package/dist/host/mcpcat.mjs
CHANGED
|
@@ -49,6 +49,101 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
49
49
|
mod
|
|
50
50
|
));
|
|
51
51
|
|
|
52
|
+
// src/config/lock.ts
|
|
53
|
+
var lock_exports = {};
|
|
54
|
+
__export(lock_exports, {
|
|
55
|
+
acquireLock: () => acquireLock
|
|
56
|
+
});
|
|
57
|
+
function isEexist(err) {
|
|
58
|
+
if (err instanceof Error && "code" in err)
|
|
59
|
+
return err.code === "EEXIST";
|
|
60
|
+
if (err instanceof Error) return err.message.includes("EEXIST");
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
async function removeStaleLockDir(fs, lockPath) {
|
|
64
|
+
try {
|
|
65
|
+
const s = await fs.stat(lockPath);
|
|
66
|
+
if (Date.now() - s.mtimeMs > LOCK_STALE_MS) {
|
|
67
|
+
try {
|
|
68
|
+
await fs.rmdir(lockPath);
|
|
69
|
+
} catch {
|
|
70
|
+
}
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
} catch {
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
async function removeStaleLockFile(fs, lockPath) {
|
|
78
|
+
try {
|
|
79
|
+
const s = await fs.stat(lockPath);
|
|
80
|
+
if (Date.now() - s.mtimeMs > LOCK_STALE_MS) {
|
|
81
|
+
try {
|
|
82
|
+
await fs.unlink(lockPath);
|
|
83
|
+
} catch {
|
|
84
|
+
}
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
} catch {
|
|
88
|
+
}
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
async function acquireLock(fs, configPath) {
|
|
92
|
+
const useFile = typeof fs.createExclusive === "function";
|
|
93
|
+
const lockPath = `${configPath}.lock`;
|
|
94
|
+
const start = Date.now();
|
|
95
|
+
const parentDir = lockPath.slice(0, lockPath.lastIndexOf("/"));
|
|
96
|
+
if (parentDir) {
|
|
97
|
+
try {
|
|
98
|
+
await fs.mkdir(parentDir);
|
|
99
|
+
} catch {
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
while (true) {
|
|
103
|
+
try {
|
|
104
|
+
if (useFile) {
|
|
105
|
+
await fs.createExclusive(lockPath);
|
|
106
|
+
} else {
|
|
107
|
+
await fs.mkdirExclusive(lockPath);
|
|
108
|
+
}
|
|
109
|
+
break;
|
|
110
|
+
} catch (err) {
|
|
111
|
+
if (!isEexist(err)) throw err;
|
|
112
|
+
if (useFile) {
|
|
113
|
+
await removeStaleLockFile(fs, lockPath);
|
|
114
|
+
} else {
|
|
115
|
+
await removeStaleLockDir(fs, lockPath);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (Date.now() - start > LOCK_MAX_WAIT_MS) {
|
|
119
|
+
throw new Error(`mcpcat: could not acquire lock ${lockPath} within ${LOCK_MAX_WAIT_MS}ms`);
|
|
120
|
+
}
|
|
121
|
+
await new Promise((r) => setTimeout(r, LOCK_POLL_MS));
|
|
122
|
+
}
|
|
123
|
+
let released = false;
|
|
124
|
+
return async () => {
|
|
125
|
+
if (released) return;
|
|
126
|
+
released = true;
|
|
127
|
+
try {
|
|
128
|
+
if (useFile && fs.unlink) {
|
|
129
|
+
await fs.unlink(lockPath);
|
|
130
|
+
} else {
|
|
131
|
+
await fs.rmdir(lockPath);
|
|
132
|
+
}
|
|
133
|
+
} catch {
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
var LOCK_STALE_MS, LOCK_POLL_MS, LOCK_MAX_WAIT_MS;
|
|
138
|
+
var init_lock = __esm({
|
|
139
|
+
"src/config/lock.ts"() {
|
|
140
|
+
"use strict";
|
|
141
|
+
LOCK_STALE_MS = 1e4;
|
|
142
|
+
LOCK_POLL_MS = 50;
|
|
143
|
+
LOCK_MAX_WAIT_MS = 5e3;
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
52
147
|
// node_modules/isexe/windows.js
|
|
53
148
|
var require_windows = __commonJS({
|
|
54
149
|
"node_modules/isexe/windows.js"(exports, module) {
|
|
@@ -6345,7 +6440,7 @@ var McpOAuthProvider = class {
|
|
|
6345
6440
|
};
|
|
6346
6441
|
|
|
6347
6442
|
// src/auth/jerk-token-source.ts
|
|
6348
|
-
var MIN_VERSION = [0,
|
|
6443
|
+
var MIN_VERSION = [0, 14, 1];
|
|
6349
6444
|
var VERSION_TIMEOUT_MS = 2e3;
|
|
6350
6445
|
var cachedAvailable;
|
|
6351
6446
|
function parseVersion(raw) {
|
|
@@ -6471,6 +6566,192 @@ var JerkTokenSource = class {
|
|
|
6471
6566
|
}
|
|
6472
6567
|
};
|
|
6473
6568
|
|
|
6569
|
+
// src/auth/pi-store.ts
|
|
6570
|
+
init_lock();
|
|
6571
|
+
|
|
6572
|
+
// src/config/paths.ts
|
|
6573
|
+
function userConfigDir(platform2) {
|
|
6574
|
+
const piDir = platform2.env.PI_CODING_AGENT_DIR;
|
|
6575
|
+
if (piDir) return piDir;
|
|
6576
|
+
const home = platform2.env.HOME ?? platform2.env.USERPROFILE ?? "/";
|
|
6577
|
+
return `${home}/.pi/agent`;
|
|
6578
|
+
}
|
|
6579
|
+
function userConfigPath(platform2) {
|
|
6580
|
+
return `${userConfigDir(platform2)}/mcp.json`;
|
|
6581
|
+
}
|
|
6582
|
+
function projectConfigPath(platform2) {
|
|
6583
|
+
return `${platform2.cwd}/.pi/mcp.json`;
|
|
6584
|
+
}
|
|
6585
|
+
function stateDir(platform2) {
|
|
6586
|
+
if (platform2.env.XDG_STATE_HOME) return `${platform2.env.XDG_STATE_HOME}/mcpcat`;
|
|
6587
|
+
const home = platform2.env.HOME ?? platform2.env.USERPROFILE ?? "/";
|
|
6588
|
+
if (platform2.env.LOCALAPPDATA) return `${platform2.env.LOCALAPPDATA}\\mcpcat\\state`;
|
|
6589
|
+
if (platform2.env.SLICC_KERNEL) return `${home}/.local/state/mcpcat`;
|
|
6590
|
+
return `${home}/Library/Application Support/mcpcat`;
|
|
6591
|
+
}
|
|
6592
|
+
|
|
6593
|
+
// src/auth/token-source.ts
|
|
6594
|
+
function mcpNamespace(server) {
|
|
6595
|
+
return `mcp__${server.replace(/-/g, "_")}`;
|
|
6596
|
+
}
|
|
6597
|
+
function storeKey(name, serverUrl) {
|
|
6598
|
+
const ns = mcpNamespace(name);
|
|
6599
|
+
const url = String(new URL(serverUrl));
|
|
6600
|
+
return `${ns}|${url}`;
|
|
6601
|
+
}
|
|
6602
|
+
function isKernel(platform2) {
|
|
6603
|
+
return platform2.kind === "kernel";
|
|
6604
|
+
}
|
|
6605
|
+
|
|
6606
|
+
// src/auth/pi-store.ts
|
|
6607
|
+
var AUTH_FILE = "mcp-auth.json";
|
|
6608
|
+
var FILE_MODE = 384;
|
|
6609
|
+
var DIR_MODE = 448;
|
|
6610
|
+
function parseStates(raw) {
|
|
6611
|
+
if (!raw?.trim()) return {};
|
|
6612
|
+
const parsed = JSON.parse(raw);
|
|
6613
|
+
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : {};
|
|
6614
|
+
}
|
|
6615
|
+
function serializeStates(states) {
|
|
6616
|
+
return `${JSON.stringify(states, null, 2)}
|
|
6617
|
+
`;
|
|
6618
|
+
}
|
|
6619
|
+
function legacyKey(serverUrl) {
|
|
6620
|
+
return String(new URL(serverUrl));
|
|
6621
|
+
}
|
|
6622
|
+
var PiFileTokenSource = class {
|
|
6623
|
+
platform;
|
|
6624
|
+
authPath;
|
|
6625
|
+
dirPath;
|
|
6626
|
+
constructor(platform2) {
|
|
6627
|
+
this.platform = platform2;
|
|
6628
|
+
this.dirPath = userConfigDir(platform2);
|
|
6629
|
+
this.authPath = `${this.dirPath}/${AUTH_FILE}`;
|
|
6630
|
+
}
|
|
6631
|
+
get path() {
|
|
6632
|
+
return this.authPath;
|
|
6633
|
+
}
|
|
6634
|
+
async loadWithoutLock(name, serverUrl) {
|
|
6635
|
+
const key = storeKey(name, serverUrl);
|
|
6636
|
+
const legacy = legacyKey(serverUrl);
|
|
6637
|
+
try {
|
|
6638
|
+
const raw = await this.readRaw();
|
|
6639
|
+
const states = parseStates(raw);
|
|
6640
|
+
return states[key] ?? states[legacy];
|
|
6641
|
+
} catch {
|
|
6642
|
+
return void 0;
|
|
6643
|
+
}
|
|
6644
|
+
}
|
|
6645
|
+
async getToken(name, serverUrl) {
|
|
6646
|
+
const state = await this.load(name, serverUrl);
|
|
6647
|
+
if (!state?.tokens?.access_token) return void 0;
|
|
6648
|
+
return {
|
|
6649
|
+
accessToken: state.tokens.access_token,
|
|
6650
|
+
expiresAt: state.tokensExpireAt
|
|
6651
|
+
};
|
|
6652
|
+
}
|
|
6653
|
+
async load(name, serverUrl) {
|
|
6654
|
+
const key = storeKey(name, serverUrl);
|
|
6655
|
+
const legacy = legacyKey(serverUrl);
|
|
6656
|
+
const release = await this.acquireLock();
|
|
6657
|
+
try {
|
|
6658
|
+
const raw = await this.readRaw();
|
|
6659
|
+
const states = parseStates(raw);
|
|
6660
|
+
if (states[key]) return states[key];
|
|
6661
|
+
if (states[legacy]) {
|
|
6662
|
+
states[key] = states[legacy];
|
|
6663
|
+
delete states[legacy];
|
|
6664
|
+
await this.writeStates(states);
|
|
6665
|
+
return states[key];
|
|
6666
|
+
}
|
|
6667
|
+
return void 0;
|
|
6668
|
+
} finally {
|
|
6669
|
+
await release();
|
|
6670
|
+
}
|
|
6671
|
+
}
|
|
6672
|
+
async save(name, serverUrl, state) {
|
|
6673
|
+
const key = storeKey(name, serverUrl);
|
|
6674
|
+
const release = await this.acquireLock();
|
|
6675
|
+
try {
|
|
6676
|
+
const raw = await this.readRaw();
|
|
6677
|
+
const states = parseStates(raw);
|
|
6678
|
+
states[key] = state;
|
|
6679
|
+
await this.writeStates(states);
|
|
6680
|
+
} finally {
|
|
6681
|
+
await release();
|
|
6682
|
+
}
|
|
6683
|
+
}
|
|
6684
|
+
async remove(name, serverUrl) {
|
|
6685
|
+
const key = storeKey(name, serverUrl);
|
|
6686
|
+
const legacy = legacyKey(serverUrl);
|
|
6687
|
+
const release = await this.acquireLock();
|
|
6688
|
+
try {
|
|
6689
|
+
const raw = await this.readRaw();
|
|
6690
|
+
const states = parseStates(raw);
|
|
6691
|
+
const stored = key in states ? key : legacy in states ? legacy : void 0;
|
|
6692
|
+
if (!stored) return false;
|
|
6693
|
+
delete states[stored];
|
|
6694
|
+
await this.writeStates(states);
|
|
6695
|
+
return true;
|
|
6696
|
+
} finally {
|
|
6697
|
+
await release();
|
|
6698
|
+
}
|
|
6699
|
+
}
|
|
6700
|
+
async acquireLock() {
|
|
6701
|
+
await this.ensureDir();
|
|
6702
|
+
return acquireLock(this.platform.fs, this.authPath);
|
|
6703
|
+
}
|
|
6704
|
+
async ensureDir() {
|
|
6705
|
+
const fs = this.platform.fs;
|
|
6706
|
+
try {
|
|
6707
|
+
await fs.mkdir(this.dirPath, { mode: DIR_MODE });
|
|
6708
|
+
} catch {
|
|
6709
|
+
}
|
|
6710
|
+
if (fs.chmod) {
|
|
6711
|
+
try {
|
|
6712
|
+
await fs.chmod(this.dirPath, DIR_MODE);
|
|
6713
|
+
} catch {
|
|
6714
|
+
}
|
|
6715
|
+
const piDir = this.dirPath.slice(0, this.dirPath.lastIndexOf("/"));
|
|
6716
|
+
if (piDir) {
|
|
6717
|
+
try {
|
|
6718
|
+
await fs.chmod(piDir, DIR_MODE);
|
|
6719
|
+
} catch {
|
|
6720
|
+
}
|
|
6721
|
+
}
|
|
6722
|
+
}
|
|
6723
|
+
}
|
|
6724
|
+
async readRaw() {
|
|
6725
|
+
try {
|
|
6726
|
+
const data = await this.platform.fs.readFile(this.authPath);
|
|
6727
|
+
return new TextDecoder().decode(data);
|
|
6728
|
+
} catch {
|
|
6729
|
+
return void 0;
|
|
6730
|
+
}
|
|
6731
|
+
}
|
|
6732
|
+
async writeStates(states) {
|
|
6733
|
+
const fs = this.platform.fs;
|
|
6734
|
+
const content = serializeStates(states);
|
|
6735
|
+
const tmpPath = `${this.authPath}.tmp.${Date.now()}`;
|
|
6736
|
+
try {
|
|
6737
|
+
await fs.writeFile(tmpPath, content, { mode: FILE_MODE });
|
|
6738
|
+
await fs.rename(tmpPath, this.authPath);
|
|
6739
|
+
} catch (renameErr) {
|
|
6740
|
+
try {
|
|
6741
|
+
if (fs.unlink) await fs.unlink(tmpPath);
|
|
6742
|
+
} catch {
|
|
6743
|
+
}
|
|
6744
|
+
throw renameErr;
|
|
6745
|
+
}
|
|
6746
|
+
if (fs.chmod) {
|
|
6747
|
+
try {
|
|
6748
|
+
await fs.chmod(this.authPath, FILE_MODE);
|
|
6749
|
+
} catch {
|
|
6750
|
+
}
|
|
6751
|
+
}
|
|
6752
|
+
}
|
|
6753
|
+
};
|
|
6754
|
+
|
|
6474
6755
|
// src/auth/auth-provider.ts
|
|
6475
6756
|
var CIMD_URL = "https://mcpcat.sliccy.ai/oauth/client.json";
|
|
6476
6757
|
var CLIENT_NAME = "mcpcat";
|
|
@@ -6492,10 +6773,12 @@ var SourceBackedStore = class {
|
|
|
6492
6773
|
source;
|
|
6493
6774
|
name;
|
|
6494
6775
|
serverUrl;
|
|
6495
|
-
|
|
6776
|
+
platform;
|
|
6777
|
+
constructor(source, name, serverUrl, platform2) {
|
|
6496
6778
|
this.source = source;
|
|
6497
6779
|
this.name = name;
|
|
6498
6780
|
this.serverUrl = serverUrl;
|
|
6781
|
+
this.platform = platform2;
|
|
6499
6782
|
}
|
|
6500
6783
|
async load() {
|
|
6501
6784
|
return this.source.load(this.name, this.serverUrl);
|
|
@@ -6503,6 +6786,17 @@ var SourceBackedStore = class {
|
|
|
6503
6786
|
async save(state) {
|
|
6504
6787
|
await this.source.save(this.name, this.serverUrl, state);
|
|
6505
6788
|
}
|
|
6789
|
+
async withRefreshLock(fn) {
|
|
6790
|
+
if (!(this.source instanceof PiFileTokenSource)) return fn();
|
|
6791
|
+
const refreshPath = `${this.source.path}.refresh`;
|
|
6792
|
+
const { acquireLock: acquireLock2 } = await Promise.resolve().then(() => (init_lock(), lock_exports));
|
|
6793
|
+
const release = await acquireLock2(this.platform.fs, refreshPath);
|
|
6794
|
+
try {
|
|
6795
|
+
return await fn();
|
|
6796
|
+
} finally {
|
|
6797
|
+
await release();
|
|
6798
|
+
}
|
|
6799
|
+
}
|
|
6506
6800
|
};
|
|
6507
6801
|
function cimdFn(redirectUrl) {
|
|
6508
6802
|
return (metadata) => {
|
|
@@ -6531,10 +6825,9 @@ function createMcpAuthProvider(options) {
|
|
|
6531
6825
|
function createJerkAuthProvider(options) {
|
|
6532
6826
|
const { name, serverUrl, source } = options;
|
|
6533
6827
|
let currentToken;
|
|
6828
|
+
const _fetched = false;
|
|
6534
6829
|
return {
|
|
6535
6830
|
async token() {
|
|
6536
|
-
const result = await source.getToken(name, serverUrl);
|
|
6537
|
-
currentToken = result?.accessToken;
|
|
6538
6831
|
return currentToken;
|
|
6539
6832
|
},
|
|
6540
6833
|
async onUnauthorized(context) {
|
|
@@ -6565,10 +6858,10 @@ function createJerkAuthProvider(options) {
|
|
|
6565
6858
|
}
|
|
6566
6859
|
function createPiAuthProvider(options) {
|
|
6567
6860
|
const { name, serverUrl, source, oauth, platform: platform2 } = options;
|
|
6568
|
-
const store = new SourceBackedStore(source, name, serverUrl);
|
|
6861
|
+
const store = new SourceBackedStore(source, name, serverUrl, platform2);
|
|
6569
6862
|
let refreshing;
|
|
6570
6863
|
const refresh = async (staleToken) => {
|
|
6571
|
-
refreshing ??= (async () => {
|
|
6864
|
+
refreshing ??= store.withRefreshLock(async () => {
|
|
6572
6865
|
const state = await store.load();
|
|
6573
6866
|
if (state?.tokens?.access_token !== staleToken) return;
|
|
6574
6867
|
if (!state?.tokens?.refresh_token) throw new McpOAuthAuthorizationRequiredError();
|
|
@@ -6591,7 +6884,7 @@ function createPiAuthProvider(options) {
|
|
|
6591
6884
|
fetch: timedFetch(platform2.fetch)
|
|
6592
6885
|
});
|
|
6593
6886
|
if (result === "REDIRECT") throw new McpOAuthAuthorizationRequiredError();
|
|
6594
|
-
})
|
|
6887
|
+
}).finally(() => {
|
|
6595
6888
|
refreshing = void 0;
|
|
6596
6889
|
});
|
|
6597
6890
|
return refreshing;
|
|
@@ -9571,27 +9864,6 @@ async function loadConfig(input) {
|
|
|
9571
9864
|
};
|
|
9572
9865
|
}
|
|
9573
9866
|
|
|
9574
|
-
// src/config/paths.ts
|
|
9575
|
-
function userConfigDir(platform2) {
|
|
9576
|
-
const piDir = platform2.env.PI_CODING_AGENT_DIR;
|
|
9577
|
-
if (piDir) return piDir;
|
|
9578
|
-
const home = platform2.env.HOME ?? platform2.env.USERPROFILE ?? "/";
|
|
9579
|
-
return `${home}/.pi/agent`;
|
|
9580
|
-
}
|
|
9581
|
-
function userConfigPath(platform2) {
|
|
9582
|
-
return `${userConfigDir(platform2)}/mcp.json`;
|
|
9583
|
-
}
|
|
9584
|
-
function projectConfigPath(platform2) {
|
|
9585
|
-
return `${platform2.cwd}/.pi/mcp.json`;
|
|
9586
|
-
}
|
|
9587
|
-
function stateDir(platform2) {
|
|
9588
|
-
if (platform2.env.XDG_STATE_HOME) return `${platform2.env.XDG_STATE_HOME}/mcpcat`;
|
|
9589
|
-
const home = platform2.env.HOME ?? platform2.env.USERPROFILE ?? "/";
|
|
9590
|
-
if (platform2.env.LOCALAPPDATA) return `${platform2.env.LOCALAPPDATA}\\mcpcat\\state`;
|
|
9591
|
-
if (platform2.env.SLICC_KERNEL) return `${home}/.local/state/mcpcat`;
|
|
9592
|
-
return `${home}/Library/Application Support/mcpcat`;
|
|
9593
|
-
}
|
|
9594
|
-
|
|
9595
9867
|
// src/config/index.ts
|
|
9596
9868
|
var MergedConfigSource = class _MergedConfigSource {
|
|
9597
9869
|
entries;
|
|
@@ -9631,65 +9903,8 @@ var MergedConfigSource = class _MergedConfigSource {
|
|
|
9631
9903
|
}
|
|
9632
9904
|
};
|
|
9633
9905
|
|
|
9634
|
-
// src/config/lock.ts
|
|
9635
|
-
var LOCK_STALE_MS = 1e4;
|
|
9636
|
-
var LOCK_POLL_MS = 50;
|
|
9637
|
-
var LOCK_MAX_WAIT_MS = 5e3;
|
|
9638
|
-
function isEexist(err) {
|
|
9639
|
-
if (err instanceof Error && "code" in err)
|
|
9640
|
-
return err.code === "EEXIST";
|
|
9641
|
-
if (err instanceof Error) return err.message.includes("EEXIST");
|
|
9642
|
-
return false;
|
|
9643
|
-
}
|
|
9644
|
-
async function removeStaleLock(fs, lockPath) {
|
|
9645
|
-
try {
|
|
9646
|
-
const s = await fs.stat(lockPath);
|
|
9647
|
-
if (Date.now() - s.mtimeMs > LOCK_STALE_MS) {
|
|
9648
|
-
try {
|
|
9649
|
-
await fs.rmdir(lockPath);
|
|
9650
|
-
} catch {
|
|
9651
|
-
}
|
|
9652
|
-
return true;
|
|
9653
|
-
}
|
|
9654
|
-
} catch {
|
|
9655
|
-
}
|
|
9656
|
-
return false;
|
|
9657
|
-
}
|
|
9658
|
-
async function acquireLock(fs, configPath) {
|
|
9659
|
-
const lockPath = `${configPath}.lock`;
|
|
9660
|
-
const start = Date.now();
|
|
9661
|
-
const parentDir = lockPath.slice(0, lockPath.lastIndexOf("/"));
|
|
9662
|
-
if (parentDir) {
|
|
9663
|
-
try {
|
|
9664
|
-
await fs.mkdir(parentDir);
|
|
9665
|
-
} catch {
|
|
9666
|
-
}
|
|
9667
|
-
}
|
|
9668
|
-
while (true) {
|
|
9669
|
-
try {
|
|
9670
|
-
await fs.mkdirExclusive(lockPath);
|
|
9671
|
-
break;
|
|
9672
|
-
} catch (err) {
|
|
9673
|
-
if (!isEexist(err)) throw err;
|
|
9674
|
-
await removeStaleLock(fs, lockPath);
|
|
9675
|
-
}
|
|
9676
|
-
if (Date.now() - start > LOCK_MAX_WAIT_MS) {
|
|
9677
|
-
throw new Error(`mcpcat: could not acquire lock ${lockPath} within ${LOCK_MAX_WAIT_MS}ms`);
|
|
9678
|
-
}
|
|
9679
|
-
await new Promise((r) => setTimeout(r, LOCK_POLL_MS));
|
|
9680
|
-
}
|
|
9681
|
-
let released = false;
|
|
9682
|
-
return async () => {
|
|
9683
|
-
if (released) return;
|
|
9684
|
-
released = true;
|
|
9685
|
-
try {
|
|
9686
|
-
await fs.rmdir(lockPath);
|
|
9687
|
-
} catch {
|
|
9688
|
-
}
|
|
9689
|
-
};
|
|
9690
|
-
}
|
|
9691
|
-
|
|
9692
9906
|
// src/config/edit.ts
|
|
9907
|
+
init_lock();
|
|
9693
9908
|
function isRecord2(value) {
|
|
9694
9909
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9695
9910
|
}
|
|
@@ -12934,124 +13149,6 @@ async function signIn(options) {
|
|
|
12934
13149
|
}
|
|
12935
13150
|
}
|
|
12936
13151
|
|
|
12937
|
-
// src/auth/token-source.ts
|
|
12938
|
-
function mcpNamespace(server) {
|
|
12939
|
-
return `mcp__${server.replace(/-/g, "_")}`;
|
|
12940
|
-
}
|
|
12941
|
-
function storeKey(name, serverUrl) {
|
|
12942
|
-
const ns = mcpNamespace(name);
|
|
12943
|
-
const url = String(new URL(serverUrl));
|
|
12944
|
-
return `${ns}|${url}`;
|
|
12945
|
-
}
|
|
12946
|
-
function isKernel(platform2) {
|
|
12947
|
-
return platform2.kind === "kernel";
|
|
12948
|
-
}
|
|
12949
|
-
|
|
12950
|
-
// src/auth/pi-store.ts
|
|
12951
|
-
var AUTH_FILE = "mcp-auth.json";
|
|
12952
|
-
var FILE_MODE = 384;
|
|
12953
|
-
function parseStates(raw) {
|
|
12954
|
-
if (!raw?.trim()) return {};
|
|
12955
|
-
const parsed = JSON.parse(raw);
|
|
12956
|
-
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : {};
|
|
12957
|
-
}
|
|
12958
|
-
function serializeStates(states) {
|
|
12959
|
-
return `${JSON.stringify(states, null, 2)}
|
|
12960
|
-
`;
|
|
12961
|
-
}
|
|
12962
|
-
function legacyKey(serverUrl) {
|
|
12963
|
-
return String(new URL(serverUrl));
|
|
12964
|
-
}
|
|
12965
|
-
var PiFileTokenSource = class {
|
|
12966
|
-
platform;
|
|
12967
|
-
authPath;
|
|
12968
|
-
dirPath;
|
|
12969
|
-
constructor(platform2) {
|
|
12970
|
-
this.platform = platform2;
|
|
12971
|
-
this.dirPath = userConfigDir(platform2);
|
|
12972
|
-
this.authPath = `${this.dirPath}/${AUTH_FILE}`;
|
|
12973
|
-
}
|
|
12974
|
-
get path() {
|
|
12975
|
-
return this.authPath;
|
|
12976
|
-
}
|
|
12977
|
-
async getToken(name, serverUrl) {
|
|
12978
|
-
const state = await this.load(name, serverUrl);
|
|
12979
|
-
if (!state?.tokens?.access_token) return void 0;
|
|
12980
|
-
return {
|
|
12981
|
-
accessToken: state.tokens.access_token,
|
|
12982
|
-
expiresAt: state.tokensExpireAt
|
|
12983
|
-
};
|
|
12984
|
-
}
|
|
12985
|
-
async load(name, serverUrl) {
|
|
12986
|
-
const key = storeKey(name, serverUrl);
|
|
12987
|
-
const legacy = legacyKey(serverUrl);
|
|
12988
|
-
const release = await this.acquireLock();
|
|
12989
|
-
try {
|
|
12990
|
-
const raw = await this.readRaw();
|
|
12991
|
-
const states = parseStates(raw);
|
|
12992
|
-
if (states[key]) return states[key];
|
|
12993
|
-
if (states[legacy]) {
|
|
12994
|
-
states[key] = states[legacy];
|
|
12995
|
-
delete states[legacy];
|
|
12996
|
-
await this.writeStates(states);
|
|
12997
|
-
return states[key];
|
|
12998
|
-
}
|
|
12999
|
-
return void 0;
|
|
13000
|
-
} finally {
|
|
13001
|
-
await release();
|
|
13002
|
-
}
|
|
13003
|
-
}
|
|
13004
|
-
async save(name, serverUrl, state) {
|
|
13005
|
-
const key = storeKey(name, serverUrl);
|
|
13006
|
-
const release = await this.acquireLock();
|
|
13007
|
-
try {
|
|
13008
|
-
const raw = await this.readRaw();
|
|
13009
|
-
const states = parseStates(raw);
|
|
13010
|
-
states[key] = state;
|
|
13011
|
-
await this.writeStates(states);
|
|
13012
|
-
} finally {
|
|
13013
|
-
await release();
|
|
13014
|
-
}
|
|
13015
|
-
}
|
|
13016
|
-
async remove(name, serverUrl) {
|
|
13017
|
-
const key = storeKey(name, serverUrl);
|
|
13018
|
-
const legacy = legacyKey(serverUrl);
|
|
13019
|
-
const release = await this.acquireLock();
|
|
13020
|
-
try {
|
|
13021
|
-
const raw = await this.readRaw();
|
|
13022
|
-
const states = parseStates(raw);
|
|
13023
|
-
const stored = key in states ? key : legacy in states ? legacy : void 0;
|
|
13024
|
-
if (!stored) return false;
|
|
13025
|
-
delete states[stored];
|
|
13026
|
-
await this.writeStates(states);
|
|
13027
|
-
return true;
|
|
13028
|
-
} finally {
|
|
13029
|
-
await release();
|
|
13030
|
-
}
|
|
13031
|
-
}
|
|
13032
|
-
async acquireLock() {
|
|
13033
|
-
await this.ensureDir();
|
|
13034
|
-
return acquireLock(this.platform.fs, this.authPath);
|
|
13035
|
-
}
|
|
13036
|
-
async ensureDir() {
|
|
13037
|
-
try {
|
|
13038
|
-
await this.platform.fs.mkdir(this.dirPath);
|
|
13039
|
-
} catch {
|
|
13040
|
-
}
|
|
13041
|
-
}
|
|
13042
|
-
async readRaw() {
|
|
13043
|
-
try {
|
|
13044
|
-
const data = await this.platform.fs.readFile(this.authPath);
|
|
13045
|
-
return new TextDecoder().decode(data);
|
|
13046
|
-
} catch {
|
|
13047
|
-
return void 0;
|
|
13048
|
-
}
|
|
13049
|
-
}
|
|
13050
|
-
async writeStates(states) {
|
|
13051
|
-
await this.platform.fs.writeFile(this.authPath, serializeStates(states), { mode: FILE_MODE });
|
|
13052
|
-
}
|
|
13053
|
-
};
|
|
13054
|
-
|
|
13055
13152
|
// src/cli/auth-verbs.ts
|
|
13056
13153
|
var resolvedSource;
|
|
13057
13154
|
async function createTokenSource(platform2) {
|
|
@@ -14745,6 +14842,17 @@ async function runCall(platform2, conn, toolName, dataArg, toolArgs, opts) {
|
|
|
14745
14842
|
return EXIT_USAGE;
|
|
14746
14843
|
}
|
|
14747
14844
|
fin = mergeArgs(base, c.value);
|
|
14845
|
+
} else if (!dataArg && !opts.noValidate) {
|
|
14846
|
+
const tools = await conn.listTools();
|
|
14847
|
+
const tool = tools.find((t) => t.name === toolName);
|
|
14848
|
+
const schema = tool?.inputSchema;
|
|
14849
|
+
const required = Array.isArray(schema?.required) ? schema.required : [];
|
|
14850
|
+
for (const r of required) {
|
|
14851
|
+
if (!Object.hasOwn(base, r)) {
|
|
14852
|
+
await writeErr(platform2, opts.json ?? false, "usage", `missing required flag --${r}`);
|
|
14853
|
+
return EXIT_USAGE;
|
|
14854
|
+
}
|
|
14855
|
+
}
|
|
14748
14856
|
}
|
|
14749
14857
|
return renderCallResult(
|
|
14750
14858
|
platform2,
|
|
@@ -14962,7 +15070,10 @@ async function probeServer(_name, config, platform2) {
|
|
|
14962
15070
|
const opts = { version: "probe" };
|
|
14963
15071
|
if ("url" in config && config.url) {
|
|
14964
15072
|
opts.url = config.url;
|
|
14965
|
-
if ("headers" in config)
|
|
15073
|
+
if ("headers" in config) {
|
|
15074
|
+
const expanded = expandHeaders(config.headers, platform2.env);
|
|
15075
|
+
if (expanded) opts.headers = expanded;
|
|
15076
|
+
}
|
|
14966
15077
|
} else if ("command" in config && config.command) {
|
|
14967
15078
|
opts.command = config.command;
|
|
14968
15079
|
if ("args" in config) opts.args = config.args;
|
|
@@ -15324,11 +15435,25 @@ function classifyError(err) {
|
|
|
15324
15435
|
}
|
|
15325
15436
|
async function resolveAuthProvider(platform2, hasAuthHeader, url, target, config) {
|
|
15326
15437
|
if (hasAuthHeader || !url) return void 0;
|
|
15327
|
-
const
|
|
15438
|
+
const piSource = new PiFileTokenSource(platform2);
|
|
15328
15439
|
const entry = config.entry(target);
|
|
15329
15440
|
const oauth = entry && "url" in entry.config ? entry.config.oauth : void 0;
|
|
15330
15441
|
const name = entry ? target : `url:${new URL(url).origin}${new URL(url).pathname}`;
|
|
15331
|
-
|
|
15442
|
+
const provider = createMcpAuthProvider({
|
|
15443
|
+
name,
|
|
15444
|
+
serverUrl: url,
|
|
15445
|
+
source: piSource,
|
|
15446
|
+
oauth,
|
|
15447
|
+
platform: platform2
|
|
15448
|
+
});
|
|
15449
|
+
const credentialSecrets = [];
|
|
15450
|
+
const state = await piSource.loadWithoutLock(name, url);
|
|
15451
|
+
if (state?.tokens?.access_token) credentialSecrets.push(state.tokens.access_token);
|
|
15452
|
+
if (state?.tokens?.refresh_token) credentialSecrets.push(state.tokens.refresh_token);
|
|
15453
|
+
if (state?.clientInformation && "client_secret" in state.clientInformation && state.clientInformation.client_secret) {
|
|
15454
|
+
credentialSecrets.push(state.clientInformation.client_secret);
|
|
15455
|
+
}
|
|
15456
|
+
return { provider, credentialSecrets };
|
|
15332
15457
|
}
|
|
15333
15458
|
function classifyConnectionError(err, target, interrupted) {
|
|
15334
15459
|
if (err instanceof McpAuthError || err instanceof AuthStepUpError || err instanceof JerkSignInRequiredError) {
|
|
@@ -15374,7 +15499,7 @@ async function handleInputRequired(platform2, conn, err, respondData, json) {
|
|
|
15374
15499
|
`);
|
|
15375
15500
|
return EXIT_INPUT_REQUIRED;
|
|
15376
15501
|
}
|
|
15377
|
-
const isTty = platform2.isatty(0);
|
|
15502
|
+
const isTty = platform2.isatty(0) && platform2.isatty(2);
|
|
15378
15503
|
const elicitResult = await handleElicitation(platform2, inputReq, isTty, respondData);
|
|
15379
15504
|
if ("exitCode" in elicitResult) {
|
|
15380
15505
|
await platform2.write(2, `${err.requestJson}
|
|
@@ -15467,13 +15592,20 @@ async function runClientVerb(platform2, version, parsed) {
|
|
|
15467
15592
|
};
|
|
15468
15593
|
const mergedHeaders = { ...configHeaders, ...expanded };
|
|
15469
15594
|
const hasAuthHeader = "Authorization" in mergedHeaders;
|
|
15470
|
-
const
|
|
15595
|
+
const authResolved = await resolveAuthProvider(
|
|
15471
15596
|
platform2,
|
|
15472
15597
|
hasAuthHeader,
|
|
15473
15598
|
resolved.url,
|
|
15474
15599
|
target,
|
|
15475
15600
|
config
|
|
15476
15601
|
);
|
|
15602
|
+
const authProvider = authResolved?.provider;
|
|
15603
|
+
if (authResolved?.credentialSecrets) {
|
|
15604
|
+
for (const s of authResolved.credentialSecrets) {
|
|
15605
|
+
allSecrets.add(s);
|
|
15606
|
+
verbose.secrets.add(s);
|
|
15607
|
+
}
|
|
15608
|
+
}
|
|
15477
15609
|
const roots = buildRoots(parsed.roots, !!resolved.command, platform2.cwd);
|
|
15478
15610
|
let respondData;
|
|
15479
15611
|
if (parsed.respondArg) {
|
|
@@ -15570,7 +15702,18 @@ function isSpawnNotFound(err) {
|
|
|
15570
15702
|
// src/platform/host.ts
|
|
15571
15703
|
import { spawn as cpSpawn } from "node:child_process";
|
|
15572
15704
|
import { constants } from "node:fs";
|
|
15573
|
-
import {
|
|
15705
|
+
import {
|
|
15706
|
+
access,
|
|
15707
|
+
chmod,
|
|
15708
|
+
mkdir,
|
|
15709
|
+
open,
|
|
15710
|
+
readFile as readFile3,
|
|
15711
|
+
rename,
|
|
15712
|
+
rmdir,
|
|
15713
|
+
stat,
|
|
15714
|
+
unlink,
|
|
15715
|
+
writeFile
|
|
15716
|
+
} from "node:fs/promises";
|
|
15574
15717
|
import { createServer as createServer2 } from "node:net";
|
|
15575
15718
|
import { Readable, Writable } from "node:stream";
|
|
15576
15719
|
import * as tty from "node:tty";
|
|
@@ -15672,6 +15815,13 @@ var hostFs = {
|
|
|
15672
15815
|
},
|
|
15673
15816
|
async unlink(path) {
|
|
15674
15817
|
await unlink(path);
|
|
15818
|
+
},
|
|
15819
|
+
async createExclusive(path) {
|
|
15820
|
+
const fh = await open(path, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY);
|
|
15821
|
+
await fh.close();
|
|
15822
|
+
},
|
|
15823
|
+
async chmod(path, mode) {
|
|
15824
|
+
await chmod(path, mode);
|
|
15675
15825
|
}
|
|
15676
15826
|
};
|
|
15677
15827
|
function createStdinStream() {
|
|
@@ -15792,5 +15942,5 @@ try {
|
|
|
15792
15942
|
});
|
|
15793
15943
|
} catch {
|
|
15794
15944
|
}
|
|
15795
|
-
var code = await run(platform, "0.14.
|
|
15945
|
+
var code = await run(platform, "0.14.2", args);
|
|
15796
15946
|
process.exit(code);
|