@modelcontextprotocol/inspector 2.13.0 → 2.14.0
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 +1 -1
- package/clients/cli/build/index.js +1013 -80
- package/clients/mcpdo/build/mcp-bin.js +50 -22
- package/clients/mcpdo/build/mcpdod.js +1 -1
- package/clients/mcpdo/build/{server-BHuKGkMj.js → server-Dv339Ejx.js} +886 -48
- package/clients/tui/build/index.js +781 -46
- package/clients/web/build/index.js +223 -124
- package/clients/web/dist/assets/fredoka-normal-hebrew-CjvktpUN.woff2 +0 -0
- package/clients/web/dist/assets/fredoka-normal-latin-DOQG_Jwn.woff2 +0 -0
- package/clients/web/dist/assets/fredoka-normal-latin-ext-tYNUQHO6.woff2 +0 -0
- package/clients/web/dist/assets/index-BCud2uMC.js +1594 -0
- package/clients/web/dist/assets/{index-dqp8Sd8W.css → index-Dval2a7I.css} +1 -1
- package/clients/web/dist/assets/{prism-light-BIhJtJkv.js → prism-light-CoVRM9R2.js} +1 -1
- package/clients/web/dist/assets/roboto-mono-italic-cyrillic-C1E63de8.woff2 +0 -0
- package/clients/web/dist/assets/roboto-mono-italic-cyrillic-ext-DR9ovEqT.woff2 +0 -0
- package/clients/web/dist/assets/roboto-mono-italic-greek-Cs2u2nVh.woff2 +0 -0
- package/clients/web/dist/assets/roboto-mono-italic-latin-D_P-kX1t.woff2 +0 -0
- package/clients/web/dist/assets/roboto-mono-italic-latin-ext-CErTcBzw.woff2 +0 -0
- package/clients/web/dist/assets/roboto-mono-italic-vietnamese-D4UvzJMM.woff2 +0 -0
- package/clients/web/dist/assets/roboto-mono-normal-cyrillic-DfzWIUPd.woff2 +0 -0
- package/clients/web/dist/assets/roboto-mono-normal-cyrillic-ext-D8QBEkUe.woff2 +0 -0
- package/clients/web/dist/assets/roboto-mono-normal-greek-DlC4X1lQ.woff2 +0 -0
- package/clients/web/dist/assets/roboto-mono-normal-latin-BAKpfWyj.woff2 +0 -0
- package/clients/web/dist/assets/roboto-mono-normal-latin-ext-CSSVNFqV.woff2 +0 -0
- package/clients/web/dist/assets/roboto-mono-normal-vietnamese-DFkHeOHB.woff2 +0 -0
- package/clients/web/dist/fonts/Fredoka-OFL.txt +93 -0
- package/clients/web/dist/fonts/RobotoMono-OFL.txt +93 -0
- package/clients/web/dist/index.html +2 -5
- package/clients/web/static/sandbox_proxy.html +177 -6
- package/package.json +5 -4
- package/skills/mcpdo/SKILL.md +14 -0
- package/clients/web/dist/assets/index-BqEbhCDX.js +0 -1587
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as
|
|
2
|
+
import { $ as withDefaultCatalogPath, A as resolveLoadOptions, B as assertSocketPathWithinLimit, C as clearAllOAuthClientState, D as loadSummaryWarnings, E as LOAD_FLAG_CONFLICT, F as generateDaemonToken, G as getDaemonSocketPath, H as ensureDaemonDir, I as getDaemonTokenFromEnv, J as loadServerEntries, K as readInspectorVersion, L as readDaemonTokenFile, M as sanitizeDeep, N as sanitizeText, O as positiveIntegerParser, P as encodeRequest, Q as resolveServerSource, R as DAEMON_DIR_ENV, S as NodeOAuthStorage, T as resetNodeOAuthStorageCache, U as getDaemonDir, V as createPrivateDaemonDir, W as getDaemonLogPath, X as parseHeaderPair, Y as selectServerEntry, Z as parseKeyValuePair, _ as isCliAutoOpenForced, _t as awaitableError, a as obtainPendingUrlForKey, at as readOAuthStore, b as DEFAULT_CONNECT_TIMEOUT_MS, c as runAuthHelper, ct as setSecretStorageWarningsQuiet, d as emaLogin, dt as CallbackNavigation, et as DEFAULT_MAX_FETCH_REQUESTS, f as emaLogout, ft as clearEmaIdpSession, g as runEmaIdpInteractiveFlow, gt as parseIdpOAuthStorageKey, h as requireIdp, ht as normalizeIdpIssuer, i as obtainPendingAuthUrl, it as handleError, j as isSafeLinkTarget, k as positiveNumberParser, l as writePendingAuthMarker, lt as warnAboutSecretStorage, m as loadEmaIdpConfig, mt as idpOAuthStorageKey, n as AUTH_HELPER_COMMAND, nt as CliExitCodeError, o as pendingAuthMarkerPath, ot as disallowMemorySecretStoreFallback, p as getEmaStatus, pt as getEmaIdpLoginState, q as readInspectorVersionSafe, r as PENDING_AUTH_TTL_MS, rt as EXIT_CODES, s as removeOwnPendingAuthMarker, st as getSecretStorageInfo, tt as DEFAULT_TASK_TTL_MS, u as authorizeInFrontend, ut as InMemorySecretStore, v as PLAIN, vt as awaitableLog, w as getStateFilePath, x as withConnectTimeout, y as styleFromOpts, z as DAEMON_TOKEN_ENV } from "./server-Dv339Ejx.js";
|
|
3
3
|
import { realpathSync } from "fs";
|
|
4
4
|
import { resolve } from "path";
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
@@ -304,14 +304,18 @@ async function waitForDaemon(socketPath, token, logPath, opts) {
|
|
|
304
304
|
while (Date.now() < deadline) {
|
|
305
305
|
if (await isDaemonReachable(socketPath)) {
|
|
306
306
|
const effectiveToken = opts?.rereadTokenDir ? readDaemonTokenFile(opts.rereadTokenDir) ?? token : token;
|
|
307
|
+
let pong;
|
|
307
308
|
try {
|
|
308
|
-
await callDaemon("ping", {}, {
|
|
309
|
+
pong = await callDaemon("ping", {}, {
|
|
309
310
|
socketPath,
|
|
310
311
|
timeoutMs: 2e3,
|
|
311
312
|
token: effectiveToken
|
|
312
313
|
});
|
|
313
|
-
return;
|
|
314
314
|
} catch {}
|
|
315
|
+
if (pong !== void 0) {
|
|
316
|
+
assertDaemonVersion(pong.version, CLIENT_VERSION);
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
315
319
|
}
|
|
316
320
|
await new Promise((r) => setTimeout(r, READY_POLL_MS));
|
|
317
321
|
}
|
|
@@ -343,6 +347,12 @@ async function waitForDaemonExit(pid, socketPath, timeoutMs = STOPPING_EXIT_TIME
|
|
|
343
347
|
await new Promise((r) => setTimeout(r, pollMs));
|
|
344
348
|
}
|
|
345
349
|
}
|
|
350
|
+
const CLIENT_VERSION = readInspectorVersionSafe(import.meta.url);
|
|
351
|
+
function assertDaemonVersion(daemonVersion, clientVersion) {
|
|
352
|
+
if (clientVersion === void 0 || daemonVersion === clientVersion) return;
|
|
353
|
+
const running = daemonVersion === void 0 ? "an older mcpdo release" : `mcpdo ${daemonVersion}`;
|
|
354
|
+
throw new CliExitCodeError(EXIT_CODES.UNREACHABLE, `The running connection daemon is from ${running}, but this is mcpdo ${clientVersion}. Run \`mcpdo daemon stop\` (its open connections will close), then re-run the command.`, { code: "daemon_version_mismatch" });
|
|
355
|
+
}
|
|
346
356
|
async function ensureDaemon(options) {
|
|
347
357
|
const dir = options?.dir ?? getDaemonDir();
|
|
348
358
|
let token = options?.token ?? getDaemonTokenFromEnv();
|
|
@@ -356,10 +366,13 @@ async function ensureDaemon(options) {
|
|
|
356
366
|
timeoutMs: 2e3,
|
|
357
367
|
token
|
|
358
368
|
});
|
|
359
|
-
if (pong?.stopping !== true)
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
369
|
+
if (pong?.stopping !== true) {
|
|
370
|
+
assertDaemonVersion(pong?.version, CLIENT_VERSION);
|
|
371
|
+
return {
|
|
372
|
+
socketPath,
|
|
373
|
+
spawned: false
|
|
374
|
+
};
|
|
375
|
+
}
|
|
363
376
|
await waitForDaemonExit(pong.pid, socketPath);
|
|
364
377
|
}
|
|
365
378
|
const tokenWasGenerated = token === void 0;
|
|
@@ -572,7 +585,7 @@ function p99Breach(summary, max) {
|
|
|
572
585
|
const p99 = summary.latencyMs?.p99;
|
|
573
586
|
if (p99 === void 0) return {
|
|
574
587
|
code: LOAD_P99_EXCEEDED,
|
|
575
|
-
message: `no call
|
|
588
|
+
message: `no call succeeded, so there is no p99 latency to check against --load-max-p99 ${max}`
|
|
576
589
|
};
|
|
577
590
|
if (p99 <= max) return void 0;
|
|
578
591
|
return {
|
|
@@ -626,7 +639,7 @@ function resolveLoadFlags(flags) {
|
|
|
626
639
|
...thresholds && { thresholds }
|
|
627
640
|
};
|
|
628
641
|
}
|
|
629
|
-
function usage(message, code =
|
|
642
|
+
function usage(message, code = LOAD_FLAG_CONFLICT) {
|
|
630
643
|
return new CliExitCodeError(EXIT_CODES.USAGE, message, { code });
|
|
631
644
|
}
|
|
632
645
|
//#endregion
|
|
@@ -1483,16 +1496,27 @@ function formatLoadSummaryHuman(summary, style = PLAIN) {
|
|
|
1483
1496
|
const rate = `${(summary.errorRate * 100).toFixed(2)}%`;
|
|
1484
1497
|
const lines = [
|
|
1485
1498
|
`${heading(style, "Load test")}${tool} ${style.dim(`(${bounds.join(", ")})`)}`,
|
|
1486
|
-
` Requests: ${summary.requests} in ${(summary.elapsedMs / 1e3).toFixed(2)}s (${summary.throughput}/s)`,
|
|
1499
|
+
` Requests: ${summary.requests} in ${(summary.elapsedMs / 1e3).toFixed(2)}s (${summary.throughput}/s, ${summary.okThroughput}/s ok)`,
|
|
1487
1500
|
` Outcomes: ${style.green(`${summary.ok} ok`)}, ${summary.toolErrors} tool errors, ${summary.errors} errors`,
|
|
1488
1501
|
` Error rate: ${failed > 0 ? style.red(rate) : rate}`
|
|
1489
1502
|
];
|
|
1503
|
+
if (summary.plannedStarts !== void 0) {
|
|
1504
|
+
const dropped = `${summary.droppedSlots} dropped`;
|
|
1505
|
+
lines.push(` Rate: ${summary.achievedRate}/s achieved; ${summary.plannedStarts} planned, ${summary.droppedSlots > 0 ? style.red(dropped) : dropped}`);
|
|
1506
|
+
}
|
|
1490
1507
|
const l = summary.latencyMs;
|
|
1491
|
-
lines.push(l === null ? ` Latency: ${style.dim("no calls
|
|
1508
|
+
lines.push(l === null ? ` Latency: ${style.dim("no calls succeeded")}` : ` Latency: min ${l.min} / mean ${l.mean} / p50 ${l.p50} / p90 ${l.p90} / p99 ${l.p99} / max ${l.max} ms`);
|
|
1509
|
+
const e = summary.errorLatencyMs;
|
|
1510
|
+
if (e !== null) lines.push(` Failed in: min ${e.min} / mean ${e.mean} / p50 ${e.p50} / p90 ${e.p90} / p99 ${e.p99} / max ${e.max} ms`);
|
|
1492
1511
|
if (summary.errorMessages.length > 0) {
|
|
1493
1512
|
lines.push(` ${style.bold("Top errors:")}`);
|
|
1494
1513
|
for (const { message, count } of summary.errorMessages) lines.push(` ${count}× ${message}`);
|
|
1495
1514
|
}
|
|
1515
|
+
if (summary.toolErrorMessages.length > 0) {
|
|
1516
|
+
lines.push(` ${style.bold("Top tool errors:")}`);
|
|
1517
|
+
for (const { message, count } of summary.toolErrorMessages) lines.push(` ${count}× ${message}`);
|
|
1518
|
+
}
|
|
1519
|
+
if (summary.stoppedEarly !== void 0) lines.push(` ${style.red("Stopped early")} (${summary.stoppedEarly.reason}): ${summary.stoppedEarly.detail}`);
|
|
1496
1520
|
const c = summary.connections;
|
|
1497
1521
|
if (c !== void 0) {
|
|
1498
1522
|
const failed = `${c.failed} failed`;
|
|
@@ -2061,7 +2085,10 @@ async function dispatchConnectionRpc(method, methodArgs, opts) {
|
|
|
2061
2085
|
format,
|
|
2062
2086
|
style
|
|
2063
2087
|
}, method, methodArgs.toolName, outcome);
|
|
2064
|
-
if (outcome.kind === "load")
|
|
2088
|
+
if (outcome.kind === "load") {
|
|
2089
|
+
for (const warning of loadSummaryWarnings(outcome.summary)) await awaitableError(`${warning}\n`);
|
|
2090
|
+
checkLoadThresholds(outcome.summary, opts.load?.thresholds);
|
|
2091
|
+
}
|
|
2065
2092
|
}
|
|
2066
2093
|
async function writeRpcOutcome(out, method, toolName, outcome) {
|
|
2067
2094
|
const { format, style } = out;
|
|
@@ -2300,13 +2327,17 @@ function resolveFriendlyName(name, index) {
|
|
|
2300
2327
|
function isDaemonUnreachable(error) {
|
|
2301
2328
|
return error instanceof CliExitCodeError && error.envelope?.code === "daemon_unreachable";
|
|
2302
2329
|
}
|
|
2330
|
+
function assertNoDaemonMeansNothingConnected(error) {
|
|
2331
|
+
if (!isDaemonUnreachable(error)) throw error;
|
|
2332
|
+
assertSocketPathWithinLimit(getDaemonSocketPath());
|
|
2333
|
+
}
|
|
2303
2334
|
async function resolveMruEntryName() {
|
|
2304
2335
|
if (requireExplicitConnection()) throw new CliExitCodeError(EXIT_CODES.USAGE, "servers/show requires an entry name in non-interactive mode. Pass one (see mcpdo servers/list).", { code: "server_name_required" });
|
|
2305
2336
|
let connections = [];
|
|
2306
2337
|
try {
|
|
2307
2338
|
connections = (await callDaemon("connections/list", {})).connections;
|
|
2308
2339
|
} catch (error) {
|
|
2309
|
-
|
|
2340
|
+
assertNoDaemonMeansNothingConnected(error);
|
|
2310
2341
|
}
|
|
2311
2342
|
const mru = connections.find((c) => c.isMru);
|
|
2312
2343
|
if (!mru) throw new CliExitCodeError(EXIT_CODES.USAGE, "No entry name given and there is no most-recently-used connection to infer one from. Pass a catalog entry name (see mcpdo servers/list).", { code: "server_name_required" });
|
|
@@ -2699,14 +2730,11 @@ function registerConnectionAdmin(program) {
|
|
|
2699
2730
|
connections: result.connections
|
|
2700
2731
|
});
|
|
2701
2732
|
} catch (error) {
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
return;
|
|
2708
|
-
}
|
|
2709
|
-
throw error;
|
|
2733
|
+
assertNoDaemonMeansNothingConnected(error);
|
|
2734
|
+
await writeConnectionOutput(outOpts(opts), {
|
|
2735
|
+
kind: "connections/list",
|
|
2736
|
+
connections: []
|
|
2737
|
+
});
|
|
2710
2738
|
}
|
|
2711
2739
|
});
|
|
2712
2740
|
program.command("connections/use").description("Set the MRU connection without an MCP RPC").argument("<connection>", "Connection @name / name").action(async (connectionArg) => {
|
|
@@ -2835,7 +2863,7 @@ function registerRpcCommands(program) {
|
|
|
2835
2863
|
});
|
|
2836
2864
|
break;
|
|
2837
2865
|
case "tools/call":
|
|
2838
|
-
cmd.argument("[toolName]", "Tool name").argument("[toolArgs...]", "Arguments as key:=value pairs or a JSON object").option("--tool-name <name>", "Tool name").option("--tool-arg <pairs...>", "Tool argument as key=value pair (alternative to key:=value positionals)", parseKeyValue, {}).option("--tool-args-json <json>", "Tool arguments as a JSON object (alternative to inline JSON positional)").option("--tool-metadata <pairs...>", "Tool-specific metadata", parseKeyValue, {}).option("--task", "Request a task-augmented tool call (legacy servers; on modern the server decides)").option("--app-info", "Probe MCP App metadata only").option("--load", "Load-test the tool: call it repeatedly and concurrently, then print a latency and error-rate summary instead of a result. Bounded by --load-duration (default 10s) and/or --load-requests. Later commands on this connection wait until the run ends.").option("--load-concurrency <n>", "With --load: most calls in flight at once (positive integer; default 10).", positiveIntegerParser("--load-concurrency")).option("--load-connections <n>", "With --load: spread the calls over this many independent sessions to the connection's HTTP or SSE server, opened before timing starts with stored credentials only (positive integer, at most --load-concurrency; default 1).", positiveIntegerParser("--load-connections")).option("--load-duration <sec>", "With --load: stop starting calls after this many seconds; in-flight calls still finish (default 10 when --load-requests is not set).", positiveNumberParser("--load-duration")).option("--load-requests <n>", "With --load: stop after starting this many calls (positive integer).", positiveIntegerParser("--load-requests")).option("--load-rate <n>", "With --load: start at most this many calls per second, spread evenly (positive number; default unlimited).", positiveNumberParser("--load-rate")).option("--load-max-error-rate <fraction>", "With --load: exit 10 (load_error_rate_exceeded) when the share of failed calls is above this value, after printing the summary (0 to 1; 0 fails on any failed call).", fractionParser("--load-max-error-rate")).option("--load-max-p99 <ms>", "With --load: exit 10 (load_p99_exceeded) when the p99 latency is above this many milliseconds, or when no call
|
|
2866
|
+
cmd.argument("[toolName]", "Tool name").argument("[toolArgs...]", "Arguments as key:=value pairs or a JSON object").option("--tool-name <name>", "Tool name").option("--tool-arg <pairs...>", "Tool argument as key=value pair (alternative to key:=value positionals)", parseKeyValue, {}).option("--tool-args-json <json>", "Tool arguments as a JSON object (alternative to inline JSON positional)").option("--tool-metadata <pairs...>", "Tool-specific metadata", parseKeyValue, {}).option("--task", "Request a task-augmented tool call (legacy servers; on modern the server decides)").option("--app-info", "Probe MCP App metadata only").option("--load", "Load-test the tool: call it repeatedly and concurrently, then print a latency and error-rate summary instead of a result. Bounded by --load-duration (default 10s) and/or --load-requests. Later commands on this connection wait until the run ends.").option("--load-concurrency <n>", "With --load: most calls in flight at once (positive integer; default 10).", positiveIntegerParser("--load-concurrency")).option("--load-connections <n>", "With --load: spread the calls over this many independent sessions to the connection's HTTP or SSE server, opened before timing starts with stored credentials only (positive integer, at most --load-concurrency; default 1).", positiveIntegerParser("--load-connections")).option("--load-duration <sec>", "With --load: stop starting calls after this many seconds; in-flight calls still finish (default 10 when --load-requests is not set).", positiveNumberParser("--load-duration")).option("--load-requests <n>", "With --load: stop after starting this many calls (positive integer).", positiveIntegerParser("--load-requests")).option("--load-rate <n>", "With --load: start at most this many calls per second, spread evenly (positive number; default unlimited).", positiveNumberParser("--load-rate")).option("--load-max-error-rate <fraction>", "With --load: exit 10 (load_error_rate_exceeded) when the share of failed calls is above this value, after printing the summary (0 to 1; 0 fails on any failed call).", fractionParser("--load-max-error-rate")).option("--load-max-p99 <ms>", "With --load: exit 10 (load_p99_exceeded) when the p99 latency of the successful calls is above this many milliseconds, or when no call succeeded, after printing the summary (positive number).", maxP99Parser);
|
|
2839
2867
|
cmd.action(async (toolNamePos, toolArgsPos, o) => {
|
|
2840
2868
|
const { toolName, toolArg } = resolveToolCallArgs({
|
|
2841
2869
|
toolNameFlag: o.toolName,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { F as generateDaemonToken, H as ensureDaemonDir, I as getDaemonTokenFromEnv, _t as awaitableError, ot as disallowMemorySecretStoreFallback, t as DaemonServer } from "./server-Dv339Ejx.js";
|
|
3
3
|
//#region src/daemon/run.ts
|
|
4
4
|
process.title = "mcpdod";
|
|
5
5
|
disallowMemorySecretStoreFallback();
|