@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.
Files changed (32) hide show
  1. package/README.md +1 -1
  2. package/clients/cli/build/index.js +1013 -80
  3. package/clients/mcpdo/build/mcp-bin.js +50 -22
  4. package/clients/mcpdo/build/mcpdod.js +1 -1
  5. package/clients/mcpdo/build/{server-BHuKGkMj.js → server-Dv339Ejx.js} +886 -48
  6. package/clients/tui/build/index.js +781 -46
  7. package/clients/web/build/index.js +223 -124
  8. package/clients/web/dist/assets/fredoka-normal-hebrew-CjvktpUN.woff2 +0 -0
  9. package/clients/web/dist/assets/fredoka-normal-latin-DOQG_Jwn.woff2 +0 -0
  10. package/clients/web/dist/assets/fredoka-normal-latin-ext-tYNUQHO6.woff2 +0 -0
  11. package/clients/web/dist/assets/index-BCud2uMC.js +1594 -0
  12. package/clients/web/dist/assets/{index-dqp8Sd8W.css → index-Dval2a7I.css} +1 -1
  13. package/clients/web/dist/assets/{prism-light-BIhJtJkv.js → prism-light-CoVRM9R2.js} +1 -1
  14. package/clients/web/dist/assets/roboto-mono-italic-cyrillic-C1E63de8.woff2 +0 -0
  15. package/clients/web/dist/assets/roboto-mono-italic-cyrillic-ext-DR9ovEqT.woff2 +0 -0
  16. package/clients/web/dist/assets/roboto-mono-italic-greek-Cs2u2nVh.woff2 +0 -0
  17. package/clients/web/dist/assets/roboto-mono-italic-latin-D_P-kX1t.woff2 +0 -0
  18. package/clients/web/dist/assets/roboto-mono-italic-latin-ext-CErTcBzw.woff2 +0 -0
  19. package/clients/web/dist/assets/roboto-mono-italic-vietnamese-D4UvzJMM.woff2 +0 -0
  20. package/clients/web/dist/assets/roboto-mono-normal-cyrillic-DfzWIUPd.woff2 +0 -0
  21. package/clients/web/dist/assets/roboto-mono-normal-cyrillic-ext-D8QBEkUe.woff2 +0 -0
  22. package/clients/web/dist/assets/roboto-mono-normal-greek-DlC4X1lQ.woff2 +0 -0
  23. package/clients/web/dist/assets/roboto-mono-normal-latin-BAKpfWyj.woff2 +0 -0
  24. package/clients/web/dist/assets/roboto-mono-normal-latin-ext-CSSVNFqV.woff2 +0 -0
  25. package/clients/web/dist/assets/roboto-mono-normal-vietnamese-DFkHeOHB.woff2 +0 -0
  26. package/clients/web/dist/fonts/Fredoka-OFL.txt +93 -0
  27. package/clients/web/dist/fonts/RobotoMono-OFL.txt +93 -0
  28. package/clients/web/dist/index.html +2 -5
  29. package/clients/web/static/sandbox_proxy.html +177 -6
  30. package/package.json +5 -4
  31. package/skills/mcpdo/SKILL.md +14 -0
  32. package/clients/web/dist/assets/index-BqEbhCDX.js +0 -1587
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { $ as CliExitCodeError, A as sanitizeDeep, B as ensureDaemonDir, C as clearAllOAuthClientState, D as positiveNumberParser, E as positiveIntegerParser, F as readDaemonTokenFile, G as loadServerEntries, H as getDaemonLogPath, I as DAEMON_DIR_ENV, J as parseKeyValuePair, K as selectServerEntry, L as DAEMON_TOKEN_ENV, M as encodeRequest, N as generateDaemonToken, O as resolveLoadOptions, P as getDaemonTokenFromEnv, Q as DEFAULT_TASK_TTL_MS, R as assertSocketPathWithinLimit, S as NodeOAuthStorage, T as resetNodeOAuthStorageCache, U as getDaemonSocketPath, V as getDaemonDir, W as readInspectorVersion, X as withDefaultCatalogPath, Y as resolveServerSource, Z as DEFAULT_MAX_FETCH_REQUESTS, _ as isCliAutoOpenForced, a as obtainPendingUrlForKey, at as setSecretStorageWarningsQuiet, b as DEFAULT_CONNECT_TIMEOUT_MS, c as runAuthHelper, ct as CallbackNavigation, d as emaLogin, dt as idpOAuthStorageKey, et as EXIT_CODES, f as emaLogout, ft as normalizeIdpIssuer, g as runEmaIdpInteractiveFlow, h as requireIdp, ht as awaitableLog, i as obtainPendingAuthUrl, it as getSecretStorageInfo, j as sanitizeText, k as isSafeLinkTarget, l as writePendingAuthMarker, lt as clearEmaIdpSession, m as loadEmaIdpConfig, mt as awaitableError, n as AUTH_HELPER_COMMAND, nt as readOAuthStore, o as pendingAuthMarkerPath, ot as warnAboutSecretStorage, p as getEmaStatus, pt as parseIdpOAuthStorageKey, q as parseHeaderPair, r as PENDING_AUTH_TTL_MS, rt as disallowMemorySecretStoreFallback, s as removeOwnPendingAuthMarker, st as InMemorySecretStore, tt as handleError, u as authorizeInFrontend, ut as getEmaIdpLoginState, v as PLAIN, w as getStateFilePath, x as withConnectTimeout, y as styleFromOpts, z as createPrivateDaemonDir } from "./server-BHuKGkMj.js";
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) return {
360
- socketPath,
361
- spawned: false
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 completed, so there is no p99 latency to check against --load-max-p99 ${max}`
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 = "load_flag_conflict") {
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 completed")}` : ` Latency: min ${l.min} / mean ${l.mean} / p50 ${l.p50} / p90 ${l.p90} / p99 ${l.p99} / max ${l.max} ms`);
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") checkLoadThresholds(outcome.summary, opts.load?.thresholds);
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
- if (!isDaemonUnreachable(error)) throw error;
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
- if (isDaemonUnreachable(error)) {
2703
- await writeConnectionOutput(outOpts(opts), {
2704
- kind: "connections/list",
2705
- connections: []
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 completed, after printing the summary (positive number).", maxP99Parser);
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 { B as ensureDaemonDir, N as generateDaemonToken, P as getDaemonTokenFromEnv, mt as awaitableError, rt as disallowMemorySecretStoreFallback, t as DaemonServer } from "./server-BHuKGkMj.js";
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();