@ai-ecoverse/mcpcat 0.15.5 → 0.15.7
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/host/mcpcat.mjs +359 -147
- package/dist/kernel/mcpcat.mjs +371 -156
- package/package.json +4 -3
package/dist/kernel/mcpcat.mjs
CHANGED
|
@@ -1475,6 +1475,16 @@ var init_version = __esm({
|
|
|
1475
1475
|
});
|
|
1476
1476
|
|
|
1477
1477
|
// node_modules/quickjs-wasi/dist/index.js
|
|
1478
|
+
var dist_exports = {};
|
|
1479
|
+
__export(dist_exports, {
|
|
1480
|
+
CompileFlags: () => CompileFlags,
|
|
1481
|
+
EvalFlags: () => EvalFlags,
|
|
1482
|
+
Intrinsics: () => Intrinsics,
|
|
1483
|
+
JSException: () => JSException,
|
|
1484
|
+
JSValueHandle: () => JSValueHandle,
|
|
1485
|
+
MAX_STACK_SIZE: () => MAX_STACK_SIZE,
|
|
1486
|
+
QuickJS: () => QuickJS
|
|
1487
|
+
});
|
|
1478
1488
|
function stringKeyNeedsValuePath(key) {
|
|
1479
1489
|
return key.includes("\0") || LONE_SURROGATE_RE.test(key);
|
|
1480
1490
|
}
|
|
@@ -4950,8 +4960,8 @@ function parseCodemodeSource(input) {
|
|
|
4950
4960
|
throw new CodemodeSourceError(`The ${CODEMODE_OPTIONS_PREFIX} line must be the first line of the input; found one on line ${misplaced + 1}`);
|
|
4951
4961
|
}
|
|
4952
4962
|
const newline = input.indexOf("\n");
|
|
4953
|
-
const
|
|
4954
|
-
const trimmed =
|
|
4963
|
+
const firstLine2 = lines[0].replace(/\r$/, "");
|
|
4964
|
+
const trimmed = firstLine2.trimStart();
|
|
4955
4965
|
if (!trimmed.startsWith(CODEMODE_OPTIONS_PREFIX))
|
|
4956
4966
|
return { code: input, options: {} };
|
|
4957
4967
|
const code = newline === -1 ? "" : input.slice(newline);
|
|
@@ -4986,8 +4996,8 @@ SOURCE: /[\s\S]+/
|
|
|
4986
4996
|
});
|
|
4987
4997
|
|
|
4988
4998
|
// node_modules/@earendil-works/pi-codemode/dist/index.js
|
|
4989
|
-
var
|
|
4990
|
-
__export(
|
|
4999
|
+
var dist_exports2 = {};
|
|
5000
|
+
__export(dist_exports2, {
|
|
4991
5001
|
CODEMODE_OPTIONS_PREFIX: () => CODEMODE_OPTIONS_PREFIX,
|
|
4992
5002
|
CODEMODE_SOURCE_GRAMMAR: () => CODEMODE_SOURCE_GRAMMAR,
|
|
4993
5003
|
CodemodeSandbox: () => CodemodeSandbox,
|
|
@@ -7990,8 +8000,9 @@ var McpTimeoutError2 = class extends Error {
|
|
|
7990
8000
|
var McpAuthError = class extends Error {
|
|
7991
8001
|
status;
|
|
7992
8002
|
target;
|
|
7993
|
-
constructor(status, target) {
|
|
7994
|
-
|
|
8003
|
+
constructor(status, target, reason) {
|
|
8004
|
+
const why = reason ? ` (${reason})` : "";
|
|
8005
|
+
super(`HTTP ${status}: authentication required${why}. Run: mcpcat login ${target}`);
|
|
7995
8006
|
this.name = "McpAuthError";
|
|
7996
8007
|
this.status = status;
|
|
7997
8008
|
this.target = target;
|
|
@@ -8009,12 +8020,23 @@ var TransportRefusalError = class extends Error {
|
|
|
8009
8020
|
};
|
|
8010
8021
|
var AuthRetryableError = class extends Error {
|
|
8011
8022
|
response;
|
|
8012
|
-
|
|
8023
|
+
reason;
|
|
8024
|
+
constructor(response, reason) {
|
|
8013
8025
|
super(`HTTP ${response.status}: auth retry`);
|
|
8014
8026
|
this.name = "AuthRetryableError";
|
|
8015
8027
|
this.response = response;
|
|
8028
|
+
this.reason = reason;
|
|
8016
8029
|
}
|
|
8017
8030
|
};
|
|
8031
|
+
var KERNEL_REFUSAL = "nodeTransport refuses ";
|
|
8032
|
+
function firstLine(text) {
|
|
8033
|
+
return text.trim().split("\n")[0].trim().slice(0, 200);
|
|
8034
|
+
}
|
|
8035
|
+
async function authReason(res) {
|
|
8036
|
+
const type = res.headers.get("content-type") ?? "";
|
|
8037
|
+
if (!type.toLowerCase().startsWith("text/plain")) return void 0;
|
|
8038
|
+
return firstLine(await res.text()) || void 0;
|
|
8039
|
+
}
|
|
8018
8040
|
function selectSseFrame(body, targetId) {
|
|
8019
8041
|
const text = new TextDecoder().decode(body);
|
|
8020
8042
|
const blocks = text.replace(/\r\n/g, "\n").split(/\n\n/);
|
|
@@ -8131,7 +8153,8 @@ async function createStatelessConnection(options) {
|
|
|
8131
8153
|
clientInfo = { name: "mcpcat", version: "0.0.0" },
|
|
8132
8154
|
signal: externalSignal,
|
|
8133
8155
|
verbose,
|
|
8134
|
-
authProvider
|
|
8156
|
+
authProvider,
|
|
8157
|
+
transportRefusals
|
|
8135
8158
|
} = options;
|
|
8136
8159
|
let nextId2 = 1;
|
|
8137
8160
|
let negotiatedVersion;
|
|
@@ -8149,18 +8172,14 @@ async function createStatelessConnection(options) {
|
|
|
8149
8172
|
return h;
|
|
8150
8173
|
}
|
|
8151
8174
|
async function handleErrorStatus(res, method) {
|
|
8152
|
-
if (res.status === 403) {
|
|
8153
|
-
const
|
|
8154
|
-
if (!
|
|
8155
|
-
|
|
8156
|
-
if (body && !body.includes("insufficient_scope")) {
|
|
8157
|
-
throw new TransportRefusalError(403, body.split("\n")[0].slice(0, 200));
|
|
8158
|
-
}
|
|
8175
|
+
if (res.status === 401 || res.status === 403) {
|
|
8176
|
+
const reason = await authReason(res);
|
|
8177
|
+
if (transportRefusals && res.status === 403 && !res.headers.has("www-authenticate") && reason?.startsWith(KERNEL_REFUSAL)) {
|
|
8178
|
+
throw new TransportRefusalError(403, reason);
|
|
8159
8179
|
}
|
|
8180
|
+
if (authProvider) throw new AuthRetryableError(res, reason);
|
|
8181
|
+
throw new McpAuthError(res.status, url, reason);
|
|
8160
8182
|
}
|
|
8161
|
-
if ((res.status === 401 || res.status === 403) && authProvider)
|
|
8162
|
-
throw new AuthRetryableError(res);
|
|
8163
|
-
if (res.status === 401 || res.status === 403) throw new McpAuthError(res.status, url);
|
|
8164
8183
|
const text = await res.text();
|
|
8165
8184
|
let rpc;
|
|
8166
8185
|
try {
|
|
@@ -8215,7 +8234,7 @@ async function createStatelessConnection(options) {
|
|
|
8215
8234
|
return frame.result;
|
|
8216
8235
|
}
|
|
8217
8236
|
async function handleAuthError(err, token) {
|
|
8218
|
-
if (!authProvider?.onUnauthorized) throw new McpAuthError(err.response.status, url);
|
|
8237
|
+
if (!authProvider?.onUnauthorized) throw new McpAuthError(err.response.status, url, err.reason);
|
|
8219
8238
|
try {
|
|
8220
8239
|
await authProvider.onUnauthorized({
|
|
8221
8240
|
response: err.response,
|
|
@@ -8225,7 +8244,7 @@ async function createStatelessConnection(options) {
|
|
|
8225
8244
|
});
|
|
8226
8245
|
} catch (authErr) {
|
|
8227
8246
|
if (authErr instanceof AuthStepUpError || authErr instanceof JerkTimeoutError) throw authErr;
|
|
8228
|
-
throw new McpAuthError(err.response.status, url);
|
|
8247
|
+
throw new McpAuthError(err.response.status, url, err.reason);
|
|
8229
8248
|
}
|
|
8230
8249
|
}
|
|
8231
8250
|
async function request(method, params) {
|
|
@@ -8686,7 +8705,8 @@ async function connect(platform2, options) {
|
|
|
8686
8705
|
timeoutMs: options.timeoutMs,
|
|
8687
8706
|
signal: options.signal,
|
|
8688
8707
|
verbose: options.verbose,
|
|
8689
|
-
authProvider: options.authProvider
|
|
8708
|
+
authProvider: options.authProvider,
|
|
8709
|
+
transportRefusals: platform2.kind === "kernel"
|
|
8690
8710
|
});
|
|
8691
8711
|
} catch (err) {
|
|
8692
8712
|
const isMethodNotFound = err instanceof StatelessRpcError && err.code === -32601 || err instanceof StatelessHttpError && err.status >= 400 && err.status < 500;
|
|
@@ -8978,7 +8998,7 @@ function toolDeclaration(tool) {
|
|
|
8978
8998
|
};
|
|
8979
8999
|
}
|
|
8980
9000
|
async function runDescribeTs(platform2, targets, budget) {
|
|
8981
|
-
const { renderDeclarations: renderDeclarations2 } = await Promise.resolve().then(() => (init_dist2(),
|
|
9001
|
+
const { renderDeclarations: renderDeclarations2 } = await Promise.resolve().then(() => (init_dist2(), dist_exports2));
|
|
8982
9002
|
const allTools = [];
|
|
8983
9003
|
for (const target of targets) {
|
|
8984
9004
|
const tools = await target.conn.listTools();
|
|
@@ -9049,6 +9069,39 @@ async function runGrep(platform2, pattern, targets, options) {
|
|
|
9049
9069
|
// src/codemode/run.ts
|
|
9050
9070
|
init_dist2();
|
|
9051
9071
|
init_source();
|
|
9072
|
+
|
|
9073
|
+
// src/codemode/deadline.ts
|
|
9074
|
+
var expiries = /* @__PURE__ */ new WeakMap();
|
|
9075
|
+
var hooked = /* @__PURE__ */ new WeakSet();
|
|
9076
|
+
function hookDeadlines(quickjs) {
|
|
9077
|
+
if (hooked.has(quickjs)) return;
|
|
9078
|
+
hooked.add(quickjs);
|
|
9079
|
+
const create = quickjs.create.bind(quickjs);
|
|
9080
|
+
quickjs.create = (options) => {
|
|
9081
|
+
const expired = options.wasm ? expiries.get(options.wasm) : void 0;
|
|
9082
|
+
const inner = options.interruptHandler;
|
|
9083
|
+
if (!expired || !inner) return create(options);
|
|
9084
|
+
return create({ ...options, interruptHandler: () => expired() || inner() });
|
|
9085
|
+
};
|
|
9086
|
+
}
|
|
9087
|
+
function bindDeadline(wasm, timeoutMs, now = Date.now) {
|
|
9088
|
+
let endsAt = Number.POSITIVE_INFINITY;
|
|
9089
|
+
let tripped = false;
|
|
9090
|
+
expiries.set(wasm, () => {
|
|
9091
|
+
if (!tripped && now() >= endsAt) tripped = true;
|
|
9092
|
+
return tripped;
|
|
9093
|
+
});
|
|
9094
|
+
return {
|
|
9095
|
+
start() {
|
|
9096
|
+
endsAt = now() + timeoutMs;
|
|
9097
|
+
},
|
|
9098
|
+
get tripped() {
|
|
9099
|
+
return tripped;
|
|
9100
|
+
}
|
|
9101
|
+
};
|
|
9102
|
+
}
|
|
9103
|
+
|
|
9104
|
+
// src/codemode/run.ts
|
|
9052
9105
|
async function loadStore(platform2, stateDir2) {
|
|
9053
9106
|
const storePath = `${stateDir2}/codemode-store.json`;
|
|
9054
9107
|
try {
|
|
@@ -9234,9 +9287,23 @@ async function runCode(targets, source, options) {
|
|
|
9234
9287
|
...buildDiscoveryGlobals(allDeclaredTools, namespaces, searchDocs),
|
|
9235
9288
|
...options.allowShell ? [buildShellGlobal(platform2)] : []
|
|
9236
9289
|
];
|
|
9237
|
-
const sandbox = await createSandbox(
|
|
9290
|
+
const { sandbox, deadline } = await createSandbox(
|
|
9291
|
+
platform2,
|
|
9292
|
+
toolImpls,
|
|
9293
|
+
globals,
|
|
9294
|
+
timeoutMs,
|
|
9295
|
+
memoryLimitBytes
|
|
9296
|
+
);
|
|
9238
9297
|
try {
|
|
9239
|
-
|
|
9298
|
+
deadline?.start();
|
|
9299
|
+
const executed = await sandbox.execute(code, { store });
|
|
9300
|
+
const result = deadline?.tripped && !executed.ok ? {
|
|
9301
|
+
...executed,
|
|
9302
|
+
error: {
|
|
9303
|
+
kind: "timeout",
|
|
9304
|
+
message: `Execution timed out after ${timeoutMs} ms`
|
|
9305
|
+
}
|
|
9306
|
+
} : executed;
|
|
9240
9307
|
if (result.ok) {
|
|
9241
9308
|
const writes = result.storeWrites;
|
|
9242
9309
|
if (Object.keys(writes.set).length > 0 || writes.delete.length > 0) {
|
|
@@ -9282,12 +9349,23 @@ async function createSandbox(platform2, tools, globals, timeoutMs, memoryLimitBy
|
|
|
9282
9349
|
const isKernel2 = platform2.packageDir !== void 0;
|
|
9283
9350
|
if (isKernel2) {
|
|
9284
9351
|
const { InlineCodemodeSandbox: InlineCodemodeSandbox2 } = await Promise.resolve().then(() => (init_portable(), portable_exports));
|
|
9352
|
+
const { QuickJS: QuickJS2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
|
|
9353
|
+
hookDeadlines(QuickJS2);
|
|
9285
9354
|
const wasm = await loadWasmKernel(platform2);
|
|
9286
|
-
|
|
9355
|
+
const deadline = bindDeadline(wasm, timeoutMs);
|
|
9356
|
+
const sandbox2 = new InlineCodemodeSandbox2({
|
|
9357
|
+
tools,
|
|
9358
|
+
globals,
|
|
9359
|
+
timeoutMs,
|
|
9360
|
+
wasm,
|
|
9361
|
+
memoryLimitBytes,
|
|
9362
|
+
interruptBudget: Number.POSITIVE_INFINITY
|
|
9363
|
+
});
|
|
9364
|
+
return { sandbox: sandbox2, deadline };
|
|
9287
9365
|
}
|
|
9288
|
-
const { CodemodeSandbox: CodemodeSandbox2, loadQuickJSWasm: loadQuickJSWasm2 } = await Promise.resolve().then(() => (init_dist2(),
|
|
9366
|
+
const { CodemodeSandbox: CodemodeSandbox2, loadQuickJSWasm: loadQuickJSWasm2 } = await Promise.resolve().then(() => (init_dist2(), dist_exports2));
|
|
9289
9367
|
const wasmPath = await resolveWasmPath(platform2);
|
|
9290
|
-
|
|
9368
|
+
const sandbox = new CodemodeSandbox2({
|
|
9291
9369
|
tools,
|
|
9292
9370
|
globals,
|
|
9293
9371
|
timeoutMs,
|
|
@@ -9295,6 +9373,7 @@ async function createSandbox(platform2, tools, globals, timeoutMs, memoryLimitBy
|
|
|
9295
9373
|
wasm: loadQuickJSWasm2(wasmPath),
|
|
9296
9374
|
workerUrl: new URL("./codemode-worker.mjs", import.meta.url)
|
|
9297
9375
|
});
|
|
9376
|
+
return { sandbox };
|
|
9298
9377
|
}
|
|
9299
9378
|
async function resolveWasmPath(platform2) {
|
|
9300
9379
|
const candidates = [
|
|
@@ -11804,16 +11883,45 @@ function wrapUntrusted(content) {
|
|
|
11804
11883
|
${neutralised}
|
|
11805
11884
|
${closeTag}`;
|
|
11806
11885
|
}
|
|
11807
|
-
|
|
11886
|
+
var WEBMCP_LIST_FLOOR = 1048576;
|
|
11887
|
+
function capCollector(limit) {
|
|
11888
|
+
const dec = new TextDecoder();
|
|
11889
|
+
const half = Math.floor(limit / 2);
|
|
11890
|
+
let head = "";
|
|
11891
|
+
let tail = "";
|
|
11892
|
+
let total = 0;
|
|
11893
|
+
const take = (piece) => {
|
|
11894
|
+
if (!piece) return;
|
|
11895
|
+
total += piece.length;
|
|
11896
|
+
if (head.length < limit) head += piece.slice(0, limit - head.length);
|
|
11897
|
+
tail = half > 0 ? (tail + piece).slice(-half) : "";
|
|
11898
|
+
};
|
|
11899
|
+
return {
|
|
11900
|
+
push(chunk) {
|
|
11901
|
+
take(dec.decode(chunk, { stream: true }));
|
|
11902
|
+
},
|
|
11903
|
+
finish() {
|
|
11904
|
+
take(dec.decode());
|
|
11905
|
+
if (total <= limit) return { text: head, cut: false };
|
|
11906
|
+
return {
|
|
11907
|
+
text: `${head.slice(0, half)}
|
|
11908
|
+
\u2026 ${total - limit} characters cut \u2026
|
|
11909
|
+
${tail}`,
|
|
11910
|
+
cut: true
|
|
11911
|
+
};
|
|
11912
|
+
}
|
|
11913
|
+
};
|
|
11914
|
+
}
|
|
11915
|
+
async function runProcess(platform2, argv, stdin, timeoutMs, limit) {
|
|
11808
11916
|
let proc;
|
|
11809
11917
|
try {
|
|
11810
11918
|
proc = await platform2.spawn({ argv });
|
|
11811
|
-
} catch (
|
|
11812
|
-
const code =
|
|
11919
|
+
} catch (err2) {
|
|
11920
|
+
const code = err2.code;
|
|
11813
11921
|
if (code === "ENOENT" || code === "EACCES") {
|
|
11814
|
-
return { stdout: "", stderr: `command not found: ${argv[0]}`, exitCode: -1 };
|
|
11922
|
+
return { stdout: "", stderr: `command not found: ${argv[0]}`, exitCode: -1, cut: false };
|
|
11815
11923
|
}
|
|
11816
|
-
throw
|
|
11924
|
+
throw err2;
|
|
11817
11925
|
}
|
|
11818
11926
|
if (stdin !== void 0) {
|
|
11819
11927
|
const writer = proc.stdin.getWriter();
|
|
@@ -11825,8 +11933,8 @@ async function runProcess(platform2, argv, stdin, timeoutMs) {
|
|
|
11825
11933
|
} catch {
|
|
11826
11934
|
}
|
|
11827
11935
|
}
|
|
11828
|
-
const
|
|
11829
|
-
const
|
|
11936
|
+
const out = capCollector(limit);
|
|
11937
|
+
const err = capCollector(limit);
|
|
11830
11938
|
const readStream3 = async (stream, into) => {
|
|
11831
11939
|
const r = stream.getReader();
|
|
11832
11940
|
try {
|
|
@@ -11839,53 +11947,136 @@ async function runProcess(platform2, argv, stdin, timeoutMs) {
|
|
|
11839
11947
|
r.releaseLock();
|
|
11840
11948
|
}
|
|
11841
11949
|
};
|
|
11842
|
-
|
|
11843
|
-
|
|
11844
|
-
|
|
11950
|
+
let timeoutId;
|
|
11951
|
+
const timer = new Promise((resolve2) => {
|
|
11952
|
+
timeoutId = setTimeout(() => resolve2("timeout"), timeoutMs);
|
|
11953
|
+
});
|
|
11845
11954
|
const work = Promise.all([
|
|
11846
|
-
readStream3(proc.stdout,
|
|
11847
|
-
readStream3(proc.stderr,
|
|
11955
|
+
readStream3(proc.stdout, out),
|
|
11956
|
+
readStream3(proc.stderr, err),
|
|
11848
11957
|
proc.wait()
|
|
11849
11958
|
]);
|
|
11850
11959
|
const result = await Promise.race([work, timer]);
|
|
11960
|
+
clearTimeout(timeoutId);
|
|
11851
11961
|
if (result === "timeout") {
|
|
11852
11962
|
await proc.kill("SIGTERM");
|
|
11853
|
-
return { stdout: "", stderr: "timed out", exitCode: 124 };
|
|
11963
|
+
return { stdout: "", stderr: "timed out", exitCode: 124, cut: false };
|
|
11854
11964
|
}
|
|
11855
11965
|
const [, , exitResult] = result;
|
|
11856
|
-
const
|
|
11857
|
-
const
|
|
11858
|
-
|
|
11859
|
-
|
|
11860
|
-
|
|
11861
|
-
|
|
11862
|
-
|
|
11863
|
-
offset += c.length;
|
|
11864
|
-
}
|
|
11865
|
-
return out;
|
|
11966
|
+
const stdout = out.finish();
|
|
11967
|
+
const stderr = err.finish();
|
|
11968
|
+
return {
|
|
11969
|
+
stdout: stdout.text,
|
|
11970
|
+
stderr: stderr.text,
|
|
11971
|
+
exitCode: exitResult.status,
|
|
11972
|
+
cut: stdout.cut
|
|
11866
11973
|
};
|
|
11974
|
+
}
|
|
11975
|
+
async function resolveWebMcpTab(platform2, options) {
|
|
11976
|
+
const argv = [options.playwrightCli, "tab-list"];
|
|
11977
|
+
if (options.cdp) argv.push("--cdp", options.cdp);
|
|
11978
|
+
const result = await runProcess(
|
|
11979
|
+
platform2,
|
|
11980
|
+
argv,
|
|
11981
|
+
void 0,
|
|
11982
|
+
options.callTimeoutMs,
|
|
11983
|
+
WEBMCP_LIST_FLOOR
|
|
11984
|
+
);
|
|
11985
|
+
if (result.exitCode === -1) return { error: result.stderr, notFound: true };
|
|
11986
|
+
if (result.exitCode !== 0) {
|
|
11987
|
+
return { error: result.stderr.trim() || `tab-list exited ${result.exitCode}` };
|
|
11988
|
+
}
|
|
11989
|
+
const rows = [];
|
|
11990
|
+
for (const line of result.stdout.split("\n")) {
|
|
11991
|
+
const match = /^(\d+): \[([^\]\s]+)\] /.exec(line);
|
|
11992
|
+
if (!match) continue;
|
|
11993
|
+
if (Number(match[1]) !== rows.length + 1) {
|
|
11994
|
+
return { error: "could not read playwright-cli tab-list" };
|
|
11995
|
+
}
|
|
11996
|
+
rows.push({ id: match[2], active: line.endsWith('" (active)') });
|
|
11997
|
+
}
|
|
11998
|
+
const active = rows.filter((r) => r.active);
|
|
11999
|
+
if (new Set(rows.map((r) => r.id)).size !== rows.length || active.length > 1) {
|
|
12000
|
+
return { error: "could not read playwright-cli tab-list" };
|
|
12001
|
+
}
|
|
12002
|
+
if (active.length === 1) return { tab: active[0].id };
|
|
12003
|
+
if (rows.length === 1) return { tab: rows[0].id };
|
|
11867
12004
|
return {
|
|
11868
|
-
|
|
11869
|
-
stderr: dec.decode(concat2(stderrChunks)),
|
|
11870
|
-
exitCode: exitResult.status
|
|
12005
|
+
error: rows.length === 0 ? "no browser tab is open; open one or pass --tab <targetId>" : "no current playwright-cli tab; pass --tab <targetId> (see playwright-cli tab-list)"
|
|
11871
12006
|
};
|
|
11872
12007
|
}
|
|
12008
|
+
function mapDescriptionAnnotations(ann) {
|
|
12009
|
+
const mapped = { openWorldHint: true };
|
|
12010
|
+
if (!ann) return mapped;
|
|
12011
|
+
if (ann.readOnlyHint !== void 0) mapped.readOnlyHint = ann.readOnlyHint;
|
|
12012
|
+
if (ann.consequentialHint) mapped.destructiveHint = true;
|
|
12013
|
+
return mapped;
|
|
12014
|
+
}
|
|
12015
|
+
function originPrefix(tools) {
|
|
12016
|
+
const origins = new Set(tools.map((t) => t.origin));
|
|
12017
|
+
return origins.size > 1;
|
|
12018
|
+
}
|
|
12019
|
+
function hostFromOrigin(origin) {
|
|
12020
|
+
try {
|
|
12021
|
+
return new URL(origin).host;
|
|
12022
|
+
} catch {
|
|
12023
|
+
return origin;
|
|
12024
|
+
}
|
|
12025
|
+
}
|
|
12026
|
+
function buildDescription(tool) {
|
|
12027
|
+
const parts = [];
|
|
12028
|
+
if (tool.description) parts.push(tool.description);
|
|
12029
|
+
parts.push(`[origin: ${tool.origin}]`);
|
|
12030
|
+
return parts.join("\n");
|
|
12031
|
+
}
|
|
12032
|
+
function buildToolName(tool, prefix) {
|
|
12033
|
+
const base = tool.name;
|
|
12034
|
+
if (!prefix) return base;
|
|
12035
|
+
const host = hostFromOrigin(tool.origin).replace(/[^a-zA-Z0-9_]/g, "_");
|
|
12036
|
+
return `${host}__${base}`;
|
|
12037
|
+
}
|
|
12038
|
+
function exposedTools(tools) {
|
|
12039
|
+
const needPrefix = originPrefix(tools);
|
|
12040
|
+
const byBase = /* @__PURE__ */ new Map();
|
|
12041
|
+
const byName = /* @__PURE__ */ new Map();
|
|
12042
|
+
for (const tool of tools) {
|
|
12043
|
+
const name = buildToolName(tool, needPrefix);
|
|
12044
|
+
byBase.set(tool.name, [...byBase.get(tool.name) ?? [], tool]);
|
|
12045
|
+
byName.set(name, [...byName.get(name) ?? [], tool]);
|
|
12046
|
+
}
|
|
12047
|
+
return tools.map((tool) => {
|
|
12048
|
+
const name = buildToolName(tool, needPrefix);
|
|
12049
|
+
const sameBase = byBase.get(tool.name);
|
|
12050
|
+
const sameName = byName.get(name);
|
|
12051
|
+
return { name, tool, peers: sameBase.length > 1 ? sameBase : sameName };
|
|
12052
|
+
});
|
|
12053
|
+
}
|
|
12054
|
+
function ambiguityError(name, peers) {
|
|
12055
|
+
const origins = [...new Set(peers.map((t) => String(t.origin)))].join(", ");
|
|
12056
|
+
return new Error(
|
|
12057
|
+
`tool "${name}" is ambiguous: ${peers.length} tools on the page match it (${origins}), and playwright-cli runs the first tool by name and cannot select one by origin, so mcpcat refuses the call`
|
|
12058
|
+
);
|
|
12059
|
+
}
|
|
11873
12060
|
function createWebMcpHandler(platform2, options) {
|
|
11874
12061
|
let cache;
|
|
11875
12062
|
const baseArgs = buildBaseArgs(options);
|
|
11876
|
-
|
|
12063
|
+
const listLimit = Math.max(options.maxOutput, WEBMCP_LIST_FLOOR);
|
|
12064
|
+
async function listRaw(fresh = false) {
|
|
11877
12065
|
const now = Date.now();
|
|
11878
|
-
if (cache && now < cache.expiresAt) {
|
|
12066
|
+
if (!fresh && cache && now < cache.expiresAt) {
|
|
11879
12067
|
return { tools: cache.tools };
|
|
11880
12068
|
}
|
|
11881
12069
|
const argv = [options.playwrightCli, "webmcp-list", "--json", ...baseArgs];
|
|
11882
|
-
const result = await runProcess(platform2, argv, void 0, options.callTimeoutMs);
|
|
12070
|
+
const result = await runProcess(platform2, argv, void 0, options.callTimeoutMs, listLimit);
|
|
11883
12071
|
if (result.exitCode === -1) {
|
|
11884
12072
|
return { tools: [], error: result.stderr, notFound: true };
|
|
11885
12073
|
}
|
|
11886
12074
|
if (result.exitCode !== 0) {
|
|
11887
12075
|
return { tools: [], error: result.stderr || `webmcp-list exited ${result.exitCode}` };
|
|
11888
12076
|
}
|
|
12077
|
+
if (result.cut) {
|
|
12078
|
+
return { tools: [], error: `webmcp-list output exceeds ${listLimit} characters` };
|
|
12079
|
+
}
|
|
11889
12080
|
let parsed;
|
|
11890
12081
|
try {
|
|
11891
12082
|
parsed = JSON.parse(result.stdout);
|
|
@@ -11899,49 +12090,19 @@ function createWebMcpHandler(platform2, options) {
|
|
|
11899
12090
|
cache = { tools, expiresAt: now + options.ttlMs };
|
|
11900
12091
|
return { tools };
|
|
11901
12092
|
}
|
|
11902
|
-
function mapDescriptionAnnotations(ann) {
|
|
11903
|
-
const mapped = { openWorldHint: true };
|
|
11904
|
-
if (!ann) return mapped;
|
|
11905
|
-
if (ann.readOnlyHint !== void 0) mapped.readOnlyHint = ann.readOnlyHint;
|
|
11906
|
-
if (ann.consequentialHint) mapped.destructiveHint = true;
|
|
11907
|
-
return mapped;
|
|
11908
|
-
}
|
|
11909
|
-
function originPrefix(tools) {
|
|
11910
|
-
const origins = new Set(tools.map((t) => t.origin));
|
|
11911
|
-
return origins.size > 1;
|
|
11912
|
-
}
|
|
11913
|
-
function hostFromOrigin(origin) {
|
|
11914
|
-
try {
|
|
11915
|
-
return new URL(origin).host;
|
|
11916
|
-
} catch {
|
|
11917
|
-
return origin;
|
|
11918
|
-
}
|
|
11919
|
-
}
|
|
11920
|
-
function buildDescription(tool) {
|
|
11921
|
-
const parts = [];
|
|
11922
|
-
if (tool.description) parts.push(tool.description);
|
|
11923
|
-
parts.push(`[origin: ${tool.origin}]`);
|
|
11924
|
-
return parts.join("\n");
|
|
11925
|
-
}
|
|
11926
|
-
function buildToolName(tool, prefix) {
|
|
11927
|
-
const base = tool.name;
|
|
11928
|
-
if (!prefix) return base;
|
|
11929
|
-
const host = hostFromOrigin(tool.origin).replace(/[^a-zA-Z0-9_]/g, "_");
|
|
11930
|
-
return `${host}__${base}`;
|
|
11931
|
-
}
|
|
11932
12093
|
async function getRpcTools() {
|
|
11933
12094
|
const { tools, error, notFound } = await listRaw();
|
|
11934
12095
|
if (notFound) return null;
|
|
11935
12096
|
if (error) return [];
|
|
11936
|
-
const needPrefix = originPrefix(tools);
|
|
11937
12097
|
const rpcTools = [];
|
|
11938
|
-
for (const tool of tools) {
|
|
12098
|
+
for (const { name, tool, peers } of exposedTools(tools)) {
|
|
12099
|
+
if (peers.length > 1) continue;
|
|
11939
12100
|
if (tool.annotations?.consequentialHint && !options.allowConsequential) {
|
|
11940
12101
|
continue;
|
|
11941
12102
|
}
|
|
11942
12103
|
const mapped = mapDescriptionAnnotations(tool.annotations);
|
|
11943
12104
|
rpcTools.push({
|
|
11944
|
-
name
|
|
12105
|
+
name,
|
|
11945
12106
|
description: buildDescription(tool),
|
|
11946
12107
|
inputSchema: tool.inputSchema,
|
|
11947
12108
|
annotations: mapped
|
|
@@ -11950,21 +12111,30 @@ function createWebMcpHandler(platform2, options) {
|
|
|
11950
12111
|
return rpcTools;
|
|
11951
12112
|
}
|
|
11952
12113
|
async function callTool(name, args) {
|
|
11953
|
-
const { tools, error } = await listRaw();
|
|
12114
|
+
const { tools, error } = await listRaw(true);
|
|
11954
12115
|
if (error) {
|
|
11955
12116
|
return { stdout: "", stderr: error, exitCode: 2 };
|
|
11956
12117
|
}
|
|
11957
|
-
const
|
|
11958
|
-
|
|
11959
|
-
if (!tool) {
|
|
12118
|
+
const match = exposedTools(tools).find((t) => t.name === name);
|
|
12119
|
+
if (!match) {
|
|
11960
12120
|
return { stdout: "", stderr: `unknown tool: ${name}`, exitCode: 2 };
|
|
11961
12121
|
}
|
|
12122
|
+
if (match.peers.length > 1) {
|
|
12123
|
+
throw ambiguityError(name, match.peers);
|
|
12124
|
+
}
|
|
12125
|
+
const { tool } = match;
|
|
11962
12126
|
const argv = [options.playwrightCli, "webmcp-call", tool.name, "-", ...baseArgs];
|
|
11963
12127
|
if (options.allowConsequential) {
|
|
11964
12128
|
argv.push("--allow-consequential");
|
|
11965
12129
|
}
|
|
11966
12130
|
const stdinData = JSON.stringify(args ?? {});
|
|
11967
|
-
const result = await runProcess(
|
|
12131
|
+
const result = await runProcess(
|
|
12132
|
+
platform2,
|
|
12133
|
+
argv,
|
|
12134
|
+
stdinData,
|
|
12135
|
+
options.callTimeoutMs,
|
|
12136
|
+
options.maxOutput
|
|
12137
|
+
);
|
|
11968
12138
|
if (result.exitCode === -1) {
|
|
11969
12139
|
throw new Error(result.stderr || "playwright-cli not found");
|
|
11970
12140
|
}
|
|
@@ -12490,6 +12660,7 @@ async function discoverWithSignal(platform2, commands, childEnv, cwd) {
|
|
|
12490
12660
|
};
|
|
12491
12661
|
platform2.onSignal?.("SIGTERM", onShutdown);
|
|
12492
12662
|
platform2.onSignal?.("SIGINT", onShutdown);
|
|
12663
|
+
platform2.onSignal?.("SIGHUP", onShutdown);
|
|
12493
12664
|
for (const cmd of commands) {
|
|
12494
12665
|
try {
|
|
12495
12666
|
const cli = await discoverCli(platform2, cmd.path, cmd.name, childEnv, cwd, earlyAbort.signal);
|
|
@@ -12715,9 +12886,30 @@ async function runWebMcpServe(platform2, options, version, resolvedBearer, gener
|
|
|
12715
12886
|
return 3;
|
|
12716
12887
|
}
|
|
12717
12888
|
const cdp = options.webmcpCdp ?? platform2.env.SLICC_CDP_URL;
|
|
12889
|
+
let tab = options.webmcpTab;
|
|
12890
|
+
if (!tab) {
|
|
12891
|
+
const resolved = await resolveWebMcpTab(platform2, {
|
|
12892
|
+
playwrightCli: cliPath,
|
|
12893
|
+
cdp,
|
|
12894
|
+
callTimeoutMs: options.callTimeout
|
|
12895
|
+
});
|
|
12896
|
+
if (resolved.notFound) {
|
|
12897
|
+
await platform2.write(
|
|
12898
|
+
2,
|
|
12899
|
+
"mcpcat serve --webmcp: playwright-cli not found. Install it with: curl -fsSL https://get.sliccy.ai/playwright-cli | sh\n"
|
|
12900
|
+
);
|
|
12901
|
+
return 3;
|
|
12902
|
+
}
|
|
12903
|
+
if (!resolved.tab) {
|
|
12904
|
+
await platform2.write(2, `mcpcat serve --webmcp: ${resolved.error}
|
|
12905
|
+
`);
|
|
12906
|
+
return 3;
|
|
12907
|
+
}
|
|
12908
|
+
tab = resolved.tab;
|
|
12909
|
+
}
|
|
12718
12910
|
const handler = createWebMcpHandler(platform2, {
|
|
12719
12911
|
playwrightCli: cliPath,
|
|
12720
|
-
tab
|
|
12912
|
+
tab,
|
|
12721
12913
|
cdp,
|
|
12722
12914
|
allowConsequential: options.webmcpAllowConsequential,
|
|
12723
12915
|
ttlMs: options.webmcpTtl,
|
|
@@ -12799,6 +12991,21 @@ async function runWebMcpHttp(platform2, options, getTools, callTool, serverName,
|
|
|
12799
12991
|
const address = serveAddress(platform2, options.host, actualPort);
|
|
12800
12992
|
const listenUrl = address.url;
|
|
12801
12993
|
let tokenFilePath;
|
|
12994
|
+
let shutdownRequested = false;
|
|
12995
|
+
const shutdown = () => {
|
|
12996
|
+
if (shutdownRequested) return;
|
|
12997
|
+
shutdownRequested = true;
|
|
12998
|
+
listener.close();
|
|
12999
|
+
if (tokenFilePath) {
|
|
13000
|
+
platform2.fs.unlink?.(tokenFilePath).catch(() => {
|
|
13001
|
+
});
|
|
13002
|
+
}
|
|
13003
|
+
};
|
|
13004
|
+
if (platform2.onSignal) {
|
|
13005
|
+
platform2.onSignal("SIGINT", shutdown);
|
|
13006
|
+
platform2.onSignal("SIGTERM", shutdown);
|
|
13007
|
+
platform2.onSignal("SIGHUP", shutdown);
|
|
13008
|
+
}
|
|
12802
13009
|
if (generatedBearer && resolvedBearer) {
|
|
12803
13010
|
tokenFilePath = await publishBearer(
|
|
12804
13011
|
platform2,
|
|
@@ -12807,31 +13014,22 @@ async function runWebMcpHttp(platform2, options, getTools, callTool, serverName,
|
|
|
12807
13014
|
address,
|
|
12808
13015
|
options.json
|
|
12809
13016
|
);
|
|
13017
|
+
if (shutdownRequested && tokenFilePath) {
|
|
13018
|
+
await platform2.fs.unlink?.(tokenFilePath).catch(() => {
|
|
13019
|
+
});
|
|
13020
|
+
}
|
|
12810
13021
|
} else {
|
|
12811
13022
|
if (options.json) {
|
|
12812
13023
|
await platform2.write(1, `${JSON.stringify(address)}
|
|
12813
13024
|
`);
|
|
12814
13025
|
}
|
|
12815
13026
|
}
|
|
12816
|
-
|
|
13027
|
+
if (!shutdownRequested) {
|
|
13028
|
+
await platform2.write(2, `mcpcat serve --webmcp: listening on ${listenUrl}
|
|
12817
13029
|
`);
|
|
12818
|
-
|
|
12819
|
-
|
|
12820
|
-
}
|
|
12821
|
-
let shutdownRequested = false;
|
|
12822
|
-
const shutdown = () => {
|
|
12823
|
-
if (shutdownRequested) return;
|
|
12824
|
-
shutdownRequested = true;
|
|
12825
|
-
listener.close();
|
|
12826
|
-
if (tokenFilePath) {
|
|
12827
|
-
platform2.fs.unlink?.(tokenFilePath).catch(() => {
|
|
12828
|
-
});
|
|
13030
|
+
if (options.onListening) {
|
|
13031
|
+
await options.onListening(actualPort);
|
|
12829
13032
|
}
|
|
12830
|
-
};
|
|
12831
|
-
if (platform2.onSignal) {
|
|
12832
|
-
platform2.onSignal("SIGINT", shutdown);
|
|
12833
|
-
platform2.onSignal("SIGTERM", shutdown);
|
|
12834
|
-
platform2.onSignal("SIGHUP", shutdown);
|
|
12835
13033
|
}
|
|
12836
13034
|
const handler = async (request) => {
|
|
12837
13035
|
if (request.target !== "/mcp") {
|
|
@@ -12995,6 +13193,23 @@ async function runProxyHttp(platform2, options, proxy, resolvedBearer, generated
|
|
|
12995
13193
|
const address = serveAddress(platform2, options.host, actualPort);
|
|
12996
13194
|
const listenUrl = address.url;
|
|
12997
13195
|
let tokenFilePath;
|
|
13196
|
+
let shutdownRequested = false;
|
|
13197
|
+
let proxyDone;
|
|
13198
|
+
const shutdown = () => {
|
|
13199
|
+
if (shutdownRequested) return;
|
|
13200
|
+
shutdownRequested = true;
|
|
13201
|
+
listener.close();
|
|
13202
|
+
proxyDone = proxy.shutdown();
|
|
13203
|
+
if (tokenFilePath) {
|
|
13204
|
+
platform2.fs.unlink?.(tokenFilePath).catch(() => {
|
|
13205
|
+
});
|
|
13206
|
+
}
|
|
13207
|
+
};
|
|
13208
|
+
if (platform2.onSignal) {
|
|
13209
|
+
platform2.onSignal("SIGINT", shutdown);
|
|
13210
|
+
platform2.onSignal("SIGTERM", shutdown);
|
|
13211
|
+
platform2.onSignal("SIGHUP", shutdown);
|
|
13212
|
+
}
|
|
12998
13213
|
if (generatedBearer && resolvedBearer) {
|
|
12999
13214
|
tokenFilePath = await publishBearer(
|
|
13000
13215
|
platform2,
|
|
@@ -13003,32 +13218,22 @@ async function runProxyHttp(platform2, options, proxy, resolvedBearer, generated
|
|
|
13003
13218
|
address,
|
|
13004
13219
|
options.json
|
|
13005
13220
|
);
|
|
13221
|
+
if (shutdownRequested && tokenFilePath) {
|
|
13222
|
+
await platform2.fs.unlink?.(tokenFilePath).catch(() => {
|
|
13223
|
+
});
|
|
13224
|
+
}
|
|
13006
13225
|
} else {
|
|
13007
13226
|
if (options.json) {
|
|
13008
13227
|
await platform2.write(1, `${JSON.stringify(address)}
|
|
13009
13228
|
`);
|
|
13010
13229
|
}
|
|
13011
13230
|
}
|
|
13012
|
-
|
|
13231
|
+
if (!shutdownRequested) {
|
|
13232
|
+
await platform2.write(2, `mcpcat serve --proxy: listening on ${listenUrl}
|
|
13013
13233
|
`);
|
|
13014
|
-
|
|
13015
|
-
|
|
13016
|
-
}
|
|
13017
|
-
let shutdownRequested = false;
|
|
13018
|
-
const shutdown = () => {
|
|
13019
|
-
if (shutdownRequested) return;
|
|
13020
|
-
shutdownRequested = true;
|
|
13021
|
-
listener.close();
|
|
13022
|
-
void proxy.shutdown();
|
|
13023
|
-
if (tokenFilePath) {
|
|
13024
|
-
platform2.fs.unlink?.(tokenFilePath).catch(() => {
|
|
13025
|
-
});
|
|
13234
|
+
if (options.onListening) {
|
|
13235
|
+
await options.onListening(actualPort);
|
|
13026
13236
|
}
|
|
13027
|
-
};
|
|
13028
|
-
if (platform2.onSignal) {
|
|
13029
|
-
platform2.onSignal("SIGINT", shutdown);
|
|
13030
|
-
platform2.onSignal("SIGTERM", shutdown);
|
|
13031
|
-
platform2.onSignal("SIGHUP", shutdown);
|
|
13032
13237
|
}
|
|
13033
13238
|
const handler = (request) => handleProxyMcpRequest(
|
|
13034
13239
|
request,
|
|
@@ -13053,6 +13258,7 @@ async function runProxyHttp(platform2, options, proxy, resolvedBearer, generated
|
|
|
13053
13258
|
} catch {
|
|
13054
13259
|
if (!shutdownRequested) throw new Error("listener closed unexpectedly");
|
|
13055
13260
|
}
|
|
13261
|
+
await proxyDone;
|
|
13056
13262
|
return 0;
|
|
13057
13263
|
}
|
|
13058
13264
|
async function handleProxyMcpRequest(request, proxy, serverOrigins, allowedOrigins, allowedHosts, resolvedBearer) {
|
|
@@ -13172,22 +13378,6 @@ async function runHttpServer(platform2, options, tools, call, serverName, versio
|
|
|
13172
13378
|
const address = serveAddress(platform2, options.host, actualPort);
|
|
13173
13379
|
const listenUrl = address.url;
|
|
13174
13380
|
let tokenFilePath;
|
|
13175
|
-
if (generatedBearer && resolvedBearer) {
|
|
13176
|
-
tokenFilePath = await publishBearer(
|
|
13177
|
-
platform2,
|
|
13178
|
-
resolvedBearer,
|
|
13179
|
-
actualPort,
|
|
13180
|
-
address,
|
|
13181
|
-
options.json
|
|
13182
|
-
);
|
|
13183
|
-
} else {
|
|
13184
|
-
if (options.json) {
|
|
13185
|
-
await platform2.write(1, `${JSON.stringify(address)}
|
|
13186
|
-
`);
|
|
13187
|
-
}
|
|
13188
|
-
}
|
|
13189
|
-
await platform2.write(2, `mcpcat serve: listening on ${listenUrl}
|
|
13190
|
-
`);
|
|
13191
13381
|
let shutdownRequested = false;
|
|
13192
13382
|
let inflightDone;
|
|
13193
13383
|
const shutdown = () => {
|
|
@@ -13205,6 +13395,28 @@ async function runHttpServer(platform2, options, tools, call, serverName, versio
|
|
|
13205
13395
|
platform2.onSignal("SIGTERM", shutdown);
|
|
13206
13396
|
platform2.onSignal("SIGHUP", shutdown);
|
|
13207
13397
|
}
|
|
13398
|
+
if (generatedBearer && resolvedBearer) {
|
|
13399
|
+
tokenFilePath = await publishBearer(
|
|
13400
|
+
platform2,
|
|
13401
|
+
resolvedBearer,
|
|
13402
|
+
actualPort,
|
|
13403
|
+
address,
|
|
13404
|
+
options.json
|
|
13405
|
+
);
|
|
13406
|
+
if (shutdownRequested && tokenFilePath) {
|
|
13407
|
+
await platform2.fs.unlink?.(tokenFilePath).catch(() => {
|
|
13408
|
+
});
|
|
13409
|
+
}
|
|
13410
|
+
} else {
|
|
13411
|
+
if (options.json) {
|
|
13412
|
+
await platform2.write(1, `${JSON.stringify(address)}
|
|
13413
|
+
`);
|
|
13414
|
+
}
|
|
13415
|
+
}
|
|
13416
|
+
if (!shutdownRequested) {
|
|
13417
|
+
await platform2.write(2, `mcpcat serve: listening on ${listenUrl}
|
|
13418
|
+
`);
|
|
13419
|
+
}
|
|
13208
13420
|
const handler = (request) => handleMcpRequest(
|
|
13209
13421
|
request,
|
|
13210
13422
|
tools,
|
|
@@ -16274,6 +16486,15 @@ function collectHeaders(init) {
|
|
|
16274
16486
|
}
|
|
16275
16487
|
return entries;
|
|
16276
16488
|
}
|
|
16489
|
+
async function encodeBody(body, headerEntries) {
|
|
16490
|
+
if (body == null) return new Uint8Array(0);
|
|
16491
|
+
const encoded = new Response(body);
|
|
16492
|
+
const type = encoded.headers.get("content-type");
|
|
16493
|
+
if (type && !headerEntries.some(([k]) => k.toLowerCase() === "content-type")) {
|
|
16494
|
+
headerEntries.push(["Content-Type", type]);
|
|
16495
|
+
}
|
|
16496
|
+
return new Uint8Array(await encoded.arrayBuffer());
|
|
16497
|
+
}
|
|
16277
16498
|
function buildHttpRequest(method, url, headerEntries, bodyBytes) {
|
|
16278
16499
|
const enc = new TextEncoder();
|
|
16279
16500
|
const has = (n) => headerEntries.some(([k]) => k.toLowerCase() === n.toLowerCase());
|
|
@@ -16316,15 +16537,7 @@ function parseHttpResponse(buf, headerPos, bufLen) {
|
|
|
16316
16537
|
}
|
|
16317
16538
|
async function kernelLoopbackFetch(ctx, url, port, init, onRefused) {
|
|
16318
16539
|
const method = (init?.method ?? "GET").toUpperCase();
|
|
16319
|
-
const enc = new TextEncoder();
|
|
16320
16540
|
const dec = new TextDecoder();
|
|
16321
|
-
let bodyStr = "";
|
|
16322
|
-
if (init?.body != null) {
|
|
16323
|
-
bodyStr = typeof init.body === "string" ? init.body : dec.decode(init.body);
|
|
16324
|
-
}
|
|
16325
|
-
const bodyBytes = enc.encode(bodyStr);
|
|
16326
|
-
const headerEntries = collectHeaders(init);
|
|
16327
|
-
const reqBytes = buildHttpRequest(method, url, headerEntries, bodyBytes);
|
|
16328
16541
|
let conn;
|
|
16329
16542
|
try {
|
|
16330
16543
|
conn = await ctx.net.connect({ host: "127.0.0.1", port });
|
|
@@ -16332,8 +16545,10 @@ async function kernelLoopbackFetch(ctx, url, port, init, onRefused) {
|
|
|
16332
16545
|
if (onRefused && isConnectionRefused(err)) return onRefused();
|
|
16333
16546
|
throw err;
|
|
16334
16547
|
}
|
|
16548
|
+
const headerEntries = collectHeaders(init);
|
|
16549
|
+
const bodyBytes = await encodeBody(init?.body, headerEntries);
|
|
16335
16550
|
const writer = conn.writable.getWriter();
|
|
16336
|
-
await writer.write(
|
|
16551
|
+
await writer.write(buildHttpRequest(method, url, headerEntries, bodyBytes));
|
|
16337
16552
|
const reader = conn.readable.getReader();
|
|
16338
16553
|
let buf = new Uint8Array(4096);
|
|
16339
16554
|
let bufLen = 0;
|
|
@@ -16452,7 +16667,7 @@ async function main(ctx) {
|
|
|
16452
16667
|
packageDir: "/node_modules/@ai-ecoverse/mcpcat"
|
|
16453
16668
|
});
|
|
16454
16669
|
const args = ctx.argv.slice(1);
|
|
16455
|
-
return run(platform2, "0.15.
|
|
16670
|
+
return run(platform2, "0.15.7", args);
|
|
16456
16671
|
}
|
|
16457
16672
|
export {
|
|
16458
16673
|
main as default
|